为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Android

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

--------------------------第三套广播体操:时代在召唤。现在开始-----------------------

一言不合上效果图。

5ba65a7a00019f0003600240.jpg

我做的gif好模糊啊

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

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

5ba65a7b0001edef10621350.jpg

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

  • view获取自身坐标:getLeft(),getTop(),getRight(),getBottom()

  • view获取自身宽高:getHeight(),getWidth()

  • motionEvent获取坐标:getX(),getY(),getRawX(),getRawY()


1.View获取自身坐标

其中getLeft(),getTop(),getRight(),getBottom()是View 根据父视图相应的left,top,right,buttom的位置。

5ba65a7c0001fb9003200482.jpg

view获取自身坐标

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

2.view获取自身宽高

没错。从字面意思看就能理解,就是获取View的宽高。
这里提到一个以前遇到的一个问题,就是在Activity中有时候获取某个View的width和height会为0。
没错,下面的链接你就可以搞定这个问题。哈哈。点起来。
Activity中获取view的高度和宽度为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),这时候是如下图所示这样:

5ba65a7d0001567209060716.jpg

setX(200)和setY(200)

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

5ba65a7d00018d2108740730.jpg


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

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

5ba65a7d000111e608460708.jpg

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

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

5ba65a7e0001254508560702.jpg

Paste_Image.png

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

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

5ba65a7e0001620305780728.jpg

Paste_Image.png

错误原因:

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

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

获取状态栏高度

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

获取标题栏高度

// 获取标题栏高度  Window window = getWindow();  
int contentViewTop = getWindow()  
        .findViewById(Window.ID_ANDROID_CONTENT).getTop();  
// statusBarHeight是上面所求的状态栏的高度  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监听。直接上关键代码:

package yunyuan.androiddemo.coordinatelayout;import android.app.Activity;import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.view.Window;import android.widget.Button;import butterknife.BindView;import butterknife.ButterKnife;import yunyuan.androiddemo.R;/**
 * Created by willy on 16/12/19.
 */public class Act_CoordinateLayout extends Activity{    @BindView(R.id.btn)
    Button btn;    float dx,dy;    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_coordinatelayout);
        ButterKnife.bind(this);

        btn.setOnTouchListener(new Button.OnTouchListener() {            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                    dx = motionEvent.getX();
                    dy = motionEvent.getY();

                } else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){

                    view.setX(motionEvent.getRawX() - dx);
                    view.setY(motionEvent.getRawY()- dy - getStatusBarHeight() - getTitleBarHeight());
                }                return true;
            }
        });
    }    public int getStatusBarHeight(){        int result = 0;        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");        if (resourceId > 0) {
            result = getResources().getDimensionPixelSize(resourceId);
        }        return result;
    }    public int getTitleBarHeight(){
        Window window = getWindow();        int contentViewTop = getWindow()
                .findViewById(Window.ID_ANDROID_CONTENT).getTop();        // statusBarHeight是上面所求的状态栏的高度
        int titleBarHeight = contentViewTop - getStatusBarHeight();        return titleBarHeight;
    }

}

原文链接:http://www.apkbus.com/blog-875309-62943.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消