小Demo大知识-通过控制Button移动来学习Android坐标

简介:

今天分享一个简单的Demo。Demo实现的功能就是,用鼠标点中button的时候,然后拖动Button。这时候Button会根据你鼠标的移动而移动,同时,你鼠标点中的Button的位置也不会改变。比如你点在Button的左上角,那移动的时候。鼠标还是在Button的左上角

一言不合上效果图

大家不要介意上面那么模糊的gif图,毕竟我是用手机拍的。(介意你又能拿我怎么办。哈哈)

我们先来打个预防针,先学习基本的知识点:

涉及到的方法一共有下面几个:

  • view获取自身坐标:getLeft(),getTop(),getRight(),getBottom()
  • view获取自身宽高:getHeight(),getWidth()
  • motionEvent获取坐标:getX(),getY(),getRawX(),getRawY()

1.view获取自身坐标

如上图所以,绿色区域的父视图是黄色区域,所以left是55,top是55。

黄色区域的父视图是蓝色区域,所以left是60,top是115。

2.view获取自身宽高

没错。从字面意思看就能理解,就是获取View的宽高。

这里提到一个以前遇到的一个问题,就是在Activity中有时候获取某个View的width和height会为0。

3.motionEvent获取坐标

  • getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离
  • getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离
  • getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离
  • getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离

所以当我们用鼠标点击Button中间时候,那这时候getX()就是我们鼠标点击的位置与Button左边边界的距离。getY()就是点击的位置与Button顶边边界的距离。

其实设置Button跟着鼠标滑动,很简单,就是在鼠标滑动的时候,重新设置Button的x和y坐标。即使用setX()和setY()。这时候就有问题了。那二个方法中该填入的值是多少呢。让我们画个图来看下就知道了。

首先我们比如对一个Button设置setX(200),setY(200),这时候是如下图所示这样:

所以实际上对一个Button设置setX(m),setY(n),实际上是这个Button的左上角的坐标为(m,n)。所以我们在拖动的时候不能简单的把我们点击的X和Y坐标传过去。 

如上图所示,假如我们点中红色的区域,来准备移动这个Button,并且鼠标移动了绿色区域那个地方,那么这个Button也会移到图上所示那样。这样才是我们所期望的样子。

但是如果单纯把绿色区域的X和Y坐标传过去,让Button来进行setX和setY 。则会出现如下那个Button所示位置。所以发现比我们期望的位置更靠右边及下边了。  

这时候我们发现多的位置正好是绿色区域在这个Button内部中相对位置的X和Y坐标。

这下我们是不是就想到,对Button设置setX(getRawX()-getX())和setY(getRawY()- getY()),如果这时候你已经这么想到了。恭喜你,你已经距离最后的成功差一小步了。当你高兴的这么写后,你会发现你移动后的Button总是在鼠标点击的下方。你会发现。X轴的的确已经正确了。但是Y轴还是错误。如下图所示: 

这时候你一定会问,WHY???

原来这么分析是没问题的。But这个我们前面的假设都是在这个坐标系中,但是这个坐标系的位置在哪里??? 

错误原因:

因为我们调用的getRawY()方法获取到的是屏幕左上角到我们点的区域的Y轴的距离,也就是以蓝色坐标系来做参考。而我们对Button设置setY()方法的时候是绿色区域的左上角到我们点的区域的Y轴距离,也就是以红色坐标系来做参考。所以我们知道了。我们在Y轴上还要减去状态栏的高度及应用标题栏的高度才可以。

那么又有新的问题了。如何获取状态栏的高度,和应用标题栏的高度:

