Android實現滑動的七種方法
阿新 • • 發佈:2019-01-22
1.layout方法
每次移動後,呼叫layout()方法對自己重新佈局從而達到移動的效果
@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; // 在當前left、top、right、bottom的基礎上加上偏移量 layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY); break; } return true; }
2.offsetLeftAndRight()和offsetTopAndBottom()
系統提供的一個對左右、上下移動的API封裝,效果和使用layout()一樣
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
3.LayoutParams
LayoutParams裡儲存了View的佈局引數,通常通過改變LayoutParams來改變一個View的位置都是通過改變這個View的Margin屬性。
case MotionEvent.ACTION_MOVE: // 計算偏移量 int offsetX = x - lastX; int offsetY = y - lastY; ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft() + offsetX; layoutParams.topMargin = getTop() + offsetY; setLayoutParams(layoutParams); break;
4.ScrollTo與ScrollBy
這兩個方法移動的是View的內容,我們應該在要移動的View所在的ViewGroup中來使用這兩個方法。
這兩個方法的區別是scrollTo(x, y)表示移動到一個具體的座標點(x, y),而scrollBy(dx, dy)表示移動的增量為dx、dy。
同時要想實現跟隨手指一動而華東的效果,需要將偏移量設定為負數
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getX(); lastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - lastX; int offsetY = y - lastY; ((View) getParent()).scrollBy(-offsetX, -offsetY); break; } return true; }
5.Scroller類
通過Scroller類可以實現平滑移動的效果,而不再是瞬間完成的動作。
使用Scroller類需要三個步驟:
- 初始化Scroller
- 重寫computeScroll()方法。用來判斷是否完成了整個滑動
- 開始滑動。startScroll(int startX, int startY, int dx, int dy, int duration)和startScroll(int startX, int startY, int dx, int dy)方法,區別是其中一個具有指定時長
private void ininView(Context context) {
// 初始化Scroller
mScroller = new Scroller(context);
}
@Override
public void computeScroll() {
super.computeScroll();
// 判斷Scroller是否執行完畢
if (mScroller.computeScrollOffset()) {
((View) getParent()).scrollTo(
mScroller.getCurrX(),
mScroller.getCurrY());
// 通過重繪來不斷呼叫computeScroll
invalidate();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getX();
lastY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
((View) getParent()).scrollBy(-offsetX, -offsetY);
break;
case MotionEvent.ACTION_UP:
// 手指離開時,執行滑動過程
View viewGroup = ((View) getParent());
mScroller.startScroll(
viewGroup.getScrollX(),
viewGroup.getScrollY(),
-viewGroup.getScrollX(),
-viewGroup.getScrollY());
invalidate();
break;
}
return true;
}
6.屬性動畫
詳情見屬性動畫的介紹
7.ViewDragHelper
使用步驟:
- 初始化ViewDragHelper
mViewDragHelper = ViewDragHelper.create(this, callback);
- 攔截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//將觸控事件傳遞給ViewDragHelper,此操作必不可少
mViewDragHelper.processTouchEvent(event);
return true;
}
- 處理computeScroll()
@Override
public void computeScroll() {
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
- 處理回撥CallBack
private ViewDragHelper.Callback callback =
new ViewDragHelper.Callback() {
// 何時開始檢測觸控事件
@Override
public boolean tryCaptureView(View child, int pointerId) {
//如果當前觸控的child是mMainView時開始檢測
return mMainView == child;
}
// 觸控到View後回撥
@Override
public void onViewCaptured(View capturedChild,
int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
// 當拖拽狀態改變,比如idle,dragging
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
}
// 當位置改變的時候呼叫,常用與滑動時更改scale等
@Override
public void onViewPositionChanged(View changedView,
int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
}
// 處理垂直滑動
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
// 處理水平滑動
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
// 拖動結束後呼叫
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指擡起後緩慢移動到指定位置
if (mMainView.getLeft() < 500) {
//關閉選單
//相當於Scroller的startScroll方法
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
//開啟選單
mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
參考文章:《Android群英傳》