Android自定义控件热身——View的坐标位置和大小详解

Android自定义控件热身——View的坐标位置和大小详解

原创  2017年02月10日 11:20:47

转载请注明出处:http://blog.csdn.net/xiaohao0724/article/details/54965579

在自定义控件中我们经常会用到View位置的腾挪移动,今天就来和大家一块揭开View坐标位置的神秘面纱。

android中View的坐标系统 :屏幕的左上角View绘制区是坐标系统原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向。


屏幕高度=状态栏高度+应用区高度=状态栏高度+(标题栏高度+View绘制区域高度)

一、View的坐标位置

1、getTop(),getBottom(),getLeft()和getRight()

需要注意view的坐标位置是相对父容器(紧包括着View的父容器不是最外层的父容器)而言的。

以getTop为例,函数源代码为:

[java]  view plain  copy
  1. /** 
  2. * Top position of this view relative to its parent. 
  3. * 相对应父控件的top位置,单位为像素,即头部到父控件的距离 
  4. * @return The top of this view, in pixels. 
  5. */   
  6. @ViewDebug.CapturedViewProperty   
  7.   
  8. public final int getTop() {   
  9.     return mTop;   
  10. }    



①为View.getLeft() ;  

②为View.getTop();

③为ViewGroup.getRight()

④为ViewGroup.getBottom()


2、getX和getY

如果对View进行了移动如:

View.setTranslationX(200); 则View.getLeft()的值依然为①,View.getLeft() ≠ ① + 200;

View.getLeft()是控件原始位置距离父View左边的距离,那么移动后的距离如何获得呢?其实可以通过View.getX获得控件移动后的坐标View.getX = ① + 200即, View.getX()= View.getLeft() + View.getTranslationX();

getTop()、getBottom()、getLeft()和getRight()是控件初始位置距离父View容器上、下、左、右边的距离;

View.getX、View.getY是控件最后视觉位置(如果有移动则是移动过后的位置)距离父View父容器左边、上边的距离


也可获取控件距离屏幕的距离

[java]  view plain  copy
  1. final int[] location = new int[2];  
  2. View.getLocationOnScreen(location);  
  3. int x = location[0];  
  4. int y = location[1];  
  5. // 控件最终视觉位置(如果有移动则是移动过后的位置)距离手机屏幕屏幕左边、上边的距离  
  6. Log.i(TAG, "OnScreenX=" + x);  
  7. Log.i(TAG, "OnScreenY=" + y);  


在Activity的onCreat方法中获取不到控件的位置和大小,必修要控件完成绘制才可以获取到其位置和大小,可以用以下两种方式来实现:

[java]  view plain  copy
  1. @Override  
  2. public void onWindowFocusChanged(boolean hasFocus) {  
  3.     super.onWindowFocusChanged(hasFocus);  
  4.      //获取控件的位置和大小  
  5.        
  6. }  


[java]  view plain  copy
  1. View.getViewTreeObserver().addOnGlobalLayoutListener(  
  2.         new ViewTreeObserver.OnGlobalLayoutListener() {  
  3.             // 在控件完成绘制后调用  
  4.             @Override  
  5.             public void onGlobalLayout() {  
  6.             //后去控件的位置和大小  
  7.             .  
  8.             .  
  9.             .  
  10.             // 测量成功后移除监听器,只调用一次  
  11.             View.getViewTreeObserver().removeGlobalOnLayoutListener(this);  
  12.   
  13.             }  
  14.         });  


3、MotionEvent类中 getRawX()和 getRawY()
[java]  view plain  copy
  1. @Override  
  2.      public boolean onTouchEvent(MotionEvent event) {  
  3.             switch (event.getAction()) {  
  4.             case MotionEvent.ACTION_DOWN:  
  5.               
  6.              float rawX = event.getRawX();  
  7.              float x = event.getX();  
  8.              float rawY = event.getRawY();  
  9.              float y = event.getY();  
  10.                 break;  
  11.             case MotionEvent.ACTION_MOVE:  
  12.                    
  13.                 break;  
  14.             case MotionEvent.ACTION_UP:  
  15.                   
  16.        
  17.                 break;  
  18.             default:  
  19.                 break;  
  20.             }  
  21.             return super.onTouchEvent(event);  
  22.         }  



    event.getRowX():触摸点相对于手机屏幕原点的x坐标,不管App是否有状态栏、全屏等。
    event.getX():   触摸点相对于自身组件原点的x坐标 ,触摸点到触摸点所在控件左上角的X轴距离


