View的简介
View是所有控件的基础,熟悉和了解对于每个Android开发者来说必不可少,接下来我们就针对于Android的View从源码角度上进行深入的学习。
1.View的坐标
我们知道,获取一个View 左上和右下的两个坐标的四个值,分别对应以下四个函数:
/**
* Top position of this view relative to its parent.
*
* @return The top of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
public final int getTop() {
return mTop;
}
/**
* Bottom position of this view relative to its parent.
*
* @return The bottom of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
public final int getBottom() {
return mBottom;
}
/**
* Left position of this view relative to its parent.
*
* @return The left edge of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
public final int getLeft() {
return mLeft;
}
/**
* Right position of this view relative to its parent.
*
* @return The right edge of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
public final int getRight() {
return mRight;
}
以上四个函数获取到的就是 mTop,mBottom,mLeft,mRight View的四个位置属性。
/**
* The distance in pixels from the left edge of this view's parent
* to the left edge of this view.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
protected int mLeft;
/**
* The distance in pixels from the left edge of this view's parent
* to the right edge of this view.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
protected int mRight;
/**
* The distance in pixels from the top edge of this view's parent
* to the top edge of this view.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
protected int mTop;
/**
* The distance in pixels from the top edge of this view's parent
* to the bottom edge of this view.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
protected int mBottom;
结论
通过注释上面介绍的很清楚,我们获取到的值都是基于当前View的父布局而言。这点要特别注意。
通过以上图示,我们可以很容易得到布局的宽高和这四个参数之间的关系
width = mRight - mLeft
height = mBottom - mTop
/**
* Return the width of your view.
*
* @return The width of your view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "layout")
public final int getWidth() {
return mRight - mLeft;
}
/**
* Return the height of your view.
*
* @return The height of your view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "layout")
public final int getHeight() {
return mBottom - mTop;
2.getX与getY和getleft,getBottom区别?
我们先来看下getX与getY的源码
/**
* 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.
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
return mLeft + getTranslationX();
}
/**
* The visual y position of this view, in pixels. This is equivalent to the
* {@link #setTranslationY(float) translationY} property plus the current
* {@link #getTop() top} property.
*
* @return The visual y position of this view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getY() {
return mTop + getTranslationY();
}
getX上面注释写到:此视图的可视x位置,单位为像素。它等价于translationX+当前getLeft()的属性。
结论
1.getX获取到是View在X轴上移动以后相对于父布局的值。如果view并未进行平移操作,该值与getleft一致,getY同理**
3.getTranslationX()与getTranslationY()
我们再来看一看这两个方法的源码
/**
* 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.
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationX() {
return mRenderNode.getTranslationX();
}
/**
* The vertical location of this view relative to its {@link #getTop() top} position.
* This position is post-layout, in addition to wherever the object's
* layout placed it.
*
* @return The vertical position of this view relative to its top position,
* in pixels.
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationY() {
return mRenderNode.getTranslationY();
}
结论
通过注释了解到getTranslationX() getTranslationY() 得到是新位置与最初位置的差值,也即移动了多少距离。
4.RenderNode是什么?
有同学注意到了,getTranslationX()获取view的偏移量是通过RenderNode这个类去实现的,RenderNode是个什么呢?我们看下RenderNode的源码
我们先看一下RenderNode是在哪和View联系起来的
RenderNode与View建立关联
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO;
// Set some flags defaults
mPrivateFlags2 =
(LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
(TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) |
(PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) |
(TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) |
(PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) |
(IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
mRenderNode = RenderNode.create(getClass().getName(), this);
RenderNode初始化方法
/**
* Creates a new RenderNode that can be used to record batches of
* drawing operations, and store / apply render properties when drawn.
*
* @param name The name of the RenderNode, used for debugging purpose. May be null.
*
* @return A new RenderNode.
*/
public static RenderNode create(String name, @Nullable View owningView) {
return new RenderNode(name, owningView);
}
RenderNode获取偏移量的方法
/**
* Returns the translation value for this display list on the X axis, in pixels.
*
* @see #setTranslationX(float)
*/
public float getTranslationX() {
return nGetTranslationX(mNativeRenderNode);
}
/**
* Sets the translation value for the display list on the Y axis.
*
* @param translationY The Y axis translation value of the display list, in pixels
*
* @see View#setTranslationY(float)
* @see #getTranslationY()
*/
public boolean setTranslationY(float translationY) {
return nSetTranslationY(mNativeRenderNode, translationY);
}
//除了获取xy偏移量还有一大堆其他属性,例如,缩放,旋转,等偏移量参数
@CriticalNative
private static native float nGetTranslationX(long renderNode);
@CriticalNative
private static native float nGetTranslationY(long renderNode);
@CriticalNative
private static native float nGetTranslationZ(long renderNode);
@CriticalNative
private static native float nGetRotation(long renderNode);
@CriticalNative
private static native float nGetRotationX(long renderNode);
@CriticalNative
private static native float nGetRotationY(long renderNode);
@CriticalNative
private static native boolean nIsPivotExplicitlySet(long renderNode);
@CriticalNative
private static native float nGetPivotX(long renderNode);
@CriticalNative
private static native float nGetPivotY(long renderNode);
。。。。。。。
结论
(1).通过代码我们看到,RenderNode是view在构造函数中与View关联起来的。
(2).RenderNode作用是用于记录View的批次绘制操作,并在绘制时存储/应用渲染属性。
(3).RenderNode记录获取绘制相关是通过调用底层C处理的。
5.MotionEvent 中的 getX,getY,getRawX,getRawY?
手指接触屏幕后发生的一系列事件中,通过MotionEvent类我们可以使用getX,getY,和getRawX,getRawY,这个获取到的坐标有什么区别呢?
我们先看下getRawX
/**
* Returns the original raw X coordinate of this event. For touch
* events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
* and views.
*
* @see #getX(int)
* @see #AXIS_X
*/
public final float getRawX() {
return nativeGetRawAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
}
注释介绍很清楚,rawX返回的是点击屏幕,相对于屏幕的的绝对坐标
/**
* {@link #getX(int)} for the first pointer index (may be an
* arbitrary pointer identifier).
*
* @see #AXIS_X
*/
public final float getX() {
return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
}
nativeGetAxisValue是一个调用C层代码的函数,传入三个参数:mNativePtr MotionEvent的指针,AXIS_X,轴常数运动事件的X轴
。由于C层的代码我们不清楚文档上也没有具体说明,但是我们可以通过代码试验的方式去验证一下。这里就不在具体写了,最终的结果就是getX()返回的是相对于当前view父布局的坐标,getY同理。