前言
1.layout()方法
View进行绘制时会调用onLayout()方法来设置显示的位置,因此我们可以通过修改View的left、top、right、bottom、这4种属性来控制View的坐标系。首先我们要自定义一个View,在onTouchEvent()方法中获取触摸点的坐标,代码如下:
@Override public boolean onTouchEvent(MotionEvent event) { //获取手指触摸点的横纵坐标 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; |
接下来我们在ACTION_MOVE事件计算偏移量,再调用layout()方法重新放置这个自定义View的位置即可。代码如下:
case MotionEvent.ACTION_MOVE: //计算移动的距离 int offfsetX = x - lastX; int offfsetY = x - lastY; //重新布局 layout(getLeft() + offfsetX, getTop() + offfsetY, getRight() + offfsetX, getBottom() + offfsetY); break; |
在每次移动调用layout()方法都要重新布局,从而达到移动View的效果。自定义View如下代码:
public class CustomeView extends View { private int lastX, lastY; public CustomeView(Context context) { super(context); } public CustomeView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CustomeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { //获取手指触摸点的横纵坐标 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: //计算移动的距离 int offfsetX = x - lastX; int offfsetY = x - lastY; //重新布局 layout(getLeft() + offfsetX, getTop() + offfsetY, getRight() + offfsetX, getBottom() + offfsetY); break; } return true; } } |
随后,我们在布局中引用自定义View就OK了,xml布局代码如下:
<?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.example.administrator.mypermission.view.CustomeView
android:id="@+id/tv_callPhone"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"/>
</LinearLayout> |
2.offsetLeftAndRight()与offsetTopAndBottom()
这两种方法和layout()方法效果差不多,代码如下:
case MotionEvent.ACTION_MOVE: //计算移动的距离 int offfsetX = x - lastX; int offfsetY = x - lastY; //重新布局 // layout(getLeft() + offfsetX, // getTop() + offfsetY, // getRight() + offfsetX, // getBottom() + offfsetY); //对left和right进行偏移 offsetLeftAndRight(offfsetX); //对top和bottom进行偏移 offsetTopAndBottom(offfsetY); break; |
3.LayoutParams改变布局参数
LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变View的布局参数从而达到改变View的位置,同样我们将ACTION_MOVE中的代码替换如下代码:
case MotionEvent.ACTION_MOVE: //计算移动的距离 int offfsetX = x - lastX; int offfsetY = x - lastY; LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft()+offfsetX; layoutParams.topMargin = getLeft()+offfsetY; setLayoutParams(layoutParams); break; |
4.动画
可以采用View动画来移动,在res目录新建anim文件并创建translate.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="300"
android:duration="1000"/>
</set> |
接下来代码中调用,代码如下:
mCoustome.setAnimation(
AnimationUtils.loadAnimation(this,R.anim.translate))
运行程序,我们设置的控件会向右平移300像素,然后又回到原来的位置。为了解决这个问题,我们需要在tanslate.xml中加上fillAfter = “true”,代码如下。运行代码后会发现,控件向右平移300像素后就停留当前的位置。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:toXDelta="300"
android:duration="1000"/>
</set> |