Android中如何将子View的坐标转换为父View的坐标

  最近打算照着Android的Launcher2源码写一个精简的带有拖动功能的Launcher。在分析DragLayer类的时候发现了一个有趣方法——getDescendantCoordRelativeToSelf。通过一下两篇文章的介绍和自己的实验,总算是弄清楚了该方法的原理。

http://blog.csdn.net/hahajluzxb/article/details/8165258

http://www.cnblogs.com/platte/p/3534279.html

  下面主要分析一下代码的原理:

  首先需要知道的是,一般的坐标变换transform,包含了:平移translate,缩放scale,旋转rotate等。坐标变换改变的是坐标系,而点的坐标值是不会改变的(除非你主动去改变它),但是点是在坐标系上进行绘制的。坐标系的改变,将使得点的绘制发生改变。

  接下来是代码的分析,

 1 /**
 2      *
 3      * @param descendant 子View
 4      * @param coord 子View中的某点的坐标,同时该方法返回时coord转换为在最顶层ParentView坐标系下的坐标
 5      * @return 返回descendant相对于顶层ParentView的缩放值
 6      */
 7     public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
 8         float scale = 1.0f;
 9
10         //(coord[0],coord[1])分别是子View中所要转换的点的(x,y)坐标
11         float[] pt = {coord[0], coord[1]};
12
13         //子View由于旋转缩放等操作改变了子View的坐标系,这些变化反映在子View对应的Matrix上,
14         //getMatrix()方法获得子View的Matrix。而mapPoints方法则可以得到在初始的坐标系下pt点的坐标
15         descendant.getMatrix().mapPoints(pt);
16         //计算子View x轴的缩放值
17         scale *= descendant.getScaleX();
18
19         //在对子View变换时,经过我的实验发现子View的Left,Right,Top,Bottom是不变的
20         //因此下面两行可以计算出descendant中的点在其父View坐标系下的坐标
21         pt[0] += descendant.getLeft();
22         pt[1] += descendant.getTop();
23
24         //通过下面的循环,递归的一层一层计算出descendant中的点在最顶层View也就是DragLayer坐标系下的坐标值
25         //和x轴的总的缩放值
26         ViewParent viewParent = descendant.getParent();
27         while (viewParent instanceof View && viewParent != this) {
28             final View view = (View)viewParent;
29             view.getMatrix().mapPoints(pt);
30             scale *= view.getScaleX();
31             pt[0] += view.getLeft() - view.getScrollX();
32             pt[1] += view.getTop() - view.getScrollY();
33             viewParent = view.getParent();
34         }
35
36         //返回结果
37         coord[0] = (int) Math.round(pt[0]);
38         coord[1] = (int) Math.round(pt[1]);
39         return scale;
40     }

  以上就是代码的解释。要注意的是View在进行坐标变换时其view的左边,上边,右边,下边距离他的父组件的距离也即getLeft(), getTop()返回的值是不变的。至少我写了个简单的小程序运行后显示确实是这样的。

  小程序很简单,布局就是一个居中的ImageView。每点击ImageView一次,它就会旋转5度。然后Log输出其Left,Top信息。

 1 public class MainActivity extends Activity {
 2
 3     ImageView image;
 4     int rotation = 0;
 5
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10         image = (ImageView)findViewById(R.id.image);
11         image.setOnClickListener(new View.OnClickListener() {
12
13             @Override
14             public void onClick(View v) {
15                 // TODO Auto-generated method stub
16                 Rect r = new Rect();
17                 v.getHitRect(r);
18                 Log.d("TAG", "before change: v.left = " + v.getLeft() + ", v.top = " + v.getTop());
19                 float[] f1 = {0f, 0f};
20                 v.getMatrix().mapPoints(f1);
21                 Log.d("TAG", "after map: r.left = " + Math.round(f1[0]) + ", r.top = " + Math.round(f1[1]));
22                 rotation += 5;
23                 //v.setScaleX(0.5f);
24                 v.setRotation(rotation);
25                 v.getHitRect(r);
26                 Log.d("TAG", "after change: v.left = " + v.getLeft() + ", v.top = " + v.getTop());
27                 float[] f2 = {0f, 0f};
28                 v.getMatrix().mapPoints(f2);
29                 Log.d("TAG", "after map: r.left = " + Math.round(f2[0]) + ", r.top = " + Math.round(f2[1]));
30             }
31         });
32
33     }
34 }
01-17 05:53:08.100: D/TAG(1866): before change: v.left = 272, v.top = 73
01-17 05:53:08.110: D/TAG(1866): after map: r.left = 0, r.top = 0
01-17 05:53:08.110: D/TAG(1866): after change: v.left = 272, v.top = 73
01-17 05:53:08.110: D/TAG(1866): after map: r.left = 16, r.top = -20
01-17 05:53:08.830: D/TAG(1866): before change: v.left = 272, v.top = 73
01-17 05:53:08.830: D/TAG(1866): after map: r.left = 16, r.top = -20
01-17 05:53:08.830: D/TAG(1866): after change: v.left = 272, v.top = 73
01-17 05:53:08.830: D/TAG(1866): after map: r.left = 34, r.top = -39
01-17 05:53:09.800: D/TAG(1866): before change: v.left = 272, v.top = 73
01-17 05:53:09.800: D/TAG(1866): after map: r.left = 34, r.top = -39
01-17 05:53:09.800: D/TAG(1866): after change: v.left = 272, v.top = 73
01-17 05:53:09.800: D/TAG(1866): after map: r.left = 53, r.top = -56
01-17 05:53:10.910: D/TAG(1866): before change: v.left = 272, v.top = 73
01-17 05:53:10.910: D/TAG(1866): after map: r.left = 53, r.top = -56
01-17 05:53:10.910: D/TAG(1866): after change: v.left = 272, v.top = 73
01-17 05:53:10.910: D/TAG(1866): after map: r.left = 74, r.top = -72

从Log信息可以看出r.left = 272, r.top = 73在每一次点击后都是不变的。只有这样,下面两行才有意义。

        pt[0] += descendant.getLeft();
        pt[1] += descendant.getTop();

完(居然不能插入链接!!!)。

Android中如何将子View的坐标转换为父View的坐标,布布扣,bubuko.com

时间: 2024-11-10 14:26:40

Android中如何将子View的坐标转换为父View的坐标的相关文章

Android中多个Activity继承自己写的父容器(Activity)

如果你的一个应用里面有几个不同的页面却需要设置一些相同的东西,那么,我觉得应该尝试着用父容器,开始自己就是不知道这个概念,弄得自己写了太多的不应该的代码....所谓的程序.....苦煞也.. 在父容器里面,我们可以统一相同的title,以及·相同的背景页面... 这里我给出一个连接哦,不懂的,就可以嘿咻嘿咻..http://pan.baidu.com/s/1sjBDPbn Android中多个Activity继承自己写的父容器(Activity),布布扣,bubuko.com

Android 中 View移动总结:ViewDragHelper学习及用法详解

如上图简单呈现出两个方块后,提出一个需求: 1.拖动方块时,方块(即子View)可以跟随手指移动. 2.一个方块移动时,另一个方块可以跟随移动. 3.将方块移动到左边区域(右边区域)后放开(即手指离开屏幕),它会自动移动到左边界(右边界). 4.移动的时候给方块加点动画(duang~duang~duang~) . View移动的相关方法总结: 1. layout 在自定义控件中,View绘制的一个重写方法layout(),用来设置显示的位置.所以,可以通过修改View的坐标值来改变view在父V

Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析

转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PARENT/FILL_PARENT属性的原理说明 xml布局文件解析成View树的流程分析. 希望对大家能有帮助.- - 分析版本基于Android 2.3 . 1.WRAP_CONTENT.MATCH_PARENT/FILL_PARENT 初入Android殿堂的同学们,对这三个属性一定又爱又恨.爱的是使

【转】Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)>>中,我们 了解了View树的转换过程以及如何设置View的LayoutParams的.本文继续沿着既定轨迹继续未完成的job. 主要知识点如下:                 1.MeasureSpc类说明                 2.measure过程详解(揭秘其细节);   

一个demo让你彻底理解Android中触摸事件的分发

注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MO

Android中Canvas绘图基础详解(附源码下载)

Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API.Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形.Canvas绘图有三个基本要素:Canvas.绘图坐标系以及Paint.Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint.drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状

Android中Canvas绘图基础详解

原文:http://blog.csdn.net/iispring/article/details/49770651 Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API.Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形.Canvas绘图有三个基本要素:Canvas.绘图坐标系以及Paint.Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要

Android菜单详解——理解android中的Menu

Android菜单详解--理解android中的Menu 前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至今为止看到的最好的一本android书,中文版出到<精通Android 2>. 理解Android的菜单 菜单是许多应用程序不可或缺的一部分,Android中更是如此,所有搭载Android系统的手机甚至都要有一个"Menu&qu

Android中有关relativeLayout 和EditText的一些属性

  http://www.cnblogs.com/jqyp/archive/2010/10/23/1859182.html RelativeLayout用到的一些重要的属性: 第一类:属性值为true或false     android:layout_centerHrizontal  水平居中      android:layout_centerVertical   垂直居中     android:layout_centerInparent    相对于父元素完全居中     android: