Android简易实战教程--第五十二话《满屏拖动的控件2》
2017-01-22 11:50
471 查看
之前就有写过这种小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文章。微信公众号图片:
本篇小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简易实战教程--第四十九话《满屏拖动的控件》
- Android简易实战教程--第四十九话《满屏拖动的控件》
- Android实战简易教程<五十一>(ListView实现子控件的动态显示和隐藏、checkbox全选和反选)
- Android实战简易教程<四十四>(Ripple Effect-为控件增加涟漪效果)
- Android简易实战教程--第二十二话《自定义组合控件模拟qq登录下拉框和其中的一些”小技巧”》
- Android实战简易教程-第一枪(Spinner控件详解)
- Android实战简易教程<三十三>(自定义View实现控件晃动提示效果)
- Android简易实战教程--第二十二话《自定义组合控件模拟qq登录下拉框和其中的一些”小技巧”》
- Android实战简易教程-第五十一枪(ListView实现子控件的动态显示和隐藏、checkbox全选和反选)
- Android实战简易教程<四>(ScrollView和HorizontalScrollView动态添加控件并提供事件监听)
- Android实战简易教程<四十二>(github实用控件推荐BadgeView-图标左上角消息提示控件)
- Android实战简易教程<五十九>(EventBus小实例-传值、控制其他页控件显示)
- Android实战简易教程-第五十九枪(EventBus小实例-传值、控制其他页控件显示)
- Android实战简易教程-第四枪(ScrollView和HorizontalScrollView动态添加控件并提供事件监听)
- Android实战简易教程-第三十三枪(自定义View实现控件晃动提示效果)
- Android实战简易教程-第一枪(Spinner控件详解)
- Android实战简易教程-第二十六枪(基于ViewPager实现微信页面切换效果)