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;

猜你喜欢

转载自blog.csdn.net/txksnail/article/details/80040226
今日推荐