View体系(一):View位置参数

在 Android 整个体系中,View 在其中扮演着不可或缺的角色。

前言

我对 Android 中的 View 理解是:View 在字面上面理解指的是视图,或者更加确切来说,它指的是控件,只不过这个控件的功能比较更广泛,没有像 Button 控件那样细化罢了。我为什么这么理解呢?因为在 View 体系中,例如 ButtonTextView…它们都是继承自 View,如 Android 5.0 源码中的:

public class Button extends TextView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

在 Android 中,除了 View,还有 ViewGroup,ViewGroup 在字面上面的理解是:它指的是控件组。基于上面的 View 的解析,ViewGroup 便很好理解:ViewGroup 是多个控件的集合。也就是说,ViewGroup 它可以包含多个 View 控件,也是就可以解析下面的控件为什么可以包含多个子 View 了:

public class LinearLayout extends ViewGroup
public class RelativeLayout extends ViewGroup
public class FrameLayout extends ViewGroup

当然,ViewGroup 也是继承自 View:

public abstract class ViewGroup extends View implements ViewParent, ViewManager
1.0 View 的位置参数

在准备深入理解 View 体系的时候,需了理解 View 的一些细节,如 xytranslationXtranslationY等。在理解 View 的位置参数的时候,我们需要先弄清楚 View 中的 leftrighttopbottom 所代表的含义是什么:

/**
    * The distance in pixels from the left edge of this view's parent
    * to the left edge of this view.
    * 翻译:mLeft 值的大小是指从 View 的父容器的左边缘到该 View 的左边缘的距离,该值的单位为像素。
    */
protected int mLeft;
/**
    * The distance in pixels from the left edge of this view's parent
    * to the right edge of this view.
    * 翻译:mRight 值的大小是指从 View 的父容器的左边缘到该 View 的右边缘的距离,该值的单位为像素。
    */
protected int mRight;
/**
    * The distance in pixels from the top edge of this view's parent
    * to the top edge of this view.
    * 翻译:mTop 值的大小是指从 View 的父容器的上边缘到该 View 的上边缘的距离,该值的单位为像素。
    */
protected int mTop;
/**
    * The distance in pixels from the top edge of this view's parent
    * to the bottom edge of this view.
    * 翻译:mTop 值的大小是指从 View 的父容器的上边缘到该 View 的下边缘的距离,该值的单位为像素。
    */
protected int mBottom;

则上面四个 leftrighttopbottom 值通过上面的字面的理解,则可以通过作图表示为:

Android 坐标系

在 View 的源码中,存在着 leftrighttopbottom 的获取接口,如下 Android 5.0 源码中:

...
/**
    * Top position of this view relative to its parent.
    *
    * @return The top of this view, in pixels.
    */
public final int getTop() {
    return mTop;
}

...

/**
    * Bottom position of this view relative to its parent.
    *
    * @return The bottom of this view, in pixels.
    */
public final int getBottom() {
    return mBottom;
}

...

 /**
    * Left position of this view relative to its parent.
    *
    * @return The left edge of this view, in pixels.
    */
public final int getLeft() {
    return mLeft;
}

...

/**
    * Right position of this view relative to its parent.
    *
    * @return The right edge of this view, in pixels.
    */
public final int getRight() {
    return mRight;
}

...

在 Android 的窗口中,存在着一个直角坐标系。这个直角坐标系可以这么理解的,以手机的左上角为原点,左上角水平向右为 X 轴,从左往右为正方向;左上角垂直向下为 Y 轴,从上到下为正方向,如上图的坐标系所示。一般地,这个坐标系是贯穿于 View 体系的,我们 Android 开发者应该熟知的。

弄清楚 leftrighttopbottom 四个值的意义,那么 XY 值的含义相对简单很多,如下源码:

/**
* The visual x position of this view, in pixels. This is equivalent to the
* {@link #setTranslationX(float) translationX} property plus the current
* {@link #getLeft() left} property.
*
* @return The visual x position of this view, in pixels.
*/
public float getX() {
    return mLeft + getTranslationX();
}

方法 getX() 返回的是一个单精度浮点型的值,又上面的源码可知,X 的值是 mLeft + getTranslationX() 的和,mLeft 的值是该 View 的左边缘距父 View 的左边缘的大小,而 getTranslationX() 又源码可知,

/**
    * The horizontal location of this view relative to its {@link #getLeft() left} position.
    * This position is post-layout, in addition to wherever the object's
    * layout placed it.
    *
    * @return The horizontal position of this view relative to its left position, in pixels.
    */
public float getTranslationX() {
    return mRenderNode.getTranslationX();
}

getTranslationX()的方法中,它是通过 mRenderNode.getTranslationX() 进一步的调用,返回对应的 View 的 translationX 值。在 View 中,translationX 值指的是该 View 据其自身的在 X 轴上的偏移量,默认值为 0px; 同理地,translationY 值指的是该 View 据其自身的在 Y 轴上的偏移量,默认值为 0px。通过做图更加清楚表示为:

现在理解了 translationX,而 translationY 也是同样的原理可得,于是有源码可知,mLeft + getTranslationX() 相加的值为 X ,而 Y 则是 mTop + getTranslationY(),于是 (X,Y) 便可以看作是 VIew 的左上角的原点,并且这个 (X,Y) 是随着 View 的移动而相对变化的。

理解了 leftrighttopbottom 这四个参数的由来,对于 View 的 WidthHeight 也是比较容易理解的了:

width = mRight - mLeft;
height = mBottom - mTop;

实质上,对于 View 的 WidthHeight 在上面的解析,在 Android 5.0 的源码中也是如此的。并且 View 还提供了获取 WidthHeight 的接口: getWidth()getHeight()

有些时候,在自定义 View 的过程中,往往会遇到 rawXrawY 这两个参数,如下面 kotlin 源码:

class CustomSlidView: View {

    private var mLastX = 0f
    private var mLastY = 0f

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)


    override fun onTouchEvent(event: MotionEvent?): Boolean {

        val rawX = event!!.rawX
        val rawY = event!!.rawY

        when(event!!.action){
            MotionEvent.ACTION_MOVE -> {

                val deltaX = rawX - mLastX
                val deltaY = rawY - mLastY

                translationX += deltaX
                translationY += deltaY
            }
        }

        mLastX = rawX
        mLastY = rawY

        return true
    }
}

这个 CustomSlidView 实现的是一个可以自由拖动的 View,里面的 (rawX,rawY) 是指手指按下屏幕时的坐标点,这个坐标点是相对于 ``DecorView而言的。(值得注意的是,leftrighttopbottom这四个值是相对于该 View 的父 View 的,而(X,Y)` 是相对与自身的)

2.0 小总结

这一篇文章主要介绍了 View 的几个重要的位置参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值