第三章 view的事件體系 ----- view滑動/拖動
阿新 • • 發佈:2019-02-07
Android view的滑動
先看下view完整程式碼如下:
public class DemoView extends View {
private int lastX;
private int lastY;
private Scroller mScroller;
public DemoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public DemoView (Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public DemoView(Context context) {
super(context);
mScroller = new Scroller(context);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
super .computeScroll();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//獲取到手指處的橫座標和縱座標
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break ;
case MotionEvent.ACTION_MOVE:
//計算移動的距離
int offsetX = x - lastX;
int offsetY = y - lastY;
//呼叫layout方法來重新放置它的位置
// layout(getLeft() + offsetX, getTop() + offsetY,
// getRight() + offsetX, getBottom() + offsetY);
//通過translation來實現
// int translationX = (int) getTranslationX() + offsetX;
// int translationY = (int) getTranslationY() + offsetY;
// setTranslationX(translationX);
// setTranslationY(translationY);
//通過layout param 實現 需要注意:如果view在佈局檔案中設定了layout_above、center等類似屬性,則會出現問題
// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX;
// layoutParams.topMargin = getTop() + offsetY;
// setLayoutParams(layoutParams);
//通過MarginLayoutParams
// ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX; //這樣也可以
// layoutParams.topMargin = getTop() + offsetY;
// layoutParams.leftMargin += offsetX;
// layoutParams.topMargin += offsetY;
// setLayoutParams(layoutParams);
/*通過scrollBy操作,getParent是因為scrollBy是對view的內容進行移動,而不是對view本身移動
所以,當前view的移動通過獲取父佈局,對父佈局進行scrollBy操作,當前view就是父佈局的內容
note:scrollBy會對view的所有內容進行移動,如果父佈局中還有其他的view(button啊 TextView啊)
則在拖動該view時其他view也會一起移動*/
((View) getParent()).scrollBy(-offsetX,- offsetY);
break;
}
return true;
}
public void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int scrollY = getScrollY();
int deltaX = destX - scrollX;
int deltaY = destY - scrollY;
//1000秒內滑向destX destY
Log.d("xj", "smoothScrollTo: ");
mScroller.startScroll(scrollX,scrollY,deltaX,deltaY,1000);
postInvalidate();// invalidate();
}
}
一、通過layout方法實現
- case MotionEvent.ACTION_MOVE: 下的程式碼如下:
//呼叫layout方法來重新放置它的位置
layout(getLeft() + offsetX, getTop() + offsetY,
getRight() + offsetX, getBottom() + offsetY);
二、offsetLeftAndRight()offsetTopAndBottom()
- case MotionEvent.ACTION_MOVE: 下的程式碼如下:
//呼叫offset方法來重新放置它的位置,
offsetLeftAndRight(offX);
offsetTopAndBottom(offY);
三、通過translation(動畫的方式)來實現
- case MotionEvent.ACTION_MOVE: 下的程式碼如下:
//通過translation來實現
int translationX = (int) getTranslationX() + offsetX;
int translationY = (int) getTranslationY() + offsetY;
setTranslationX(translationX);
setTranslationY(translationY);
- 不隨手指移動,僅實現view的滑動,使用屬性動畫(若要相容3.0以下版本,需要使用開源動畫庫nineoldandroids)動畫開源庫:
ObjectAnimator.ofFloat(demoview,"translationX",0,300).setDuration(1000).start();
-使用view動畫滑動,R.anim.translate為動畫資原始檔:
demoview.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
四、通過LayoutParams來實現
如果view在佈局檔案中設定了layout_above、center(因文中使用了相對佈局)等類似屬性,則會出現問題,不會正常拖動
- case MotionEvent.ACTION_MOVE: 下的程式碼如下:
/*通過LayoutParams來實現,這裡父佈局使用的是RelativeLayout,因此使用RelativeLayout.LayoutParams,若父佈局是LinearLayout,則使用RelativeLayout.LayoutParams*/
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
還可以使用通過MarginLayoutParams實現,程式碼替換為:
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
//下面兩種寫法:使用一種即可
//方法一(註釋中)
//layoutParams.leftMargin = getLeft() + offsetX;
//layoutParams.topMargin = getTop() + offsetY;
//方法二
layoutParams.leftMargin += offsetX;
layoutParams.topMargin += offsetY;
setLayoutParams(layoutParams);
五、通過scollTo與scollBy(動畫的方式)來實現
sceollTo(x,y) 絕對滑動,傳入的是移動的終點座標
scrollBy(dx,dy) 相對滑動,傳入的是移動的增量,
通過scrollBy傳入的值應該是你需要的那個增量的相反數!
通過scrollBy操作,getParent是因為scrollBy是對view的內容進行移動,而不是對view本身移動,所以,當前view的移動通過獲取父佈局,對父佈局進行scrollBy操作,當前view就是父佈局的內容
note:scrollBy會對view的所有內容進行移動,如果父佈局中還有其他的view(button啊 TextView啊,則在拖動該view時其他view也會一起移動
- case MotionEvent.ACTION_MOVE: 下的程式碼如下:
//通過scrollBy來實現
((View) getParent()).scrollBy(-offsetX,- offsetY);
六、通過Scroller(彈性滑動)來實現
這個是滑動效果,不是隨著手指拖動效果
- 初始化Scroller
public DemoView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
- 重寫computeScroll()方法,
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
// postInvalidate();//這個也可以,效果上沒啥區別
invalidate();
}
}
- 呼叫Scroller.startScroll()方法。寫一個smoothScrollTo()方法來呼叫Scroller.startScroll()方法,實現滑動
public void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int scrollY = getScrollY();
int deltaX = destX - scrollX;
int deltaY = destY - scrollY;
//2000秒內滑動到指定點
mScroller.startScroll(scrollX,scrollY,deltaX,deltaY,2000
//postInvalidate();//這個也可以,效果上沒啥區別
invalidate();
}
- 在activity中呼叫該方法,注意:該方法移動的是demoView所在父佈局中的所用內容
demoView.smoothScrollTo(-500,-300);
- computeScrollOffset方法判斷是否完成了整個滑動,返回true,則沒有完成,否則完成滑動。
- 必須要用invalidate方法重新整理,因為computeScroll方法不會自動呼叫,它是在view的draw方法中被呼叫的,所以必須使用invalidate重新整理。
- 在startScroll中,偏移量跟使用scrollBy方法中的偏移量用法是一樣的,即也必須填寫你實際想要移動距離的相反數。也就是你實際想讓它偏移一個正值,這裡就填寫它相應的負值,如果想偏移一個負值,這裡就填寫相應的正值!
- 通過Scroller實現彈性滑動的程式碼基本是固定的,實現原理:
startScroll方法下面的invalidate方法會讓view進行重繪,view進行重繪時draw方法又會去呼叫computeScroll方法,該方法在view中是一個空實現,需要我們自己實現。computeScroll方法會向Scroller獲取當前的scrollX和scrollY,然後通過scrollTo方法滑動;接著又呼叫了invalidate方法重繪,重複之前的動作,直到整個滑動結束。
總結
- 其中一二三四五都是view隨手指可以移動
- scrollTo 和scrollBy 操作簡單,適合對view內容滑動
- 動畫:適用於沒有互動的view和實現複雜的動畫效果
- 改變佈局引數:操作稍微複雜,適用於有互動的view
- 參考文章,書籍,Android開發藝術探索