一、滑動方式
scrollTo/scrollBy
只能將view的內容移動,并不能移動view本身。
((View)getParent()).scrollBy(offsetX,offsetY)
mScrollX和mScrollY類似,mScrollX表示view左邊緣和view內容左邊緣的距離,也就是說當mScrollX=100時,內容看上去是往左側移了,就像Flash中的遮罩效果一樣。動畫方式
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
Android3.0以上使用屬性動畫很好,考慮向下兼容,就會出現view動畫只移動影像的問題。改變布局參數,適用于有交互的VIEW
<pre>
MarginLayoutParams params = (MarginLayoutParams)mButton1.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
mButton1.requestLayout();
//或者mButton1.setLayoutParams(params);
</pre>Scroller
scrollTo/scrollBy是瞬間完成的。Scroller則可以實現彈性滑動。
<pre>
Scroller scroller = new Scroller(mContext);
private void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int delta = destX - scrollX;
mScroller.startScroll(scrollX,0,delta,0,1000);//1秒內緩慢滑動
invalidate();
}
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurry());
postInvalidate();
}
}
</pre>
invalidate會導致view重繪,在重繪的draw方法中,會調用computeScroll方法。在mScroller.computeScrollOffset()中,會根據時間流逝計算出當前的插值,然后調用scrollTo方法更新。然后調用postInvalidate會再次重繪,反復循環,直到mScroller.computeScrollOffset()判斷滑動結束。
注意由于使用的仍然是scrollTo方式,移動的還是view的內容
二、滑動沖突
情況一:外部支持左右滑動,內部支持上下滑動,滑動時就會出現只有一個能滑動??梢酝ㄟ^判斷水平方向和豎直方向哪個移動距離大來決定是上下滑,還是左右滑。
情況二:都是支持左右滑動,但是要么只有一個能滑動,要么兩個都在滑動。需要根據具體業務邏輯來決定誰來滑動。
解決滑動沖突,主要是通過重寫父容器的onInterceptTouchEvent事件來解決。由于是在父窗口中處理,這種方式稱為外部攔截法。至于內部攔截法稍微復雜一些,因此推薦外部攔截法來解決常見滑動沖突。
public boolean onInterceptTouchEvent(MotionEvent event){
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
intercepted = false;
if(!mScroller.isFinished()){
mScroller.abortAnimation();//優化滑動體驗
intercepted = true;
}
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastXintercept;
int deltaY = y - mLastYintercept;
if(Math.abs(deltaX) > Math.abs(deltaY)){
//水平距離大父容器攔截此事件來處理滑動
intercepted = true;
}else{
//否則子元素去處理滑動
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
default:
break;
}
mLastXintercept = x;
mLastYintercept = y;
return intercepted;
}
- ACTION_DOWN
這個肯定要返回false,因為如果返回true就表示后續事件全部由父容器處理,相當于不管怎么操作都是父容器在處理滑動,顯示是不行。 - ACTION_MOVE
根據滑動距離判斷,如果父容器要處理滑動,就返回true,否則返回false交給子元素處理 - ACTION_UP
這個肯定要返回false,因為如果返回true會導致子元素收不到UP事件,onClick事件就會無法觸發。父容器不會受這個返回false影響,因為一旦它攔截事件,后續事件也會交給它處理,UP事件作為最后一個事件必定可以傳遞給父容器。