Android简易实战教程--第五十二话《满屏拖动的控件2》
来源:互联网 发布:ubuntu启动程序命令 编辑:程序博客网 时间:2024/05/22 05:16
之前就有写过这种小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文章。
微信公众号图片:
- Android简易实战教程--第五十二话《满屏拖动的控件2》
- Android简易实战教程--第四十九话《满屏拖动的控件》
- Android简易实战教程--第二话《两种进度条》
- Android简易实战教程--第四十二话《Spinner下拉级联效果》
- Android简易实战教程--第十二话《代码获取手机总运行内存的大小》
- Android简易实战教程--第十二话《代码获取手机总运行内存的大小》
- Android简易实战教程--第五十话《动画扫描》
- Android简易实战教程--第二十二话《自定义组合控件模拟qq登录下拉框和其中的一些”小技巧”》
- Android实战简易教程-第五十枪(工具类的测试)
- Android简易实战教程--第三十二话《使用Lrucache和NetworkImageView加载图片》
- Android实战简易教程-第一枪(Spinner控件详解)
- Android实战简易教程<一>(Spinner控件详解)
- Android实战简易教程<五十一>(ListView实现子控件的动态显示和隐藏、checkbox全选和反选)
- Android实战简易教程<四十二>(github实用控件推荐BadgeView-图标左上角消息提示控件)
- Android控件的拖动
- Android 控件的拖动
- Android实战简易教程<七>(Activity的启动模式)
- Android实战简易教程<五十>(工具类的测试)
- 13 共享内存3
- Java:日期时间字符串和毫秒相互转换
- Nginx源码阅读(ngx_array_t)
- [Boolan] C++第二周(创建一个带指针成员变量的类)[注意事项]
- 直立平衡车的姿态测量卡尔曼滤波算法原理与应用(附代码及调试截图)
- Android简易实战教程--第五十二话《满屏拖动的控件2》
- 编程珠玑: 15章 字符串 15.2寻找字符串中的最长重复子串 -------解题总结
- C ++ new的几种用法
- 堆栈窗体QStackedWidget类
- Android mipmap文件夹和drawable文件夹的区别
- Nginx源码阅读(ngx_cycle_t)
- Jmeter连接mysql成功
- DevExpress vcl 动态调用皮肤
- 利用Python 进行数据分析 ch02