手记

3D旋转动画代码解析


1初始化的时候Scroller来来测量滚动,使用滚动更加圆滑

private void init() {

        mCamera = new Camera();

        mMatrix = new Matrix();


        if (mScroller == null){

            mScroller = new Scroller(getContext(),new 


LinearInterpolator());

        }

    }

2生成一些布局参数:


    @Override

    protected LayoutParams generateDefaultLayoutParams() {

        return new MarginLayoutParams


(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);


    }

3(1)测量布局:目的给每一个子view布局

  int measureWidth = MeasureSpec.getSize(widthMeasureSpec);

        int measureHeight = MeasureSpec.getSize


(heightMeasureSpec);

        setMeasuredDimension(measureWidth,measureHeight);

给父布局测量


当精确布局的时候,减掉他们的Margin,然后布局


measureChildren(childWidthMeasureSpec,childHeightMeasureSpec);


布局完的时候获取控件的高


4重点介绍一下onLayout方法,这个是布局的关键;

 for (int i = 0; i <getChildCount() ; i++) {

            View child = getChildAt(i);

            if (child.getVisibility() != GONE){

                if (i==0){

                    childTop+=params.topMargin;

                }

                child.layout(params.leftMargin, childTop,

                        child.getMeasuredWidth() + 


params.leftMargin, childTop + child.getMeasuredHeight());

                childTop = childTop + child.getMeasuredHeight


();

            }

        }


先是在childTop的大小,

布局后,再获取下一个

 childTop = childTop + child.getMeasuredHeight();

然后给一一次循环使用


5dispatchDraw()

这个是才是重点的方法

  final int height = getHeight();获取当前view的高度,即时一个


view显示的高度


 final int scrollHeight = screen * height;

 final int scrollY = this.getScrollY();

偏移量。

这里主要是判断哪几个子view需要进行3D效果的显示


接下来是显示  final int faceIndex = screen;

        final float currentDegree = getScrollY() * (angle / 


getMeasuredHeight());

        final float faceDegree = currentDegree - faceIndex * 


angle;

        if (faceDegree > 90 || faceDegree < -90) {

            return;

        }

这个可以显示

接下来根据滚动的距离,确定围绕的旋转点,进行围绕X旋转

 final float centerY = (scrollHeight < scrollY) ? scrollHeight 


+ height

                : scrollHeight;

        final float centerX = getWidth() / 2;

        final Camera camera = mCamera;

        final Matrix matrix = mMatrix;

        canvas.save();

        camera.save();

        camera.rotateX(faceDegree);

        camera.getMatrix(matrix);

        camera.restore();


        matrix.preTranslate(-centerX, -centerY);

        matrix.postTranslate(centerX, centerY);

        canvas.concat(matrix);


6接下来是事件分发机制的点击事件,这里的拦截只是简单的拦截。




(1)VelocityTracker创建,  mTracker.addMovement(event);将事件


传入,在手指弹起的时候,判断是否有一定的滑动距离的速度;

从而进行滑动


(2)先进行down的判断

并且如果Scroller的滚动计量没有结束的话,接着进行滚动,让滚动停


止,停留在上次的位置,并且记录Y的位置,留给下一个动作使用


(3)Move的操作

   Log.i("mo","onTouchEvent-move");

                int disY  = (int) (mDownY - y);

                mDownY = y;

                if (mScroller.isFinished()){

                    //每次的滚动结束后的处理

                    recycleMove(disY);

                }

                break;

每次完成上一次滚动后进行的操作

来看一下 recycleMove(int delta)方法

  delta = delta % mHeight;

        delta = (int) (delta / resistance);//阻力后实际滑动的

经过阻力计算后,获取实际要移动的距离


  scrollBy(0, delta);


  if (getScrollY() < 8 && mCurScreen != 0) {

            setPre();

            scrollBy(0, mHeight);

        }

当滚动到一定距离的时候,进行操作

setPre

设置子view的



(4)   mTracker.computeCurrentVelocity(1000);

  float velocitY = mTracker.getYVelocity();

根据传入的单位计算速率

 //滑动的速度大于规定的速度,或者向上滑动时,上一页页面展现出


的高度超过1/2。则设定状态为STATE_PRE

                if(velocitY > standerSpeed || ((getScrollY() + 


mHeight / 2) / mHeight < mStartScreen)){

                    STATE =  STATE_PRE;

                }else if(velocitY < -standerSpeed  || 


((getScrollY() + mHeight / 2) / mHeight > mStartScreen)){

                    //滑动的速度大于规定的速度,或者向下滑动时


,下一页页面展现出的高度超过1/2。则设定状态为STATE_NEXT

                    STATE =  STATE_NEXT;

                }else{

                    STATE =  STATE_NORMAL;

                }


根据不同的速度,以及位置的时候,判定距离


 int startY;

        int delta;

        int duration;

        STATE = STATE_PRE;

        //增加新的页面

        setPre();

        //mScroller开始的坐标

        startY = getScrollY() + mHeight;

        setScrollY(startY);

        //mScroller移动的距离

        delta = -(startY - mStartScreen * mHeight);

        duration = (Math.abs(delta)) * 2;

        mScroller.startScroll(0, startY, 0, delta, duration);


滚动到前一个页面


  @Override

    public void computeScroll() {

        if (mScroller.computeScrollOffset()) {

            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

            postInvalidate();

        }

    }

原文链接:http://www.apkbus.com/blog-880881-68318.html

0人推荐
随时随地看视频
慕课网APP