實踐出真知,動手擼代碼吧!
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;