android View基本知识

来源:互联网 发布:淘宝九一一正品折扣店 编辑:程序博客网 时间:2024/06/11 21:43

本文参考了博客
https://www.zybuluo.com/TryLoveCatch/note/722664

View 获取坐标方法

  • getTop(): 获取View顶部相对父布局的距离
  • getLeft(): 获取View左侧相对父布局的距离
  • getBottom():获取View底部相对父布局的距离
  • getRight(): 获取View右侧相对父布局的距离
  • getTranslationX(): View相对于X轴的偏移量
  • getTranslationY(): View相对于Y轴的偏移量
  • getX(): View的虚拟x坐标,=getLeft()+getTranslationX()
  • getY(): View的虚拟y坐标,=getTop()+getTranslationY()
  • getScrollX(): View 内容在x轴上的滚动偏移量
  • getScrollY(): View 内容在y轴上的滚动偏移量

MotionEvent 获取坐标方法

  • getX(): 获取触摸点距离当前控件左边的距离
  • getY(): 获取触摸点距离当前控件上边的距离

// todo: 这里画个图,解释各个方法
这里写图片描述

View 的setTranslationX()和setTranslationY()会改变translationX和translationY的值,但不会改变margin的值,所以,getLeft()和getTop()不会改变,setTranslationX(0)会恢复translationX的值。

这里可以得出结论,View的宽高由left, top, right和bottom这几个参数决定,而X, Y, translationX和translationY则影响View的位置,如果想要实现更加平滑的View移动效果,可以使用属性动画,直接修改View的属性值。

measuredWidth和width的区别

一般情况下,我们通过getWidth()方法和getMeasuredWidth()方法得到的View宽度是一样的,但其实,这两个方法从字面意思上理解,再结合源码分析,发现measuredWidth值是在View的measure阶段决定的,由方法setMeasuredWidthDimension()方法赋值,而width是在View的layout阶段,由layout()方法决定的。通常layout()方法在parent中被调用,来确定child views在父容器中的位置,一般在自定义ViewGroup的onLayout()方法中调用。

需要注意的是,通常View的width和height是由View本身和parent容器共同决定的,比如,View通过自身measure()方法向parent的请求100*100的宽高,那么这个宽高就是measuredWidth和measuredHeight的值,但是,在parent的onLayout()方法中,通过调用childView.layout()方法只分配给childView50*50的宽高,那么这个50*50就是childView实际绘制并显示到屏幕的宽高,也就是width和height的值。

举个栗子:

import android.app.Activity;import android.content.Context;import android.graphics.Canvas;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;public class LearnViewWidthActivity  extends Activity{    private LinearLayout mLayout;    private TextView mView;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mLayout = new MyLinearLayout(this);        mLayout.setLayoutParams(new LinearLayout.LayoutParams(                LinearLayout.LayoutParams.MATCH_PARENT,                LinearLayout.LayoutParams.MATCH_PARENT));        mView = new MyTextView(this);        mLayout.addView(mView);        setContentView(mLayout);    }    private class MyLinearLayout extends LinearLayout{        public MyLinearLayout(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 v = getChildAt(0);            v.layout(0,0,50,50);        }    }    private class MyTextView extends android.support.v7.widget.AppCompatTextView{        public MyTextView(Context context) {            super(context);            setText("test");        }        @Override        protected void onDraw(Canvas canvas) {            super.onDraw(canvas);            measure(0,0);            Log.i("===>","width="+getWidth()+",height="+getHeight());            Log.i("===>","measuredWidth="+getMeasuredWidth()+",measuredHeight="+getMeasuredHeight());        }    }}

Log输出:

width=50,height=50measuredWidth=214,measuredHeight=38

正确获取measuredWidth的方法

  • onWindowFocusChanged()
    onWindowFocusChanged()方法表示View已经绘制完了,宽高已经准备好了,此时可以获取View的宽高值了。通过打印Activity的生命周期执行情况发现,这个方法会执行多次,每当Activity onResume()或者onPause()都会执行该方法。
 @Override    public void onWindowFocusChanged(boolean hasFocus) {        super.onWindowFocusChanged(hasFocus);        if (hasFocus){            int width = mView.getMeasuredWidth();            int height = mView.getMeasuredHeight();            Log.i("===>","onWindowFocusChanged, width="+width+",height="+height);        }    }
  • View.post(Runnable)
    我们有时会通过该方法使用主线程刷新UI,刷新UI后当然说明View已经绘制完成,此时获取View的宽高肯定是没有问题的。
mView.post(new Runnable() {            @Override            public void run() {                int width = mView.getMeasuredWidth();                int height = mView.getMeasuredHeight();                Log.i("===>","post, width="+width+",height="+height);            }        });
  • ViewTreeObserver
    这个几乎没用过,纯参考,记录学习一下
    ViewTreeObserver的众多接口和相应回调方法可以完成此功能。如onGlobalLayoutListener接口,官方解释:当View树的layout状态发生改变或者其子View可见性发生改变时,onGlobalLayout()方法会被回调。随着View树的变化,这个方法也会被执行多次。
        ViewTreeObserver viewTreeObserver = mView.getViewTreeObserver();        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                int width = mView.getMeasuredWidth();                int height = mView.getMeasuredHeight();                Log.i("===>","onGlobalLayout, width="+width+",height="+height);            }        });
  • View.measure()
    View的绘制流程:measure->layout->draw。最常见的用法就是measure(0,0),在上面的例子中就是这样用的,这里的0,0表示的意思是View测量中的常量View.MeasureSpec.UNSPECIFIED,View向parent请求的宽高保存在MeasureSpec中,由size和mode组成,其中mode共三个int值,这是源码定义:
/**         * Measure specification mode: The parent has not imposed any constraint         * on the child. It can be whatever size it wants.         */        public static final int UNSPECIFIED = 0 << MODE_SHIFT;        /**         * Measure specification mode: The parent has determined an exact size         * for the child. The child is going to be given those bounds regardless         * of how big it wants to be.         */        public static final int EXACTLY     = 1 << MODE_SHIFT;        /**         * Measure specification mode: The child can be as large as it wants up         * to the specified size.         */        public static final int AT_MOST     = 2 << MODE_SHIFT;

再看size与mode的关系:

public static int getDefaultSize(int size, int measureSpec) {        int result = size;        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        switch (specMode) {        case MeasureSpec.UNSPECIFIED:            result = size;            break;        case MeasureSpec.AT_MOST:        case MeasureSpec.EXACTLY:            result = specSize;            break;        }        return result;    }

所以measure(0,0)返回的就是mMinWidth, 或者mBackground.getMinimumWidth().

0 0
原创粉丝点击