日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)...

發布時間:2024/4/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處:王亟亟的大牛之路

開場白慣用鼓勵詩句:

黑發不知勤學早,白首方悔讀書遲。 —— 顏真卿《勸學詩》

這一系列的博文這是第五篇了,感謝大家的支持以及陪伴,往后我也會繼續努力寫出高質量的內容,謝謝

今天上的是一個自定義View,新鮮出爐,先上下效果(是一張張截圖拼接的Gif動畫都看不出來了,大家理解就行可以下Demo跑)

樣例分析(最簡單的描述了)

黑色線條是我們的手機

紅色是我們自定義的”TitleBar”

藍色是我們的自定義布局

紫色是自定義布局填充的內容

我們只需要配置我們藍色內容的參數就可以對動畫效果以及大小等進行設置。
PS:因為 藍色內容吃掉了所有藍色區域的OnTouch,所以紫色就不要做用戶交互內容了,純粹做展示吧TOT(小的該死)

看下項目結構:

就比上次的代碼多了一些資源文件和4個類,一個就是我們的麥麥Activity,另外3個解釋下

DraggableFlipView我們的自定義控件

DragGestureDetector我們的觸碰效果處理類

FlipListener動作展示以及處理結果

OK,開始分析

DraggableFlipView

public class DraggableFlipView extends FrameLayout implements DragGestureDetector.DragGestureListener {//一系列的聲明,不一一解釋了,后面用到了會加以解釋private static final float DRAG_THRESHOLD_PARAM = 50.0f;private static final int DEFAULT_VALUE = 0;private static final int DEFAULT_DRAGGABLE_VALUE = 50;private static final int DEFAULT_DRAG_DETECT_VALUE = 7;private DragGestureDetector mDragGestureDetector;private boolean isAnimation;private boolean isDragging;private int mAngle;private int mDraggableAngle;private int mDragDetectAngle;private boolean mIsReverse;private FlipListener mFlipListener;private RelativeLayout mFrontLayout;private RelativeLayout mBackLayout;//聲明左右狀態的枚舉private enum RotateDirection {RIGHT(1), LEFT(-1);private int mValue;RotateDirection(int value) {this.mValue = value;}public int getValue() {return mValue;}}//構造函數public DraggableFlipView(Context context) {this(context, null);}public DraggableFlipView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DraggableFlipView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}//初始化參數private void init(Context context, AttributeSet attrs) {//獲取布局對象并加以填充,默認顯示mBackLayout這個布局mFrontLayout = new RelativeLayout(context);RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);mFrontLayout.setLayoutParams(params1);mBackLayout = new RelativeLayout(context);RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);mBackLayout.setLayoutParams(params2);this.addView(mFrontLayout);this.addView(mBackLayout);mBackLayout.setVisibility(View.INVISIBLE);//初始化FlipListener,傳入2個布局,第二個參數為不顯示的布局mFlipListener = new FlipListener(mFrontLayout, mBackLayout, this);mDragGestureDetector = new DragGestureDetector(this);//獲取 標簽TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DraggableFlipView);LayoutInflater.from(context).inflate(a.getResourceId(R.styleable.DraggableFlipView_frontView, DEFAULT_VALUE), mFrontLayout);LayoutInflater.from(context).inflate(a.getResourceId(R.styleable.DraggableFlipView_backView, DEFAULT_VALUE), mBackLayout);//填充標簽數據mDraggableAngle = a.getInteger(R.styleable.DraggableFlipView_draggableAngle, DEFAULT_DRAGGABLE_VALUE);mDragDetectAngle = a.getInteger(R.styleable.DraggableFlipView_dragDetectAngle, DEFAULT_DRAG_DETECT_VALUE);}//onInterceptTouchEvent這個事件是從父控件開始往子控件傳的,直到有攔截或者到沒有這個事件的view,并且使用 mDragGestureDetector.setPointMap(ev);進行參數的傳遞@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (mDragGestureDetector == null) return false;int action = ev.getAction() & MotionEvent.ACTION_MASK;switch (action) {case MotionEvent.ACTION_UP:break;case MotionEvent.ACTION_MOVE:if (Math.abs(ev.getX() - mDragGestureDetector.getTouchPoint().getX())> DRAG_THRESHOLD_PARAM|| Math.abs(ev.getY() - mDragGestureDetector.getTouchPoint().getY())> DRAG_THRESHOLD_PARAM) {mDragGestureDetector.setPointMap(ev);return true;}break;case MotionEvent.ACTION_POINTER_DOWN:return true;}return false;}//onTouch這個事件是從子控件回傳到父控件的,一層層向下傳//mDragGestureDetector.onTouchEvent(event)來實現onTouchEvent的操作@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mDragGestureDetector != null) {mDragGestureDetector.onTouchEvent(event);}return true;}//計算,并判斷以哪種方式來實現切換動畫@Overridepublic void onDragGestureListener(DragGestureDetector dragGestureDetector, int action) {if (isAnimation) return;if (action == MotionEvent.ACTION_UP) {if (mAngle >= mDragDetectAngle) {startAutoRotateAnimation(RotateDirection.RIGHT);} else if (mAngle < -mDragDetectAngle) {startAutoRotateAnimation(RotateDirection.LEFT);}return;}mAngle = (dragGestureDetector.deltaX - dragGestureDetector.prevDeltaX) > 0 ? ++mAngle : --mAngle;if (Math.abs(mAngle) > mDragDetectAngle) isDragging = true;if(isDragging) this.setRotationY(mAngle);if (mAngle >= mDraggableAngle) {startAutoRotateAnimation(RotateDirection.RIGHT);} else if (mAngle < -mDraggableAngle) {startAutoRotateAnimation(RotateDirection.LEFT);}}private void startAutoRotateAnimation(RotateDirection rotateDirection) {isAnimation = true;if (mIsReverse) {mFlipListener.reverse();} else {mIsReverse = true;}mFlipListener.setRotateDirection(rotateDirection.getValue());//動畫的平滑過渡 可以參照 http://blog.csdn.net/guolin_blog/article/details/43536355//講的很詳細ValueAnimator mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);mFlipAnimator.addUpdateListener(mFlipListener);mFlipAnimator.start();mFlipAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {mAngle = 0;isAnimation = false;isDragging = false;}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});} }

DragGestureDetector

public class DragGestureDetector {public float deltaX;public float deltaY;public float prevDeltaX;public float prevDeltaY;public int originalIndex;public float velocityX;public float velocityY;//儲存用戶操作路徑private HashMap<Integer, TouchPoint> pointMap = new HashMap<>();private DragGestureListener dragGestureListener;//構造函數public DragGestureDetector(DragGestureListener dragGestureListener) {this.dragGestureListener = dragGestureListener;//初始化坐標pointMap.put(0, createPoint(0.f, 0.f));}//儲存坐標點public void setPointMap(MotionEvent event) {float eventX = event.getX();float eventY = event.getY();TouchPoint downPoint = pointMap.get(0);if (downPoint != null) {downPoint.setXY(eventX, eventY);return;}downPoint = createPoint(eventX, eventY);pointMap.put(0, downPoint);}//獲取坐標點public TouchPoint getTouchPoint() {return pointMap.get(originalIndex);}//用戶觸控坐標點相應的計算synchronized public boolean onTouchEvent(MotionEvent event) {float eventX = event.getX(originalIndex);float eventY = event.getY(originalIndex);int action = event.getAction() & MotionEvent.ACTION_MASK;switch (action) {case MotionEvent.ACTION_DOWN: {break;}case MotionEvent.ACTION_MOVE: {TouchPoint originalPoint = pointMap.get(originalIndex);if (originalPoint != null) {deltaX = eventX - originalPoint.x;deltaY = eventY - originalPoint.y;if (dragGestureListener != null) {dragGestureListener.onDragGestureListener(this, action);}velocityX = deltaX - prevDeltaX;velocityY = deltaY - prevDeltaY;prevDeltaX = deltaX;prevDeltaY = deltaY;}break;}case MotionEvent.ACTION_UP: {TouchPoint originalPoint = pointMap.get(originalIndex);if (originalPoint != null && dragGestureListener != null) {dragGestureListener.onDragGestureListener(this, action);}velocityX = velocityY = 0;prevDeltaX = prevDeltaY = 0;deltaX = deltaY = 0;break;}default:}return false;}private TouchPoint createPoint(float x, float y) {return new TouchPoint(x, y);}public interface DragGestureListener {void onDragGestureListener(DragGestureDetector dragGestureDetector, int action);}//坐標類public class TouchPoint {private float x;private float y;public TouchPoint(float x, float y) {this.x = x;this.y = y;}public TouchPoint setXY(float x, float y) {this.x = x;this.y = y;return this;}public float getX() {return this.x;}public float getY() {return this.y;}} }

FlipListener

public class FlipListener implements ValueAnimator.AnimatorUpdateListener {private View mParentView;private View mFrontView;private View mBackView;private boolean mFlipped;private int mDirection;//構造函數public FlipListener(final View front, final View back, final View parent) {this.mParentView = parent;this.mFrontView = front;this.mBackView = back;this.mBackView.setVisibility(View.GONE);}@Overridepublic void onAnimationUpdate(final ValueAnimator animation) {final float value = animation.getAnimatedFraction();final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));//根據傳入的mDirection(1或者-1)進行計算并且邏輯判斷if (value <= 0.5f) {this.mParentView.setRotationY(180 * value * mDirection);if (mFlipped) setStateFlipped(false);} else {this.mParentView.setRotationY(-180 * (1 - value) * mDirection);if (!mFlipped) setStateFlipped(true);}this.mParentView.setScaleX(scaleValue);this.mParentView.setScaleY(scaleValue);}//初始化自定義View時調用public void reverse() {View temp = mBackView;mBackView = mFrontView;mFrontView = temp;}public void setRotateDirection(int direction) {mDirection = direction;}//具體切換試圖private void setStateFlipped(boolean flipped) {mFlipped = flipped;this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);} }

OK!!!!實現就這些啦
源碼:http://yunpan.cn/cHwL97TfNdApF 訪問密碼 d11f

總結

以上是生活随笔為你收集整理的从头开始敲代码之《从BaseApplication/Activity开始(五)》(自定义控件,实现点击/滑动翻页)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。