【Android】View 的基礎知識
1. 什么是 View?
View 是 Android 中所有UI組件的基礎類。它表示屏幕上的一個矩形區域,負責繪制內容和處理用戶交互事件。所有的 UI 組件(如按鈕、文本框等)都是 View 的子類,而 ViewGroup 是一種特殊的 View,它可以包含其他 View 或 ViewGroup,用于定義布局結構。View 的主要功能包括繪制內容、響應用戶事件以及與父容器的交互。它可以顯示文本、圖片、視頻等內容,并處理觸摸、點擊等操作。
2. View 的位置參數
View的位置主要由四個參數決定,這些參數都是相對其父容器的坐標:
- left:View左邊到父容器左邊的距離
- top:View頂部到父容器頂部的距離
- right:View右邊到父容器左邊的距離
- bottom:View底部到父容器頂部的距離
在Android中,x軸和y軸的正方向分別為右和下。
獲取View寬高的方法:
// 獲取View的寬度
int width = view.getRight() - view.getLeft();
// 或者使用簡便方法
int width = view.getWidth();// 獲取View的高度
int height = view.getBottom() - view.getTop();
// 或者使用簡便方法
int height = view.getHeight();
從Android 3.0開始,View增加了額外的參數:
- x和y:View左上角的坐標,相對于父容器
- translationX和translationY:View左上角相對于父容器的偏移量
它們之間的關系為:
x = left + translationX
y = top + translationY
3. MotionEvent 和 TouchSlop
3.1 MotionEvent
MotionEvent是觸摸事件類,包含了觸摸動作、位置等信息。常見的觸摸事件類型包括:
- ACTION_DOWN:手指按下屏幕
- ACTION_MOVE:手指在屏幕上移動
- ACTION_UP:手指從屏幕抬起
- ACTION_CANCEL:觸摸事件被取消
獲取觸摸點坐標的方法:
@Override
public boolean onTouchEvent(MotionEvent event) {// 獲取相對于當前View的x坐標float x = event.getX();// 獲取相對于當前View的y坐標float y = event.getY();// 獲取相對于屏幕的原始坐標float rawX = event.getRawX();float rawY = event.getRawY();return true;
}
3.2 TouchSlop
TouchSlop是系統識別的被認為滑動的最小距離,小于這個距離的移動不會被識別為滑動。這個常量由設備制造商定義,不同設備可能不同。
獲取TouchSlop的方法:
ViewConfiguration.get(context).getScaledTouchSlop()
在實際開發中,處理滑動時應考慮TouchSlop,以避免過于敏感的滑動檢測:
private int mTouchSlop;
private float mLastX;public MyView(Context context) {super(context);mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}@Override
public boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mLastX = x;break;case MotionEvent.ACTION_MOVE:float deltaX = Math.abs(x - mLastX);if (deltaX > mTouchSlop) {// 這是一個有效的滑動}break;}return true;
}
4. VelocityTracker、GestureDetector
4.1 VelocityTracker
VelocityTracker用于追蹤手指滑動的速度,包括水平和垂直方向的速度。速度的計算單位通常是"每秒移動的像素數(px/s)"。
使用VelocityTracker的基本步驟:
// 在View的onTouchEvent方法中
private VelocityTracker mVelocityTracker;@Override
public boolean onTouchEvent(MotionEvent event) {if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 處理按下事件break;case MotionEvent.ACTION_MOVE:// 處理移動事件break;case MotionEvent.ACTION_UP:// 計算速度mVelocityTracker.computeCurrentVelocity(1000); // 計算單位:1000ms內的像素數float xVelocity = mVelocityTracker.getXVelocity();float yVelocity = mVelocityTracker.getYVelocity();// 使用速度值進行相關處理// 回收VelocityTrackerif (mVelocityTracker != null) {mVelocityTracker.recycle();mVelocityTracker = null;}break;}return true;
}
注意:獲取速度值前必須先調用computeCurrentVelocity()方法,參數表示時間單位(毫秒)。
4.2 GestureDetector
GestureDetector用于輔助檢測用戶的單擊、長按、滑動、雙擊等手勢。它簡化了復雜手勢的識別過程。
使用GestureDetector的基本步驟:
- 創建GestureDetector實例
- 實現GestureDetector.OnGestureListener接口
- 在View的onTouchEvent()方法中轉發觸摸事件
public class MyView extends View implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {private GestureDetector mGestureDetector;public MyView(Context context) {super(context);mGestureDetector = new GestureDetector(context, this);// 解決長按后無法拖動的問題mGestureDetector.setIsLongpressEnabled(false);}@Overridepublic boolean onTouchEvent(MotionEvent event) {return mGestureDetector.onTouchEvent(event);}// OnGestureListener方法@Overridepublic boolean onDown(MotionEvent e) {// 按下動作return true; // 必須返回true,否則后續事件不會傳遞}@Overridepublic void onShowPress(MotionEvent e) {// 按下但未移動或抬起}@Overridepublic boolean onSingleTapUp(MotionEvent e) {// 單擊抬起return false;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {// 滾動操作return false;}@Overridepublic void onLongPress(MotionEvent e) {// 長按事件}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {// 快速滑動后抬起return false;}// OnDoubleTapListener方法@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {// 嚴格的單擊確認(非雙擊中的第一次點擊)return false;}@Overridepublic boolean onDoubleTap(MotionEvent e) {// 雙擊事件return false;}@Overridepublic boolean onDoubleTapEvent(MotionEvent e) {// 雙擊事件中的ACTION_DOWN、ACTION_MOVE和ACTION_UPreturn false;}
}
如果不需要處理所有手勢,可以使用SimpleOnGestureListener類,它提供了所有方法的空實現,只需重寫需要的方法。