美文网首页
第五章:Android Scroll 分析

第五章:Android Scroll 分析

作者: 夜瑾漠 | 来源:发表于2018-08-16 21:43 被阅读0次

    《Android1群英传》——个人读书笔记

    5.1 滑动效果是如何产生的

    • 要实现View的滑动,就必须监听的触摸事件,并根据事件传入的坐标,动态且不断的改变坐标,从而实现View跟随用户触摸的滑动而滑动

    5.1.1 Android 坐标系

    • 坐标系原点:屏幕最左上角的顶点
    • 获取坐标系中点坐标: getLocationOnScreen(intlocation[])
    • 获取X轴坐标: getRowX()
    • 获取Y轴坐标: getRowY()

    5.1.2 视图坐标系

    • 原点:父视图左上角为坐标原点
    • 它描述了子视图在父视图中的位置
    • 两种坐标系相辅相成,并不冲突
    • 视图坐标系的获取:getX()getY()

    5.1.3 触控事件——MotionEvent

    • 1)MotionEvent中封装的一些常用的事件常量:
    // 单点触摸按下动作
    public static final int ACTION_DOWN = 0;
    // 单点触摸离开动作
    public static final int ACTION_UP = 1;
    // 单点触摸移动动作
    public static final int ACTION_MOVE = 2;
    // 触摸动作取消
    public static final int ACTION_CANCEL = 3;
    // 触摸动作超出边界
    public static final int ACTION_OUTSIDE = 4;
    // 多点触摸按下动作
    public static final int ACTION_POINTER_DOWN = 5;
    // 多点触摸离开动作
    public static final int ACTION_POINTER_UP = 6;
    
    • 2)View提供的获取坐标的方法:
    • getTop(): 获取到的是View 自身的顶边 到其 父布局顶边 的距离
    • getLeft(): <font color=#ED1A3D>左边————>左边</font>
    • getRight(): 右边————>左边
    • getBottom(): <font color=#ED1A3D>底边————>顶边</font>

    补充:
    这边需要注意:这四个方法是相互对相应的,一组是到父控件左边的距离(getLeft()、getRight()),一组是到父控件顶部的距离(getTop()、getBottom()),每一组的对应点是相同的。

    • 根据上图我们可获取View的大小:
    • View的Height值 = view.getBottom() - view.getTop();
      View的Width值 = view.getRight() - view.getLeft();
    • 3)MotionEvent提供的方法:
    • getX(): 获取点击事件距离控件左边的距离,即视图坐标
    • getY(): 顶边
    • getRawX(): 获取点击事件距离整个屏幕左边的距离,即绝对坐标
    • getRawY(): 顶边

    5.2 实现滑动的其中方法

    5.2.1 Layout方法

    5.2.2 offsetLeftAndRight() 与 offsetTopAndBottom()

    • 这两个方法相当于系统提供的一个对左右、上下移动的API的封装。当计算出偏移量之后,只需要使用如下代码就可以完成View的重新布局,效果与使用Layout方法一样。
    //同时对left和right进行偏移
    offsetLeftAndRight(offsetX);
    //同时对top和bottom进行偏移
    offsetTopAndBottom(offsetY)
    

    5.2.3 LayoutParams

    5.2.4 scrollTo 与 scrollBy

    • 改变View的位置
    • scrollTo(x,y) 表示移动到一个具体的坐标点(x,y)
    • scrollBy(dx,dy) 表示移动的增量为dx,dy
    • 获取偏移量后,使用 scrollBy 来移动View
    int offsetX = x - lastX;
    int offsetY = y = lastY;
    scrollBy(offsetX,offsetY);
    
    • 注意:scrollTo 与 scrollBy 移动的是View的content,即移动的是view的内容。当然如果是在ViewGroup中使用这两个方法,那么移动的将是所有的子View
    int offsetX = x - lastX;
    int offsetY = y = lastY;
    ((View)getParent()).scrollBy(offsetX, offsetY)
    
    • 按照上述方法进行设置,视图不会跟随手指的移动而移动,而是反方向的移动。要想跟随手指移动需要将偏移量设置为负数
    ((View)getParent()).scrollBy(-offsetX, -offsetY)
    

    5.2.5 Scroller类

    • Scroller类可以实现平滑移动的效果,而非瞬间完成的移动
    • 使用Scroll类的步骤:
    • 1)初始化Scroller
    //初始化Scroller
    mScroller = new Scroller(context);
    
    • 2)重写computeScroll()方法,实现模拟滑动
              它是使用Scroller类的核心,系统会在绘制View的时候在draw()方法中调用这个方法。
    @Override
    public void commputeScroll()
    {
        super.commputeScroll();
        //判断 Scroll 是否执行完毕
        if(mScroller.commputeScrollOffset())
        {
            ((View)getParent()).scrollTo(
                mScroller.getCurrX(),
                mScroller.getCurrY());
            //通过重绘来不断调用 commputeScroll
            invalidate();
        }
    }
    
    • Scroller类提供了 commputeScrollOffset() 方法来判断是否完成了整个滑动,同时也提供了 getCurrXgetCurrY 来获得当前的滑动坐标。
    • 注意: invalidate()方法只能在 computeScroll() 方法中获取模拟过程中的 scrollX 和 scrollY 坐标。但是 computeScroll() 是不会自动调用的,只能通过 invalidate()——>draw()——>computeScroll() 来间接调用 computeScroll() 方法,所以需要在模板代码中调用 invalidate() 方法,实现循环获取 scrollX 和 scrollY 的目的。而当模拟过程结束后,scroller.commputeScrollOffset() 方法会返回 false ,从而中断循环,完成整个平滑移动过程。
    • 3)startScroll 开启模拟过程
    • 调用 Scroller 类中的starScroll()方法来开启平滑移动过程
    • startScroll() 方法具有两个重载方法:
              public void startScroll(int startX, int startY, int dx, int dy, int duration)
              public void startScroll(int startX, int startY, int dx, int dy)

    5.2.6 属性动画

    • 与第七章重复,这里不做介绍

    5.2.7 ViewDragHelper

    • Google在support库中提供了 DrawLayoutSlidingPaneLayout 用于实现侧边栏滑动效果
    • 实现方式:
    • 1)初始化ViewDragHelper
    private void initView()
    {
       mViewDragHelper = ViewDragHelper.create(this, callback);
    }
    
    • 传入的两个参数:第一个是要监听的View,通常是ViewGroup,即ParentView;第二个是CallBack回调, 这个回调就是整个ViewDragHelper 的逻辑核心。
    • 2)拦截事件
    • 重写事件拦截方法,将事件传递给ViewDragHelper进行处理
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
            return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
            //将触摸事件传递给ViewDragHelper,此操作必不可少
            mViewDragHelper.processTouchEvent(event);
            return true;
    }
    
    • 3)处理computeScroll()
    • ViewDragHelper 的内部也是通过Scroller来实现滑动的。
    @Override
    public void computeScroll() {
            if (mViewDragHelper.continueSettling(true)) {
                ViewCompat.postInvalidateOnAnimation(this);
            }
    }
    
    • IDE 自动重写的 tryCaptureView() ,可以指定在创建ViewDragHelper时,参数ParentView中的哪个子View可以被移动。
    // 何时开始检测触摸事件
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
    //如果当前触摸的child是mMainView时开始检测
        return mMainView == child;
    }
    
    • 以上代码就是指定了 MainView 是可以被移动的
    • 具体实现滑动的方法 :
    // 处理垂直滑动
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
         return top;
    }
    
    // 处理水平滑动
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        return left;
    }
    
    • 重写 onViewReleased() 方法,可以非常简单的实现当是指离开屏幕后实现的操作,其内部也是通过 Scroller 类实现的
                    // 拖动结束后调用
                    @Override
                    public void onViewReleased(View releasedChild, float xvel, float yvel) {
                        super.onViewReleased(releasedChild, xvel, yvel);
                        //手指抬起后缓慢移动到指定位置
                        if (mMainView.getLeft() < 500) {
                            //关闭菜单
                            //相当于Scroller的startScroll方法
                            mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                            ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                        } else {
                            //打开菜单
                            mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                            ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                        }
                    }
    
    • 系统定义了大量监听事件来帮助我们处理各种事情:
              1)onViewCaptured(): 这个事件在用户触摸到View之后回调;
              2)onViewDragStateChanged(): 这个事件在拖拽状态改变时回调
              3)onViewPositionChanged(): 这个事件在位置改变时回调,常用于滑动时更改scale进行缩放等效果。
      r

    相关文章

      网友评论

          本文标题:第五章:Android Scroll 分析

          本文链接:https://www.haomeiwen.com/subject/inhubftx.html