之前就有写过这种小Demo,那里是使用setLayoutParams给控件设置新坐标的方式完成的,有兴趣读者可以参考博客:Android简易实战教程--第四十九话《满屏拖动的控件》
本篇小Demo,使用另一种实现方式同样完成类似的功能。
在开始之前,你需要复习一下有关坐标的知识:
int getLeft()
得到当前视图左顶点相对父视图的X轴坐标
int getTop()
得到当前视图左顶点相对父视图的Y轴坐标
int getRight()
得到当前视图右下角点相对父视图的X轴坐标
int getBottom()
得到当前视图右下角点相对父视图的Y轴坐标
layout(int left, int top, int right, int bottom) :
动态指定当前视图在父视图中的定位, 参数为相对父视图的坐标
ViewParent getParent() :
得到当前View的父视图对象
getX(): 得到控件相对自己坐标X值
getY(): 得到控件相对自己坐标Y值
getRawX(): 得到控件相对父容器坐标X值
getRawY(): 得到控件相对父容器坐标Y值
这个东西很简单,直接上Demo代码:
写的很详细,相信没有什么问题。咱们再看看代码:
public class MainActivity extends AppCompatActivity
implements View.OnTouchListener {
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_main);
mImageView.setOnTouchListener(this);
}
int lastX;//用于保存上一次事件的坐标。
int lastY;
//v----ImageView对象
@Override
public boolean onTouch(View v, MotionEvent event) {
//任何事件都会触发这里。包括按下、移动
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//按下执行这里,按下移动,这里只执行一次。获取刚刚按下位置坐标
lastX = eventX;
lastY = eventY;
break;
case MotionEvent.ACTION_MOVE:
//先获取偏移距离:此时的eventX与上边的eventX不是一个值
int dx = eventX - lastX;
int dy = eventY - lastY;
//计算控件最新坐标
int left = mImageView.getLeft() + dx;
int top = mImageView.getTop() + dy;
int right = mImageView.getRight() + dx;
int bottom = mImageView.getBottom() + dy;
//重新设置控件在父组件中的位置。参数是当前控件的四个坐标值
mImageView.layout(left, top, right, bottom);
//最后重新给lastX,lastY赋值。记录最后一次的值
lastX = eventX;
lastY = eventY;
break;
default:
break;
}
//表示我(图片控件),消费事件
return true;
}
}
运行程序结果如下:
上面图片完成了基本拖动功能,但是还是存在问题的。我们不希望它拖出屏幕,那么逻辑就需要做如下修改:
拖动到屏幕左右上下位置时候,控制不越界。
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
private ImageView mImageView;
private RelativeLayout mParentView;
private int mParentRight;
private int mParentBottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_main);
//获取控件父亲组件的实例
mParentView = (RelativeLayout) mImageView.getParent();
mImageView.setOnTouchListener(this);
}
//两个变量,用于存储上一次事件的坐标
int lastX;
int lastY;
//v----ImageView对象
@Override
public boolean onTouch(View v, MotionEvent event) {
//任何事件都会触发这里。包括按下、移动
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mParentBottom == 0){
//在onCreate方法中获取到的坐标值是0,0。这是由于绘图生命周期的原因。onDraw等方法
mParentRight = mParentView.getRight();
mParentBottom = mParentView.getBottom();
}
//按下执行这里,按下移动,这里只执行一次。获取刚刚按下位置坐标
lastX = eventX;
lastY = eventY;
case MotionEvent.ACTION_MOVE:
//先获取偏移距离:此时的eventX与上边的eventX不是一个值
int dx = eventX - lastX;
int dy = eventY - lastY;
//计算控件最新坐标
int left = mImageView.getLeft() + dx;
int top = mImageView.getTop() + dy;
int right = mImageView.getRight() + dx;
int bottom = mImageView.getBottom() + dy;
//限制坐标
if (left < 0) {
//控件右边坐标也要设置,否则会让图片越变越小
right += -left;
left = 0;
}
if(top<0){
//控件底部坐标也要设置,否则会让图片越变越小
bottom += -top;
top = 0;
}
if(bottom > mParentBottom){
top -= (bottom - mParentBottom);
bottom = mParentBottom;
}
if(right > mParentRight){
left -= (right - mParentRight);
right = mParentRight;
}
//重新设置控件在父组件中的位置。参数是当前控件的四个坐标值
mImageView.layout(left, top, right, bottom);
//最后重新给lastX,lastY赋值。记录最后一次的值
lastX = eventX;
lastY = eventY;
break;
default:
break;
}
//表示我(图片控件),消费事件。所有的MotionEvent交给我自己处理
return true;
}
}
通过mParentView = (RelativeLayout) mImageView.getParent();得到父组件控件的实例。在MotionEvent.ACTION_DOWN:按下的时候,拿到服务组件的坐标;注意在onCreate方法中获取到的坐标值是[0,0],这是由于绘图机制以及生命周期有关,还没有在屏幕上绘制完毕的原因。但是当我们进行事件点击的时候,肯定全部绘制完毕了。通过如下代码,控制不超出屏幕:
//限制坐标
if (left < 0) {
//控件右边坐标也要设置,否则会让图片越变越小
right += -left;
left = 0;
}
if(top<0){
//控件底部坐标也要设置,否则会让图片越变越小
bottom += -top;
top = 0;
}
if(bottom > mParentBottom){
top -= (bottom - mParentBottom);
bottom = mParentBottom;
}
if(right > mParentRight){
left -= (right - mParentRight);
right = mParentRight;
}
现在再一次运行程序:
我们发现,这时候拖动的控件是不会超出屏幕的。
喜欢我的朋友可以关注我博客,有问题大家一起交流。也可以动手微信扫描下方二维码查看更多安卓文章:
打开微信搜索公众号 Android程序员开发指南 或者手机扫描下方二维码 在公众号阅读更多Android文章。
微信公众号图片: