首页 > 代码库 > Android中如何将子View的坐标转换为父View的坐标
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 @Override14 public void onClick(View v) {15 // TODO Auto-generated method stub16 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 = 7301-17 05:53:08.110: D/TAG(1866): after map: r.left = 0, r.top = 001-17 05:53:08.110: D/TAG(1866): after change: v.left = 272, v.top = 7301-17 05:53:08.110: D/TAG(1866): after map: r.left = 16, r.top = -2001-17 05:53:08.830: D/TAG(1866): before change: v.left = 272, v.top = 7301-17 05:53:08.830: D/TAG(1866): after map: r.left = 16, r.top = -2001-17 05:53:08.830: D/TAG(1866): after change: v.left = 272, v.top = 7301-17 05:53:08.830: D/TAG(1866): after map: r.left = 34, r.top = -3901-17 05:53:09.800: D/TAG(1866): before change: v.left = 272, v.top = 7301-17 05:53:09.800: D/TAG(1866): after map: r.left = 34, r.top = -3901-17 05:53:09.800: D/TAG(1866): after change: v.left = 272, v.top = 7301-17 05:53:09.800: D/TAG(1866): after map: r.left = 53, r.top = -5601-17 05:53:10.910: D/TAG(1866): before change: v.left = 272, v.top = 7301-17 05:53:10.910: D/TAG(1866): after map: r.left = 53, r.top = -5601-17 05:53:10.910: D/TAG(1866): after change: v.left = 272, v.top = 7301-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();
完(居然不能插入链接!!!)。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。