Android开发艺术探索学习-View的基本知识

  1. What is view?
    View代表用户界面最基本组成部分。一个View在屏幕上占据一个矩形区域并负责绘图和相应地事件处理。View是所有控件的基类,View的子类被用于交互UI的组件。View有个很重要的子类ViewGroup,它是用于布局的基类。ViewGroup是一个不可见的容器,里面有其他的View或者ViewGroup并且定义它们的布局属性。View和ViewGroup采用了典型的组合模式思想,若有兴趣大家可以去了解下组合模式。
  1. View的位置参数
    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的高宽和坐标的关系。
    /**
     * Return the width of the 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;
    }
Android3.0开始,View增加了几个额外的参数:x、y、translationX、translationY,其中x、y是View左上角的坐标,而translationX、translationY是分别相对于getLeft()、getTop()位置。
    /**
     * 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();
    }
View的坐标x、y的计算公式如下。
    /**
     * 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();
    }
通过下图我们来解释下这个translationX、translationY到底怎么回事。

假如View通过动画平移到View’的位置,那么这时候View平移的位置就是translationX、translationY。因为View的横向是右移,因此translationX的值为正,而View的纵向是上移,因此translationY的值为负。
  1. MotionEvent
    MotionEvent是用来报告运动事件 鼠标, 笔, 手指, 轨迹球。在MotionEvent中提供了很多触摸事件,典型的触摸事件类型如下几种:
    /**
     * Constant for {@link #getActionMasked}: A pressed gesture has started, the
     * motion contains the initial starting location.
     * <p>
     * This is also a good time to check the button state to distinguish
     * secondary and tertiary button clicks and handle them appropriately.
     * Use {@link #getButtonState} to retrieve the button state.
     * </p>
     */
    public static final int ACTION_DOWN             = 0;
    
    /**
     * Constant for {@link #getActionMasked}: A pressed gesture has finished, the
     * motion contains the final release location as well as any intermediate
     * points since the last down or move event.
     */
    public static final int ACTION_UP               = 1;
    
    /**
     * Constant for {@link #getActionMasked}: A change has happened during a
     * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
     * The motion contains the most recent point, as well as any intermediate
     * points since the last down or move event.
     */
    public static final int ACTION_MOVE             = 2;
    一个典型的触摸事件会经历,DOWN->MOVE->UP。通过MotionEvent我们可以得到相应触摸事件发生的坐标x、y。为此,系统提供了两组方法获取事件坐标。
    /**
     * {@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);
    }

    /**
     * {@link #getY(int)} for the first pointer index (may be an
     * arbitrary pointer identifier).
     *
     * @see #AXIS_Y
     */
    public final float getY() {
        return nativeGetAxisValue(mNativePtr, AXIS_Y, 0, HISTORY_CURRENT);
    }
    /**
     * 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);
    }

    /**
     * Returns the original raw Y 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 #getY(int)
     * @see #AXIS_Y
     */
    public final float getRawY() {
        return nativeGetRawAxisValue(mNativePtr, AXIS_Y, 0, HISTORY_CURRENT);
    }
这两组方法是有区别的,getX/getY返回的是相对于当前View左上角的x和y坐标,而getRawX/getRawY返回的是相对于手机屏幕左上角的x和y坐标。
  1. TouchSlop
TouchSlop是系统所能识别出的被认为是滑动的最小距离,如果手指在屏幕滑动时,如果两次滑动之间的距离小于这个常量,那么系统就认为你不是在进行滑动操作。TouchSlop在不同的设备中,其值可能不同。我们可以通过ViewConfiguration的getScaledTouchSlop()获取TouchSlop的值。
    /**
     * @return Distance in pixels a touch can wander before we think the user is scrolling
     */
    public int getScaledTouchSlop() {
        return mTouchSlop;
    }
mTouchSlop的值是配置在config.xml中。
    <!-- Base "touch slop" value used by ViewConfiguration as a
         movement threshold where scrolling should begin. -->
    <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
  1. VelocityTracker
    VelocityTracker用于跟踪手指滑动过程中的速度,包括水平和竖直方向的速度。当你想要开始追踪滑动速度时,可以通过obtain()方法获取VelocityTracker类的实例。
    /**
     * Retrieve a new VelocityTracker object to watch the velocity of a
     * motion.  Be sure to call {@link #recycle} when done.  You should
     * generally only maintain an active object while tracking a movement,
     * so that the VelocityTracker can be re-used elsewhere.
     *
     * @return Returns a new VelocityTracker.
     */
    static public VelocityTracker obtain() {
        VelocityTracker instance = sPool.acquire();
        return (instance != null) ? instance : new VelocityTracker(null);
    }
然后通过addMovement(MotionEvent)将你接收到的MotionEvent添加到VelocityTracker类中。
    /**
     * Add a user's movement to the tracker.  You should call this for the
     * initial {@link MotionEvent#ACTION_DOWN}, the following
     * {@link MotionEvent#ACTION_MOVE} events that you receive, and the
     * final {@link MotionEvent#ACTION_UP}.  You can, however, call this
     * for whichever events you desire.
     * 
     * @param event The MotionEvent you received and would like to track.
     */
    public void addMovement(MotionEvent event) {
        if (event == null) {
            throw new IllegalArgumentException("event must not be null");
        }
        nativeAddMovement(mPtr, event);
    }
如果我们想要计算当前滑动速度时,首先调用computeCurrentVelocity(int),接着调用getXVelocity()和getYVelocity()。这里需要注意,速度有正负值的。
    /**
     * Compute the current velocity based on the points that have been
     * collected.  Only call this when you actually want to retrieve velocity
     * information, as it is relatively expensive.  You can then retrieve
     * the velocity with {@link #getXVelocity()} and
     * {@link #getYVelocity()}.
     * 
     * @param units The units you would like the velocity in.  A value of 1
     * provides pixels per millisecond, 1000 provides pixels per second, etc.
     * @param maxVelocity The maximum velocity that can be computed by this method.
     * This value must be declared in the same unit as the units parameter. This value
     * must be positive.
     */
    public void computeCurrentVelocity(int units, float maxVelocity) {
        nativeComputeCurrentVelocity(mPtr, units, maxVelocity);
    }
这里有一个入参需要解释下,int值表示单位,1表示一毫秒每像素,传1000的话代表的是1秒每像素,依次类推。

最后很重要的一点,当你不需要VelocityTracker实例时,需要按顺序调用其clear()和recycle()方法,一般是在ACTION_DOWN和ACTION_CANCEL中使用。
    /**
     * Reset the velocity tracker back to its initial state.
     */
    public void clear() {
        nativeClear(mPtr);
    }
clear()方法是用来恢复VelocityTracker的初始状态。
    /**
     * Return a VelocityTracker object back to be re-used by others.  You must
     * not touch the object after calling this function.
     */
    public void recycle() {
        if (mStrategy == null) {
            clear();
            sPool.release(this);
        }
    }
回收VelocityTracker实例,方便重新使用。

View是UI的核心内容,我们也经常需要写一些自定义View,因此我觉得很有必要更深一层了解View的工作原理,多接触一些View相关的API,这些对我们日后开发是有很帮助的!














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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值