4、通过对View多种方式的移动来研究View的getLeft和getX的不同

activity_main.xml

[html]  view plain  copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.havorld.viewxy.MainActivity" >  
  6.   
  7.     <LinearLayout  
  8.         android:id="@+id/ll"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent" >  
  11.   
  12.         <TextView  
  13.             android:id="@+id/tv"  
  14.             android:layout_width="wrap_content"  
  15.             android:layout_height="wrap_content"  
  16.             android:layout_marginLeft="10dp"  
  17.             android:background="@android:color/holo_green_light"  
  18.             android:text="我是TextView" />  
  19.     </LinearLayout>  
  20.   
  21. </RelativeLayout>  


MainActivity.java

[java]  view plain  copy
  1. public class MainActivity extends Activity implements OnClickListener {  
  2.   
  3.     protected static final String TAG = "Havorld";  
  4.     private TextView textView;  
  5.     private LinearLayout linearLayout;  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         textView = (TextView) findViewById(R.id.tv);  
  12.         linearLayout = (LinearLayout) findViewById(R.id.ll);  
  13.   
  14.         textView.setOnClickListener(this);  
  15.         linearLayout.setOnClickListener(this);  
  16.     }  
  17.   
  18.     private void move6() {  
  19.   
  20.         textView.layout(textView.getLeft() + 20, textView.getTop(),  
  21.                 textView.getRight(), textView.getBottom());  
  22.   
  23.     }  
  24.   
  25.     private void move5() {  
  26.   
  27.         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) textView  
  28.                 .getLayoutParams();  
  29.         lp.leftMargin += 100;  
  30.         textView.setLayoutParams(lp);  
  31.     }  
  32.   
  33.     private void move4() {  
  34.   
  35.         linearLayout.scrollBy(-30, -30);  
  36.     }  
  37.   
  38.     private void move3() {  
  39.   
  40.         textView.setTranslationY(300);  
  41.     }  
  42.   
  43.     private void move2() {  
  44.   
  45.         ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView,  
  46.                 "translationY"050100150200250300);  
  47.         objectAnimator.setDuration(2000).start();  
  48.     }  
  49.   
  50.     private void move1() {  
  51.   
  52.         TranslateAnimation translateAnimation = new TranslateAnimation(2020,  
  53.                 0300);  
  54.         translateAnimation.setDuration(2000);  
  55.         translateAnimation.setFillAfter(true);// 保持移动后的状态  
  56.         textView.startAnimation(translateAnimation);  
  57.     }  
  58.   
  59.     @Override  
  60.     public void onClick(View v) {  
  61.         switch (v.getId()) {  
  62.   
  63.         case R.id.tv:// 点击查看位置  
  64.             Log.e(TAG, "getLeft:" + textView.getLeft());  
  65.             Log.e(TAG, "getTop:" + textView.getTop());  
  66.             Log.e(TAG, "getX:" + textView.getX());  
  67.             Log.e(TAG, "getY:" + textView.getY());  
  68.             break;  
  69.   
  70.         case R.id.ll: // 点击对textView进行移动  
  71.   
  72.             // 方式一:通过补间动画移动  
  73.             // move1();  
  74.   
  75.             // 方式二:通过属性动画移动  
  76.             // move2();  
  77.   
  78.             // 方式三:通过setTranslationX或setTranslationY等移动  
  79.             // move3();  
  80.   
  81.             // 方式四:通过scrollBy或ScrollTo移动  
  82.             move4();  
  83.   
  84.             // 方式五:通过改变布局参数  
  85.             // move5();  
  86.   
  87.             // 方式六:通过改变布局参数  
  88.             move6();  
  89.   
  90.             break;  
  91.   
  92.         default:  
  93.             break;  
  94.         }  
  95.     }  
  96. }  