获取状态栏高度


  
  
  1. int statusBarHeight = -1;   
  2. //获取status_bar_height资源的ID   
  3. int resourceId = getResources().getIdentifier("status_bar_height""dimen""android");   
  4. if (resourceId > 0) {   
  5.     //根据资源ID获取响应的尺寸值   
  6.     statusBarHeight = getResources().getDimensionPixelSize(resourceId);   
  7.  

获取标题栏高度


  
  
  1. // 获取标题栏高度   
  2. Window window = getWindow();   
  3. int contentViewTop = getWindow()   
  4.         .findViewById(Window.ID_ANDROID_CONTENT).getTop();   
  5. // statusBarHeight是上面所求的状态栏的高度   
  6. titleBarHeight = contentViewTop - statusBarHeight;  

结论:

所以最后我们再拖动Button的时候,会对它setX(getRawX()-getX())及setY(getRawY()-getY()-状态栏高度-标题栏高度)。其中getX()和getY()是在你点击下去的时候就获取的。也就是在motionEvent.getAction() == MotionEvent.ACTION_DOWN的时候去获取这二个值即可。因为在motionEvent.getAction() == MotionEvent.ACTION_MOVE的时候去获取getX()和getY()可能因为你拖动的速度原因造成值不同,比如你拖动很快,鼠标先过去了。Button后面才跟随着过来。这时候的getX()及getY()都不同。

既然点击按钮后可以拖动Button,那肯定对Button设置了OnTouch监听。直接上关键代码: 


  
  
  1. package yunyuan.androiddemo.coordinatelayout;
  2. import android.app.Activity; 
  3. import android.os.Bundle; 
  4. import android.view.MotionEvent; 
  5. import android.view.View
  6. import android.view.Window; 
  7. import android.widget.Button; 
  8.  
  9. import butterknife.BindView; 
  10. import butterknife.ButterKnife; 
  11. import yunyuan.androiddemo.R; 
  12.  
  13. /** 
  14.  * Created by willy on 16/12/19. 
  15.  */ 
  16.  
  17. public class Act_CoordinateLayout extends Activity{ 
  18.  
  19.     @BindView(R.id.btn) 
  20.     Button btn; 
  21.  
  22.     float dx,dy; 
  23.  
  24.  
  25.     @Override 
  26.     protected void onCreate(Bundle savedInstanceState) { 
  27.         super.onCreate(savedInstanceState); 
  28.         setContentView(R.layout.act_coordinatelayout); 
  29.         ButterKnife.bind(this); 
  30.  
  31.         btn.setOnTouchListener(new Button.OnTouchListener() { 
  32.             @Override 
  33.             public boolean onTouch(View view, MotionEvent motionEvent) { 
  34.                 if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){ 
  35.                     dx = motionEvent.getX(); 
  36.                     dy = motionEvent.getY(); 
  37.  
  38.                 } else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){ 
  39.  
  40.                     view.setX(motionEvent.getRawX() - dx); 
  41.                     view.setY(motionEvent.getRawY()- dy - getStatusBarHeight() - getTitleBarHeight()); 
  42.                 } 
  43.                 return true
  44.             } 
  45.         }); 
  46.     } 
  47.  
  48.  
  49.     public int getStatusBarHeight(){ 
  50.         int result = 0; 
  51.         int resourceId = getResources().getIdentifier("status_bar_height""dimen""android"); 
  52.         if (resourceId > 0) { 
  53.             result = getResources().getDimensionPixelSize(resourceId); 
  54.         } 
  55.         return result; 
  56.     } 
  57.  
  58.  
  59.     public int getTitleBarHeight(){ 
  60.         Window window = getWindow(); 
  61.         int contentViewTop = getWindow() 
  62.                 .findViewById(Window.ID_ANDROID_CONTENT).getTop(); 
  63.         // statusBarHeight是上面所求的状态栏的高度 
  64.         int titleBarHeight = contentViewTop - getStatusBarHeight(); 
  65.         return titleBarHeight; 
  66.     } 
  67.  



作者:青蛙要fly
来源:51CTO
目录
相关文章
|
3月前
|
XML API Android开发
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
本文介绍了如何使用androidx.preference库快速创建具有一级和二级菜单的Android设置界面的步骤和示例代码。
97 1
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
|
2月前
|
Java Maven 开发工具
第一个安卓项目 | 中国象棋demo学习
本文是作者关于其第一个安卓项目——中国象棋demo的学习记录,展示了demo的运行结果、爬坑记录以及参考资料,包括解决Android Studio和maven相关问题的方法。
第一个安卓项目 | 中国象棋demo学习
|
27天前
|
Web App开发 编解码 视频直播
视频直播技术干货(十二):从入门到放弃,快速学习Android端直播技术
本文详细介绍了Android端直播技术的全貌,涵盖了从实时音视频采集、编码、传输到解码与播放的各个环节。文章还探讨了直播中音视频同步、编解码器选择、传输协议以及直播延迟优化等关键问题。希望本文能为你提供有关Andriod端直播技术的深入理解和实践指导。
39 0
|
2月前
|
Android开发
Android学习 —— 测试init.rc中的条件触发的处理顺序
Android学习 —— 测试init.rc中的条件触发的处理顺序
|
3月前
|
搜索推荐 Android开发
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
本文分享了不同价位电脑配置对于编译AOSP安卓系统源代码的影响,提供了从6000元到更高价位的电脑配置实例,并比较了它们的编译时间,以供学习AOSP源代码时电脑配置选择的参考。
216 0
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
|
5月前
|
XML Java Android开发
15. 【Android教程】按钮 Button/ImageButton
15. 【Android教程】按钮 Button/ImageButton
68 2
|
6月前
|
存储 定位技术 开发工具
Android 开发前的设计,Android之内存泄漏调试学习与总结
Android 开发前的设计,Android之内存泄漏调试学习与总结
|
6月前
|
算法 安全 Java
2024年Android最新知识体系最强总结(全方面覆盖Android知识结构,BAT面试&学习进阶)
2024年Android最新知识体系最强总结(全方面覆盖Android知识结构,BAT面试&学习进阶)
|
Java Android开发 数据安全/隐私保护
一个Demo让你掌握Android所有控件
原文:一个Demo让你掌握Android所有控件 本文是转载收藏,侵删,出处:"安卓巴士"       下面给出实现各个组件的源代码: 1.
1280 0
|
数据安全/隐私保护 Android开发 数据格式