Android学习笔记(三)View基础

参考书籍:《Android开发艺术探索》 任玉刚
如有错漏,请批评指出!

View基础知识

View类
 View类是Android中所有控件的基类,包括ViewGroup(控件组);这也就意味着,View本身可以是单个控件,也可以是包含多个控件的一组控件。

11076001-af62ae528bdd6974.png

View的位置参数
 View的位置主要由四个顶点决定,分别对应于四个属性:top、left、right、bottom。从Android3.0开始,增加了几个额外参数:x、y、translationx、translationY。这些参数都是相对于父容器的。

11076001-23d9d722fcd709b1.png

x:View发生平移后的左上角横坐标
y:View发生平移后的左上角纵坐标
translationX:View的横向偏移量(初始为0)
translationY:View的纵向偏移量(初始为0)

MotionEvent
 手指触摸屏幕后的典型事件类型有:

  • ACTION_DOWN——手指接触屏幕瞬间;
  • ACTION_MOVE——手指在屏幕上滑动;
  • ACTION_UP——手指离开屏幕瞬间;

通过MotionEvent对象可以得到点击事件发生的x、y坐标:

  • getX()——获取触摸点相对于当前View左上角的横坐标;
  • getY()——获取触摸点相对于当前View左上角的纵坐标;
  • getRawX()——获取触摸点相对于手机屏幕左上角的横坐标;
  • getRawY()——获取触摸点相对于手机屏幕左上角的纵坐标;

TouchSlop
 TouchSlop是系统所能识别出的被认为是滑动的最小距离。

  1. 这是一个常量,和设备有关,在不同设备上这个值可能不同;
  2. 当手指在屏幕上滑动的距离小于这个值,系统就不会认为这是滑动操作;
  3. 获取方法:
ViewConfiguration.get(getContext()).getScaledTouchSlop();

  这个常量的意义在于,当我们做滑动处理的时候,可以用它来做一些过滤。这样可以改善用户的使用体验。

VelocityTracker
 速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。下面是使用示例:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //创建VelocityTracker对象,并将触摸界面的滑动事件
        //加入到VelocityTracker当中。
        VelocityTracker velocityTracker = VelocityTracker.obtain();
        velocityTracker.addMovement(event);
        //指定时间间隔为1s,计算速度
        velocityTracker.computeCurrentVelocity(1000);
        //获取水平速度和竖直速度(像素/s) 
        int xVelocity = (int)velocityTracker.getXVelocity();
        int yVelocity = (int)velocityTracker.getYVelocity();
        //销毁对象,回收内存
        velocityTracker.clear();
        velocityTracker.recycle();
        return super.onTouchEvent(event);
    }

速度 = (终点位置 - 起点位置)/时间段(可以为负值)

GestureDetector
 手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。下面是使用示例:

public class MainActivity extends AppCompatActivity implements
        GestureDetector.OnGestureListener,GestureDetector.OnDoubleTapListener{
    GestureDetector mGestureDetector;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //首先,创建GestureDetector对象并根据需求实现OnGestureListener接口
        //和OnDoubleTapListener接口
        mGestureDetector = new GestureDetector(this,this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将目标View中的触摸事件交给GestureDetector处理(这里是MainActivity中的触摸事件)
        return mGestureDetector.onTouchEvent(event);
    }
}

 做完上面的事情之后,即可以选择性的实现OnGestureListener和OnDoubleTapListener中的方法了,这两个接口中的常用方法如下:

方法名 描述 所属接口
onDown 手指轻轻触摸屏幕瞬间,由一个ACTION_DOWN触发 OnGestureListener
onSingleTapUp 手指(轻轻触摸屏幕后)松开,伴随一个ACTION_UP而触发,表示单击行为 OnGestureListener
onScroll 手指按下屏幕并拖动,由一个ACTION_DOWN,多个ACTION_MOVE触发,表示拖动行为 OnGestureListener
onFling 用户按下触摸屏,快速滑动后松开,由一个ACTION_DOWN、多个ACTION_MOVE和一个ACTION_UP触发,表示快速滑动行为 OnGestureListener
onLoongPress 用户长久的按住屏幕不放,表示长按行为 OnGestureListener
onDoubleTap 双击,由连续2次单击组成 OnDoubleTapListener

 说明:

  1. 在实际开发中,可以不使用GestureDetector,完全可以自己在View中onTouchEvent方法中实现所需的监听。
  2. 建议:如果只是监听滑动相关,就在onTouchEvent中实现;如果要监听双击这种行为,就使用GestureDetector。

View的滑动

