Android實現View的滑動系列一 -- 使用layout()方法

實踐出真知,動手擼代碼吧!

Android View的繪製流程中,在onLayout()方法,子view會調用layout()方法來完成自身的佈局,我們通過修改view layout()的參數從而實現view的滑動效果!

1.實現步驟

  • 重寫View的onTouchEvent()方法
  • 在onTouchEvent()方法中獲取view的座標計算滑動時的偏移量
  • 修改view的layout()方法參數從而實現view的滑動

2.實現效果

這裏寫圖片描述

3.實現Demo

3.1.佈局文件

自定義一個DragView,設置其寬和高都是100dp,用於View 滑動的測試

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.snail.viewscroller.DragView
        android:id="@+id/dv_test"
        android:layout_width="100dp"
        android:layout_height="100dp" />
</LinearLayout>

3.2.自定義的DragView

重點關注onTouchEvent()

/**
 * @author yongjie on 2018/4/22.
 */
public class DragView extends View {

    private int lastX;
    private int lastY;

    public DragView(Context context) {
        this(context, null);
    }

    public DragView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSize;
        int heightSize;

        if (widthMode == MeasureSpec.EXACTLY) {
            widthSize = MeasureSpec.getSize(widthMeasureSpec);
        } else {
            widthSize = 100;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            heightSize = MeasureSpec.getSize(heightMeasureSpec);
        } else {
            heightSize = 100;
        }

        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.RED);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        //獲取當前的座標(獲取的是觸摸事件點相對於當前view座標系的座標)
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //記錄下ACTION_DOWN時的座標
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算每次滑動的偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //調用layout()方法來重新使view佈局,使view重新繪製
                //調用getLeft、top、bottom、right等方法來獲取View在父view的原始位置然後加上偏移量得到滑動後的佈局位置
                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        //一定要返回true,不然後面的觸摸事件不會再傳遞到這兒
        return true;
    }
}

4.使用offsetLeftAndRight()與offsetTopAndBottom()實現滑動

和layout方法效果一樣,使用系統幫我們封裝出的API。只需要輕微修改onTouchEvent()方法

   @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        //獲取當前的座標(獲取的是觸摸事件點相對於當前view座標系的座標)
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //記錄下ACTION_DOWN時的座標
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計算每次滑動的偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                //只修改此處代碼即可
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        //一定要返回true,不然後面的觸摸事件不會再傳遞到這兒
        return true;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章