1、View的滑動
1.1、使用ScrollTo和ScrollBy滑動
ScrollTo(x,y):滑動到某個位置,傳遞的是位置的座標
ScrollBy(x,y):滑動某個距離,傳遞的是移動過的距離
同時這兩個方法移動的是view中的內容,而不是view本身,比如作用於Layout,將會移動的是layout中button的位置。從理解上來說,可以理解爲畫布在移動。
操作簡單,適合於對View的內容滑動
1.2、使用動畫滑動
可以通過如下代碼調用ObjectAnimator來實現動畫滑動效果,這裏給出簡單的實例代碼,詳細代碼參見本人的另一篇博客
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
操作簡單,但是3.0以下不兼容,可以實現複雜的動畫效果
1.3、改變佈局參數實現滑動
一般我們可以改變一個view的佈局來對它進行移動,如果想把一個button向右移動100px,只需要將這個Button的LayoutParams裏的marginLeft參數的值增加100px即可。示例代碼如下:
MarginLayoutParams params = (MarginLayoutParams)mButton1.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
mButton1.requestLayout();
//或mButton1.setLayoutParams(params);
操作稍微複雜,適用於Android的所有api,同時可以保留交互事件
1.4、彈性滑動
使用Scroller
Scroller scroller = new Scroller(mContext);
//緩慢滑動到指定的位置
private void smothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int delta = destX - scrollX;
mScroller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.etCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
利用動畫
利用動畫本身的間隔時間來完成
ObjectAnimator.ofFloat(TargetView,"translationX",0,100).setDuration(100).start();
利用監聽動畫更新的方法實現移動
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000);
animator.addUpdateListeneer(new AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animator){
float fraction = animator.getAnimatedFraction();
mButton1.scrollTo(startX + (int) (deltaX*fraction),0);
}
});
animator.start();
使用延時策略
實現原理是通過發送一系列的延時消息,從而達到漸變的效果。實際上就是通過while不斷髮消息和睡眠,從而達到動畫效果。
private static final int MESSAGE_SCROLL_TO = 1;
private static final int FRAME_COUNT = 30;
private static final int DELAYED_TIME=33;
private int mCount = 0;
private Handler mHandler = new Handler(){
public void handleMEssage(Message msg){
switch(msg.what){
case MESSAGE_SCROLL_TO:{
mCount++;
if(mCount <= FRAME_COUNT{
float fraction = mCount/(float)FRAME_COUNT;
int scrollX = (int) (fraction*100);
mButton1.scrollTo(scrollX,0);
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,
DELATED_TIME);
}
break;
}
default:
break;
};
};
}
2、View的事件分發機制
事件分發機制就是其實就是對MotionEvent事件的分發過程。即當一個MotionEvent(點擊事件)產生後,系統需要把這個事件傳遞給一個具體的view進行處理,這個過程就是事件的分發過程。
2.1、點擊事件的傳遞規則
事件分發過程由三個很重要的方法來共同完成:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev)
事件進入當前view調用的第一個方法,用來進行事件分發。返回結果受到當前view的onTouchEvent方法和下級view的dispatchTouchEvent的方法的影響,表示是否消耗當前事件。
public boolean onInterceptTouchEvent(MotionEvent event)
在disPatchTouchEvent方法的內部調用,用來判斷是否攔截當前事件。如果攔截則執行onTouchEvent方法,否則執行下級view的dispatchTouchEvent方法。
public boolean onTouchEvent(MotionEvent event)
用來處理點擊事件中的各種方法,返回結果便是是否消耗當前的點擊事件。如果不消耗,則在同一個事件序列中,當前view無法再次接收到事件。
事件處理過程僞代碼
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){//判斷是否攔截事件
consume = onTouchEvent(ev);//是否消耗當前事件
}else{
consume = child.dispatchTouchEvent(ev);//子事件處理
}
return consume;//返回false會調用父控件的onTouchEvent方法
}
常用事件處理方法的優先級
OnTouchListener>onTouchEvent>onClickListener
2.2、事件傳遞相關結論
1、事件序列:從手指接觸屏幕的那一刻起,到手指離開屏幕的那一刻結束,在這個過程中產生的一系列事件。
2、一個事件序列真能被一個view攔截且消耗。除非在onTouchEvent中強行傳遞給其它view
3、如果view的onTouchEvent返回false,則事件不會向下傳遞,而會調用父控件的onTouchEvent方法進行處理。
4、如果view只消耗ACTION_DOWN事件,那麼這個點擊事件的其他後續事件會返回給Activity進行處理。
5、ViewGroup默認不攔截任何事件。
6、非ViewGroup的View沒有onInterceptTouchEvent方法,一旦有點擊事件傳遞給它,那麼它就會執行onTouchEvent方法。
7、非ViewGroup的View會默認消耗onTouchEvent,除非把clickable和longclickable同時設置爲false。
8、onClick發生情況必須是當前view是可點擊的,並且它收到了down和up事件。