一、
1、Activity頁面構成元素
- 1)在activity 中 通過 setContentView() 方法設定為根佈局。在每一個Activity 中 都包含一個Window 物件,它由 PhoneWindow來實現
- 2)PhoneWindow 將一個 DecorView 設定為整個應用視窗的根View。
- 3)DecorView,由TitleView 和ContentView組成, 前者承載的是一個Actionbar,後者承載的是一個FrameLayout,
2、MotionEvent和TouchSlop
- 1)手指接觸螢幕後 會產生以下的事件:
ACTION_DOWN // 收支接觸
ACTION_MOVE // 手指在螢幕上移動
ACTION_UP //手指從螢幕鬆開
ACTION_CANCEL //取消
複製程式碼
-
2)MotionEvent 物件獲取的 點選的 x 和 y ,
①.使用 getX / getY 獲取的是相對於當前View左上角的x和y,
②.而 getRawX / getRawY 獲取的是相對於手機螢幕左上角的座標。 -
3)TouchSlop:是系統所能識別的最小滑動距離,小於它則視未發生滑動,在不同的裝置上獲取的值不同。通過:
ViewConfiguration.get(getContext()).getScaledTouchSlop() //獲得
複製程式碼
3、VelocityTracker、GestureDetector和Scroller
- 1)VelocityTracker:速度追蹤,用於追蹤滑動過程中的速度,包括水平和豎直速度。
//1.在 onTouchEvent 方法中追蹤當前事件的速度
VelocityTracker tracker = VelocityTracker.obtain();
tracker.addMovement(event);
//2.獲取當前速度
tracker.computeCurrentVelocity(1000);//計算速度
int xVelocity = (int) tracker.getXVelocity();
int yVelocity = (int) tracker.getYVelocity();
//3.在不需要的時候重置回收記憶體
tracker.recycle();
複製程式碼
- 2)GestureDetector:用於檢測單擊、滑動、長按、雙擊等手勢。
首先要實現 GestureDetector.OnGestureListener介面,如果需要雙擊,則需實現 GestureDetector.OnDoubleTapListener 介面;
//設定監聽
mGestureDetector = new GestureDetector(this);
//避免長按後無法拖動,自己測試時發現不設定,長按後也可以拖動
mGestureDetector.setIsLongpressEnabled(false);
複製程式碼
- 3)Scroller:彈性滑動,可是實現有過度效果的滑動,View 的 ScrollTo/ScrollBy 都是瞬間滑動完成的。
4、View 的滑動
- 1)View的滑動主要有如下三種方式:
- scrollTo /scrollBy :適合對view 的內容改變;
- 動畫: 主要用於沒有互動的View 和實現複雜的動畫效果;
- 改變佈局引數:操作稍微複雜,適合有互動的View 。
- 2)View 的 ScrollTo/ScrollBy 方法
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
複製程式碼
其中 scrollBy 呼叫的是 scrollTo,它實現了使用當前位置的相對滑動,而scrollTo 是基於所傳引數的絕對滑動.
- 3)使用動畫
通過動畫為View 新增平移效果,View 的 tanslationX 和 tanslationY 屬性,可以採用傳統的動畫和屬性動畫。 - 4)改變佈局引數
通過改變View 的LayoutParams 使得 View 重新佈局實現滑動。
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
mButton.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
mButton.setLayoutParams(params);
// 或者 mButton.requestLayout();
複製程式碼
5、彈性滑動
為了避免 滑動的生硬,可以採用彈性滑動,提高使用者體驗。
這裡主要有 :Scroller、動畫、延時三種方式。
- 1)Scroller 的典型使用,主要是 invalidate方法起的作用。
Scroller mScroller = new Scroller(context);
/**
* 滑動到指定位置
*
* @param destX X 滑動距離
* @param destY Y 滑動距離
*/
private void smoothScrollTo(int destX, int destY) {
//滑動起點X
int scrollX = getScrollX();
//滑動起點Y
int scrollY = getScrollY();
//1000 ms內慢慢滑向 (destX,destY)
mScroller.startScroll(scrollX, scrollY, destX, destY, 1000);
//重繪
invalidate();
}
/**
* 使View 不斷重繪
*/
@Override
public void computeScroll() {
/**
* computeScrollOffset 方法通過時間流逝百分比計算 scrollX和scrollY
* 返回true 表示滑動未結束
*/
if (mScroller.computeScrollOffset()) {
//滑動到當前位置,通過小幅度滑動實現彈性滑動
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//再次重繪
postInvalidate();
}
}
複製程式碼
- 2)對於延時達到彈性滑動,主要是利用 了Handler 或者 View 的 postDelayed 方法,或者執行緒的 sleep方法。
6、View 的事件分發機制
- 1)所有的Touch事件都封裝到 MotionEvent 裡面;
- 2)事件處理包括三種情況,分別為:傳遞—-dispatchTouchEvent()函式、攔截——onInterceptTouchEvent()函式、消費—-onTouchEvent()函式和OnTouchListener;
- 3)事件型別分為 ACTION_DOWN, ACTION_UP, ACTION_MOVE , ACTION_POINTER_DOWN, ACTION_POINTER_UP , ACTION_CANCEL 等,每個事件都是以 ACTION_DOWN 開始 ACTION_UP 結束。
用下面虛擬碼表示事件分發過程及其關係:
//事件分發
public boolean dispatchTouchEvent(MotionEvent event) {
boolean consume = false;
//是否被攔截
if (onInterceptTouchEvent(event))
{
//被攔截,處理事件
consume = onTouchEvent(event);
} else {
//未被攔截,向下分發
consume = childView.dispatchTouchEvent(event);
}
return consume;
}
複製程式碼
1、activity --->ViewGroup --->view 正常流程:
- 1)當activity dispatchTouchEvent() 返回 true :代表事件停止分發,activity 的onTouchEvent()方法不執行。其子view也接受不到事件。
- 2)ViewGroup onInterceptTouchEvent() 返回ture時,onTouchEvent() 也返回 true時;
ViewGroup
①、
ViewGroup oninterceptTouchEnent 返回 ture時,表示:傳遞給子View的事件被攔截了,
ViewGroup onTouchEvent() 返回 true時,表示:該事件被VieWGroup自身消費了,不傳遞給父View的onTouch方法中處理了。
程式碼:
EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWN
EmptyViewGroup: onTouchEvent--->ACTION_DOWN
...
EmptyViewGroup: onTouchEvent--->ACTION_MOVE
...
EmptyViewGroup: onTouchEvent--->ACTION_UP
複製程式碼
②、
ViewGroup oninterceptTouchEnent 返回 ture時,表示:傳遞給子View事件被攔截了,
ViewGroup onTouchEvent() 返回 false時,表示:ViewGroup也不處理此事件,交給上層父View(avtivity)的OnTouchEvent()方法處理。
程式碼:
//viewGroup只消費 ACTION_DOWN 事件
EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWN
EmptyViewGroup: onTouchEvent--->ACTION_DOWN
//activity 將事件消費
DemoActivity: onTouchEvent--->ACTION_DOWN
...
DemoActivity: onTouchEvent--->ACTION_MOVE
...
DemoActivity: onTouchEvent--->ACTION_UP
複製程式碼
③、
ViewGroup onInterceptTouchEvent 返回 false時,表示事件傳遞給子View,不攔截。
ViewGroup onTouchEvent() 返回 false時,ViewGroup也不處理此事件,交給上層父View(avtivity)的OnTouchEvent()方法處理。
View onTouchEvent() 返回 true: 該子View消費了此事件。不傳遞到ViewGroup的OnTouchEvent()方法中。
EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWN
EmptyView: onTouchEvent--->ACTION_DOWN
EmptyViewGroup: onInterceptTouchEvent--->ACTION_MOVE
EmptyView: onTouchEvent--->ACTION_MOVE
...
EmptyViewGroup: onInterceptTouchEvent--->ACTION_UP
EmptyView: onTouchEvent--->ACTION_UP
複製程式碼
④、
ViewGroup onInterceptTouchEvent 返回 false時,表示事件傳遞給子View,不攔截。
ViewGroup onTouchEvent() 返回 false時,ViewGroup也不處理此事件,交給上層父View(avtivity)的OnTouchEvent()方法處理。
View onTouchEvent() 返回 false: 該子View不消費了此事件。傳遞到ViewGroup的OnTouchEvent()方法中。
EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWN
EmptyView: onTouchEvent--->ACTION_DOWN
EmptyViewGroup: onTouchEvent--->ACTION_DOWN
DemoActivity: onTouchEvent--->ACTION_DOWN
DemoActivity: onTouchEvent--->ACTION_MOVE
...
DemoActivity: onTouchEvent--->ACTION_UP
複製程式碼
由於activity作為頂級的View,當activity 中所有得子View 都不消費onTouchEvent()事件時,ativity的OnTouchEvent() 無論返回true/false。該activity都會消費使用者觸發的事件。在onTouchEvent()中。