先点击外层布局linearLayout分别通过四种方式对textView进行移动,然后再分别点击textView获取其移动后的位置。


方式一:通过补间动画移动


注意:补间动画移动后点击TextView获取其位置时要点击其原始位置而不是移动后的位置

移动后位置的点击事件不可执行


方式二:通过属性动画移动


移动后位置的点击事件可执行


方式三:通过setTranslationX或setTranslationY等移动


移动后位置的点击事件可执行


方式四:通过ScrollTo和scrollBy移动

移动后位置的点击事件可执行

更多关于scrollTo和scrollBy的内容请参考:http://blog.csdn.net/xiaohao0724/article/details/54984850


方式五:通过改变布局参数


移动后位置的点击事件可执行


方式六:通过改变布局参数


移动后位置的点击事件可执行


二、View控件的大小


1、getWidth()和getHeight()
getWidth()和getHeight()是获取控件的宽高。得到的是view在父容器中布局好后的宽高值,如果没有父布局,那麼默认的父布局是整个屏幕。


2、getMeasuredWidth()和getMeasuredHeight()

getMeasuredWidth()和getMeasuredHeight()是获取控件内容的宽高。

对控件上的内容进行测量后得到的view里面的内容占据的宽度和高度,前提是你必须在父布局的onLayout()方法或者此View的onDraw()方法里调用measure(int widthMeasureSpec, int heightMeasureSpec),获取之前必须调用否则将与getWidth()和getHeight()得到的结果相同。


[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     public void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         MyLayout myLayout = new MyLayout(this);  
  6.         MyTextView textView = new MyTextView(this);  
  7.         LayoutParams layoutParams = new LayoutParams(200400);  
  8.         textView.setLayoutParams(layoutParams);  
  9.         myLayout.addView(textView);  
  10.         setContentView(myLayout);  
  11.     }  
  12.   
  13.     public class MyLayout extends LinearLayout {  
  14.         public MyLayout(Context context) {  
  15.             super(context);  
  16.         }  
  17.   
  18.         @Override  
  19.         protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  20.             super.onLayout(changed, l, t, r, b);  
  21.             // View childView=getChildAt(0);  
  22.             // childView.measure(0, 0);  
  23.   
  24.             // 如果添加测量的话:打印日志:MyLayout---MeasuredWidth= 200,MeasuredHeight= 400  
  25.             // measure(0, 0);  
  26.             // 打印日志: MyLayout---width= 1080,height= 1716  
  27.             Log.i("TAG""MyLayout---width= " + getWidth() + ",height= "  
  28.                     + getHeight());  
  29.             // 打印日志:MyLayout---MeasuredWidth= 1080,MeasuredHeight= 1716  
  30.             Log.i("TAG""MyLayout---MeasuredWidth= " + getMeasuredWidth()  
  31.                     + ",MeasuredHeight= " + getMeasuredHeight());  
  32.         }  
  33.     }  
  34.   
  35.     public class MyTextView extends TextView {  
  36.         public MyTextView(Context context) {  
  37.             super(context);  
  38.             setText("test test ");  
  39.         }  
  40.   
  41.         @Override  
  42.         protected void onDraw(Canvas canvas) {  
  43.             super.onDraw(canvas);  
  44.             measure(00); // 添加测量方法  
  45.             // 打印日志:TextView---width: 200,height: 400  
  46.             Log.i("TAG""TextView---width: " + getWidth() + ",height: "  
  47.                     + getHeight());  
  48.             // 打印日志:TextViewTest---MeasuredWidth: 164,MeasuredHeight: 57  
  49.             Log.i("TAG""TextView---MeasuredWidth: " + getMeasuredWidth()  
  50.                     + ",MeasuredHeight: " + getMeasuredHeight());  
  51.         }  
  52.     }  
  53. }  


注:

getMeasuredWidth()和getMeasuredHeight 的值是在 onMeausre 方法结束后获取到的;

getWidth() 和 getHeight() 的值是在 onLayout 方法结束后可以获取到的。

另外getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,
而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。

视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在XML文件中指定视图的大小,然后视图本身会决定其最终的大小。

点击下载源码


版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值