当点击事件传到View
时,系统会记下触摸点的坐标,手指移动时系统记下移动后触摸的坐标并计算出偏移量,通过偏移量来修改View
的坐标。实现View
滑动有很多中方法,主要有:layout(...)
、offsetLeftAndRight(...)
与offsetTopAndBottom(...)
、LayoutParams
、动画、scrollTo(x, y)
和scrollBy(dx, dy)
,以及Scroller
。
1 layout(...)
方法
View
进行绘制的时候会调用onLayout()
方法来设置显示的位置,因此可以通过修改View
的left
、top
、right
、bottom
这 4
种属性来控制View
的坐标。
首先自定义一个View
,在onTouchEvent()
方法中获取触摸点的坐标,代码如下所示:
public class CustomView extends View {
private int lastX;
private int lastY;
public CustomView(@NonNull @NotNull Context context) {
super(context);
}
public CustomView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// 1. 在onTouchEvent()方法中获取触摸点的坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
// 2. 获取触摸点的横、纵坐标
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:
// 3. 计算偏移量
int offsetX = x - lastX;
int offsetY = y - lastY;
// 4. layout()方法重新放置这个自定义View的位置
// 5. 每次移动时都会调用layout()方法来对屏幕重新布局,从而达到移动View的效果
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
break;
}
return true;
}
}
在布局中引用自定义View
:
<RelativeLayout 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.example.myapplication.CustomView
android:id="@+id/custom_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="50dp"
android:background="@android:color/holo_red_dark" />
</RelativeLayout>
2 offsetLeftAndRight(...)
和offsetTopAndBottom(...)
这两种方法和layout()
方法的效果差不多,其使用方式也差不多,将ACTION_MOVE
中的代码替代如下:
case MotionEvent.ACTION_MOVE:
// 1. 计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
// 2. 对left和right进行偏移
offsetLeftAndRight(offsetX);
// 3. 对top和bottom进行偏移
offsetTopAndBottom(offsetY);
break;
3 LauyoutParams
(改变布局参数)
LayoutParams
主要保存了一个View
的布局参数,因此可以通过LayoutParams
来改变View
的布局参数,从而达到改变View
位置的效果, 在ACTION_MOVE
中:
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
// 1. 取决于父控件,如果是RelativeLayout,那就是RelativeLayout.LayoutParams
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
break;
4 动画
可以采用View
动画来移动,在res
目录新建anim
文件夹并创建translate.xml
:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000">
<translate
android:fromXDelta="0"
android:toXDelta="300" />
</set>
在Java
代码中调用:
findViewById(R.id.button).setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
运行程序,设置的按钮会向右移动300
像素,然后又回到原来的位置。如果想要停留在当前位置,需要加上android:fillAfter="true"
:
<