Android自定义控件热身——View的坐标位置和大小详解
2017-02-10 11:20
513 查看
转载请注明出处:http://blog.csdn.net/xiaohao0724/article/details/54965579
在自定义控件中我们经常会用到View位置的腾挪移动,今天就来和大家一块揭开View坐标位置的神秘面纱。
android中View的坐标系统 :屏幕的左上角View绘制区是坐标系统原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向。
屏幕高度=状态栏高度+应用区高度=状态栏高度+(标题栏高度+View绘制区域高度)
以getTop为例,函数源代码为:
①为View.getLeft() ;
②为View.getTop();
③为ViewGroup.getRight();
④为ViewGroup.getBottom()
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父容器左边、上边的距离。
也可获取控件距离屏幕的距离
在Activity的onCreat方法中获取不到控件的位置和大小,必修要控件完成绘制才可以获取到其位置和大小,可以用以下两种方式来实现:
event.getRowX():触摸点相对于手机屏幕原点的x坐标,不管App是否有状态栏、全屏等。
event.getX(): 触摸点相对于自身组件原点的x坐标 ,触摸点到触摸点所在控件左上角的X轴距离
MainActivity.java
先点击外层布局linearLayout分别通过四种方式对textView进行移动,然后再分别点击textView获取其移动后的位置。
方式一:通过补间动画移动
注意:补间动画移动后点击TextView获取其位置时要点击其原始位置而不是移动后的位置
移动后位置的点击事件不可执行
方式二:通过属性动画移动
移动后位置的点击事件可执行
方式三:通过setTranslationX或setTranslationY等移动
移动后位置的点击事件可执行
方式四:通过ScrollTo和[b]scrollBy移动
[/b]
移动后位置的点击事件可执行
更多关于scrollTo和scrollBy的内容请参考:http://blog.csdn.net/xiaohao0724/article/details/54984850
方式五:通过改变布局参数
移动后位置的点击事件可执行
方式六:通过改变布局参数
移动后位置的点击事件可执行
对控件上的内容进行测量后得到的view里面的内容占据的宽度和高度,前提是你必须在父布局的onLayout()方法或者此View的onDraw()方法里调用measure(int widthMeasureSpec, int heightMeasureSpec),获取之前必须调用否则将与getWidth()和getHeight()得到的结果相同。
注:
getMeasuredWidth()和getMeasuredHeight 的值是在 onMeausre 方法结束后获取到的;
getWidth() 和 getHeight() 的值是在 onLayout 方法结束后可以获取到的。
另外getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,
而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。
视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在XML文件中指定视图的大小,然后视图本身会决定其最终的大小。
点击下载源码
在自定义控件中我们经常会用到View位置的腾挪移动,今天就来和大家一块揭开View坐标位置的神秘面纱。
android中View的坐标系统 :屏幕的左上角View绘制区是坐标系统原点(0,0),原点向右延伸是X轴正方向,原点向下延伸是Y轴正方向。
屏幕高度=状态栏高度+应用区高度=状态栏高度+(标题栏高度+View绘制区域高度)
一、View的坐标位置
1、getTop(),getBottom(),getLeft()和getRight()
需要注意view的坐标位置是相对父容器(紧包括着View的父容器不是最外层的父容器)而言的。以getTop为例,函数源代码为:
/** * Top position of this view relative to its parent. * 相对应父控件的top位置,单位为像素,即头部到父控件的距离 * @return The top of this view, in pixels. */ @ViewDebug.CapturedViewProperty public final int getTop() { return mTop; }
①为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父容器左边、上边的距离。
也可获取控件距离屏幕的距离
final int[] location = new int[2]; View.getLocationOnScreen(location); int x = location[0]; int y = location[1]; // 控件最终视觉位置(如果有移动则是移动过后的位置)距离手机屏幕屏幕左边、上边的距离 Log.i(TAG, "OnScreenX=" + x); Log.i(TAG, "OnScreenY=" + y);
在Activity的onCreat方法中获取不到控件的位置和大小,必修要控件完成绘制才可以获取到其位置和大小,可以用以下两种方式来实现:
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); //获取控件的位置和大小 }
View.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { // 在控件完成绘制后调用 @Override public void onGlobalLayout() { //后去控件的位置和大小 . . . // 测量成功后移除监听器,只调用一次 View.getViewTreeObserver().removeGlobalOnLayoutListener(this); } });
3、MotionEvent类中 getRawX()和 getRawY()
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: float rawX = event.getRawX(); float x = event.getX(); float rawY = event.getRawY(); float y = event.getY(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; default: break; } return super.onTouchEvent(event); }
event.getRowX():触摸点相对于手机屏幕原点的x坐标,不管App是否有状态栏、全屏等。
event.getX(): 触摸点相对于自身组件原点的x坐标 ,触摸点到触摸点所在控件左上角的X轴距离
4、通过对View多种方式的移动来研究View的getLeft和getX的不同
activity_main.xml<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.havorld.viewxy.MainActivity" > <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:background="@android:color/holo_green_light" android:text="我是TextView" /> </LinearLayout> </RelativeLayout>
MainActivity.java
public class MainActivity extends Activity implements OnClickListener { protected static final String TAG = "Havorld"; private TextView textView; private LinearLayout linearLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.tv); linearLayout = (LinearLayout) findViewById(R.id.ll); textView.setOnClickListener(this); linearLayout.setOnClickListener(this); } private void move6() { textView.layout(textView.getLeft() + 20, textView.getTop(), textView.getRight(), textView.getBottom()); } private void move5() { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) textView .getLayoutParams(); lp.leftMargin += 100; textView.setLayoutParams(lp); } private void move4() { linearLayout.scrollBy(-30, -30); } private void move3() { textView.setTranslationY(300); } private void move2() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView, "translationY", 0, 50, 100, 150, 200, 250, 300); objectAnimator.setDuration(2000).start(); } private void move1() { TranslateAnimation translateAnimation = new TranslateAnimation(20, 20, 0, 300); translateAnimation.setDuration(2000); translateAnimation.setFillAfter(true);// 保持移动后的状态 textView.startAnimation(translateAnimation); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.tv:// 点击查看位置 Log.e(TAG, "getLeft:" + textView.getLeft()); Log.e(TAG, "getTop:" + textView.getTop()); Log.e(TAG, "getX:" + textView.getX()); Log.e(TAG, "getY:" + textView.getY()); break; case R.id.ll: // 点击对textView进行移动 // 方式一:通过补间动画移动 // move1(); // 方式二:通过属性动画移动 // move2(); // 方式三:通过setTranslationX或setTranslationY等移动 // move3(); // 方式四:通过scrollBy或ScrollTo移动 move4(); // 方式五:通过改变布局参数 // move5(); // 方式六:通过改变布局参数 move6(); break; default: break; } } }
先点击外层布局linearLayout分别通过四种方式对textView进行移动,然后再分别点击textView获取其移动后的位置。
方式一:通过补间动画移动
注意:补间动画移动后点击TextView获取其位置时要点击其原始位置而不是移动后的位置
移动后位置的点击事件不可执行
方式二:通过属性动画移动
移动后位置的点击事件可执行
方式三:通过setTranslationX或setTranslationY等移动
移动后位置的点击事件可执行
方式四:通过ScrollTo和[b]scrollBy移动
[/b]
移动后位置的点击事件可执行
更多关于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()得到的结果相同。
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyLayout myLayout = new MyLayout(this); MyTextView textView = new MyTextView(this); LayoutParams layoutParams = new LayoutParams(200, 400); textView.setLayoutParams(layoutParams); myLayout.addView(textView); setContentView(myLayout); } public class MyLayout extends LinearLayout { public MyLayout(Context context) { super(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); // View childView=getChildAt(0); // childView.measure(0, 0); // 如果添加测量的话:打印日志:MyLayout---MeasuredWidth= 200,MeasuredHeight= 400 // measure(0, 0); // 打印日志: MyLayout---width= 1080,height= 1716 Log.i("TAG", "MyLayout---width= " + getWidth() + ",height= " + getHeight()); // 打印日志:MyLayout---MeasuredWidth= 1080,MeasuredHeight= 1716 Log.i("TAG", "MyLayout---MeasuredWidth= " + getMeasuredWidth() + ",MeasuredHeight= " + getMeasuredHeight()); } } public class MyTextView extends TextView { public MyTextView(Context context) { super(context); setText("test test "); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); measure(0, 0); // 添加测量方法 // 打印日志:TextView---width: 200,height: 400 Log.i("TAG", "TextView---width: " + getWidth() + ",height: " + getHeight()); // 打印日志:TextViewTest---MeasuredWidth: 164,MeasuredHeight: 57 Log.i("TAG", "TextView---MeasuredWidth: " + getMeasuredWidth() + ",MeasuredHeight: " + getMeasuredHeight()); } } }
注:
getMeasuredWidth()和getMeasuredHeight 的值是在 onMeausre 方法结束后获取到的;
getWidth() 和 getHeight() 的值是在 onLayout 方法结束后可以获取到的。
另外getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,
而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。
视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在XML文件中指定视图的大小,然后视图本身会决定其最终的大小。
点击下载源码
相关文章推荐
- Android自定义控件热身——View的坐标位置和大小详解
- 【转】android:自定义layout动态改变view位置和大小
- android获取自定义控件位置坐标,屏幕尺寸,标题栏,状态栏高度
- android view层次与位置大小
- Android自定义控件----YluoTextView可以改变Drawable大小颜色的TextView
- Android控件架构与自定义控件详解(三)——自定义ViewGroup
- Android动态设置View的位置和大小
- 3.4.Android控件架构与自定义控件详解之ViewGroup的测量与绘制
- android开发步步为营之101:动态调整view的宽度和高度以及在页面的坐标位置
- 3.5.Android控件架构与自定义控件详解之自定义View(二)
- Android 自定义PopupWindow指定位置或给定View坐标弹出
- Android自定义ViewGroup View的大小和坐标控制
- Android动态设置View的位置和大小
- Android控件架构与自定义控件详解(一)——Android控件架构与View的绘制原理
- android控制view的大小和位置(一)
- 【android自定义控件】TextView详解及自定义<一>
- android控制view的大小和位置(一)
- 坐标相关的 android应用程序中获取view的位置
- view坐标_ _ Android应用坐标系统全面详解
- Android控件架构与自定义控件详解(二)——自定义View