实践出真知,动手撸代码吧!
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;