滑动在Android开发中具有很重要的作用,很多绚丽的滑动效果其实都是由基本的滑动操作和特效组成。书中讲了三种实现View滑动的方式:第一种是使用scrollTo / scrollBy 方法;第二种是通过动画给View施加平移效果来实现滑动;第三种是通过改变View的LayoutParams使得View重新布局从而实现滑动。这里我还要补充一种,使用 layout 方法改变View的位置参数从而实现滑动。

  1. 使用 scrollto / scrollBy 方法
    先来看看这两个方法的源码:

    /**
     * Set the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the x position to scroll to
     * @param y the y position to scroll to
     */
    public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }
    
    /**
     * Move the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the amount of pixels to scroll by horizontally
     * @param y the amount of pixels to scroll by vertically
     */
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }
    

    首先我们先了解源码中的 mScrollX 和 mScrollY 这两个值是什么:
    mScrollX 是View左边缘和View内容左边缘在水平方向上的距离
    mScrollY 是View上边缘和View内容上边缘在竖直方向上的距离

    从mScrollX 和 mScrollY的描述来看,这两个方法只能改变View内容的位置,并不能改变View的位置,也就是说,调用View的 scrollTo()和scroollBy() 方法不会改变View的位置参数(left、top、right、buttom、x、y、translationX、translationY),如果当前View还有子View时,子View也仅仅是内容发生平移,自身的位置参数不变。关于什么是View以及它的内容可以看下图:
    11076001-5256228297a793ff.png

    说明:mScrollX 和 mScrollY的单位为像素,当View左边缘在View内容右边时,mScrollX 为正值,反之为负值;当View上边缘在View内容下面时,mScrollY为正值,反之为负值。具体来说,当我们想要让View内容右移或下移时,我们传入scrollBy()或scrollTo()方法的参数应该为负值。

    从源码来看,scrollBy() 方法实际上也是调用了scrollTo() 方法,因此,这两个方法都是改变 mScrollX 和 mScrollY 的值,不过scrollTo(int x, int y)方法是直接将传入的参数赋值给mScrollX 和 mScrollY,即将View的内容移动到指定的坐标位置;而scrollBy(int x, int y)方法则是将View的内容从当前位置向上或下平移x个像素,向左或右平移y个像素。下面看看实现过程和效果:

    <LinearLayout
        android:id="@+id/ll_left"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <View
            android:id="@+id/view_left"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/colorRed"/>
    
    </LinearLayout>
    
    public void move(View v) {
        switch (v.getId()){
            case R.id.but_show:
                ll_left.scrollBy(-100,-100);
                break;
            case R.id.but_hide:
                ll_left.scrollBy(100,100);
                break;
            default:
                break;
        }
    }
    

    效果图如下:
    11076001-605fc1c84511dfe6.gif
  2. 使用动画实现
    关于动画的内容后面有单独的章节讲解,这里先略过。

  3. 改变布局参数
    改变布局参数,也就是改变LayoutParams。比如我们想把一个Buttom向右平移100px,我们只需要将这个Buttom的Layoutparams里的marginLeft参数的值增加100px即可。当然,这只是为了达到让View平移目的的一种实现方式,类似的还可以在这个Buttom左边放一个width为0的空View,当我们需要平移时,就改变空View的width,从而将Button挤到右边。具体如何实现呢?

    MarginLayoutParams params = (MarginLayoutParams)view_left.getLayoutParams();
    //改变View的width
    params.width += 100;
    //改变View的 MarginLeft
    params.leftMargin += 100;
    view_left.setLayoutParams(params);
    

    看看效果:
    11076001-31c066b67d2b47ef.gif
  4. 使用 layout(int l, int t, int r, int b) 方法实现
    这种方法和第一种方式相比,它是实实在在改变了View的left、top、right、buttom这几个位置参数的。我们直接来看代码:

    @OnClick({R.id.but_show, R.id.but_hide})
    public void move(View v) {
        int mLeft, mRight, mTop, mButtom;
        switch (v.getId()){
            case R.id.but_show:
                mLeft = view_left.getLeft() + 100;
                mTop = view_left.getTop() + 100;
                mRight = view_left.getRight() + 100;
                mButtom = view_left.getBottom() + 100;
                view_left.layout(mLeft, mTop, mRight, mButtom);
                break;
            case R.id.but_hide:
                mLeft = view_left.getLeft() - 100;
                mTop = view_left.getTop() - 100;
                mRight = view_left.getRight() - 100;
                mButtom = view_left.getBottom() - 100;
                view_left.layout(mLeft, mTop, mRight, mButtom);
                break;
            default:
                break;
        }
    }
    

    效果和第一种看起来相同,只不过第一种是View的内容发生平移,这里是View自身发生平移。

滑动方式对比

  1. ScrollTo / ScrollBy:这两个方法是View提供的原生方法,它改变的是View内容的位置,不会改变View自身的位置参数,因此,不会影响View以及其内部控件的点击事件位置。
  2. 动画:使用动画可以实现很多炫酷的动画效果,但是它不适用于有交互的View。
  3. 改变布局参数:这种方式操作略微复杂,比较适合有交互的View。
  4. layout:这种方式实际上通过改变位置参数,重绘View,会改变View的位置参数。

上一篇:Android学习笔记(二) | Activity的启动模式
下一篇:Android学习笔记(四)| Android 控件架构与自定义控件

猜你喜欢

转载自blog.csdn.net/weixin_33994444/article/details/86784051
今日推荐