IReader打開書本,關閉書本動畫的自定義控件

一,實現思路

實現的效果:
此控件主要是模仿IReader打開書本翻轉以及放大特效,在看文章之前可以找本書來翻轉加深理解,呵呵,開個玩笑,進入正題。

實現的效果:

打開書本:

上層爲cover,下層爲content。cover播放放大翻轉動畫,content播放放大動畫。



幾個注意點:

1,動畫的播放只能侷限在父ViewGroup內部,放大到全屏該怎麼進行?

A:使用克隆體添加到WindowManager中,然後去播放動畫。


2,不能直接對WindowManager中的子控件播放動畫,該怎麼解決?

A:在WindowManger鋪滿一個AbsoluteLayout,然後再將克隆體cover添加到WindowManger中。


3,如果對任意位置的一張圖片,放大到全屏,讓位置剛好合適?

A:需要尋找到一個合適的縮放點。


二,具體實現

1,ContentScaleAnimation類,實現下層圖片的縮放。如何尋找縮放點?


上圖中 

這裏只演示怎麼計算縮放點橫座標


x爲縮放點橫座標

pw爲parentWidth

ml爲marginLeft

w爲控件寬度


找到如下關係    

縮放點到自身左邊距離/縮放點到父控件左邊的距離=縮放點自身右側距離/縮放點到父控件右邊的距離


(x-ml)/x=(w-(x-ml))/(pw-x)


計算得到x=ml*pw/(pw-w)

這裏提供方法:

    private float resolvePivotX(float margingLeft, int parentWidth, int width) {
        return (margingLeft * parentWidth) / (parentWidth - width);
    }


package huwei.com.bookviewdemo;

import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * Created by jayce on 15-2-4.
 */
public class ContentScaleAnimation extends Animation {
    private final float mFromX;
    private final float mToX;
    private final float mFromY;
    private final float mToY;
    private float mPivotX;
    private float mPivotY;
    private float mPivotXValue;
    private float mPivotYValue;
    private boolean mReverse;

    public ContentScaleAnimation(float mFromX, float mToX, float mFromY, float mToY, float mPivotXValue, float mPivotYValue, boolean mReverse) {
        this.mFromX = mFromX;
        this.mToX = mToX;
        this.mFromY = mFromY;
        this.mToY = mToY;
        this.mPivotXValue = mPivotXValue;
        this.mPivotYValue = mPivotYValue;
        this.mReverse = mReverse;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float sx = 1.0f;
        float sy = 1.0f;
        if (mFromX != 1.0f || mToX != 1.0f) {
            sx = mReverse ? mToX + (mFromX - mToX) * interpolatedTime : mFromX + (mToX - mFromX) * interpolatedTime;
        }
        if (mFromY != 1.0f || mToY != 1.0f) {
            sy = mReverse ? mToY + (mFromY - mToY) * interpolatedTime : mFromY + (mToY - mFromY) * interpolatedTime;
        }


        if (mPivotX == 0 && mPivotY == 0) {
            t.getMatrix().setScale(sx, sy);
        } else {
            t.getMatrix().setScale(sx, sy, mPivotX, mPivotY);
        }
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mPivotX = resolvePivotX(mPivotXValue, parentWidth, width);
        mPivotY = resolvePivoY(mPivotYValue, parentHeight, height);
    }

    private float resolvePivotX(float margingLeft, int parentWidth, int width) {
        return (margingLeft * parentWidth) / (parentWidth - width);
    }

    private float resolvePivoY(float marginTop, int parentHeight, int height) {

        return (marginTop * parentHeight) / (parentHeight - height);
    }
    public void reverse() {
        mReverse = !mReverse;
    }

    public boolean getMReverse() {
        return mReverse;
    }
}




,2,Rotate3DAnimation類,實現參考apiDemo中的Rotate3dAnimation,在此基礎上進行修改,實現翻轉和縮放動畫。


這裏需要繞Y軸旋轉180度,在翻轉前需要將物體移動到y軸上,然後再移回去。

    matrix.preTranslate(-mPivotXValue, 0);      //在進行rotateY之前需要移動物體,讓物體左邊與Y軸對齊
    matrix.postTranslate(mPivotXValue, 0);      //還原物體位置


package huwei.com.bookviewdemo;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * @author jayce
 * @date 2015/2/3
 */
public class Rotate3DAnimation extends Animation {
    private Camera mCamera;
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mPivotXValue;
    private final float mPivotYValue;
    //private final float mDepthZ;   //不需要用到此參數
    private final float scaleTimes;
    private boolean mReverse;

    private float mPivotX;      //縮放點X
    private float mPivotY;      //縮放點Y


    /**
     * cover 動畫構造方法,一邊放大,一邊翻轉
     * @param mFromDegrees
     * @param mToDegrees
     * @param mPivotXValue  控件左上角X
     * @param mPivotYValue  控件左上角Y
     * @param scaleTimes    縮放比例
     * @param mReverse   動畫是否逆向進行
     */
    public Rotate3DAnimation(float mFromDegrees, float mToDegrees, float mPivotXValue, float mPivotYValue, float scaleTimes, boolean mReverse) {
        this.mFromDegrees = mFromDegrees;
        this.mToDegrees = mToDegrees;
        this.mPivotXValue = mPivotXValue;
        this.mPivotYValue = mPivotYValue;
        this.scaleTimes = scaleTimes;
        this.mReverse = mReverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
        mPivotX = resolvePivotX(mPivotXValue, parentWidth, width);  //計算縮放點X
        mPivotY = resolvePivoY(mPivotYValue, parentHeight, height);   //計算縮放點Y
    }

    /**
     * 執行順序 matrix.preTranslate() -->  camera.rotateY(degrees) -->   matrix.postTranslate() -->   matrix.postScale()
     * @param interpolatedTime
     * @param t
     */
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float degrees = mReverse ? mToDegrees + (mFromDegrees - mToDegrees) * interpolatedTime : mFromDegrees + (mToDegrees - mFromDegrees) * interpolatedTime;
        final Matrix matrix = t.getMatrix();

        final Camera camera = mCamera;

        camera.save();

        camera.rotateY(degrees);

        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-mPivotXValue, 0);      //在進行rotateY之前需要移動物體,讓物體左邊與Y軸對齊
        matrix.postTranslate(mPivotXValue, 0);      //還原物體位置

        if (mReverse) {
            matrix.postScale(1 + (scaleTimes - 1) * (1.0f - interpolatedTime), 1 + (scaleTimes - 1) * (1.0f - interpolatedTime), mPivotX, mPivotY);
        } else {
            matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX, mPivotY);
        }
    }

    private float resolvePivotX(float margingLeft, int parentWidth, int width) {
        return (margingLeft * parentWidth) / (parentWidth - width);
    }

    private float resolvePivoY(float marginTop, int parentHeight, int height) {
        return (marginTop * parentHeight) / (parentHeight - height);
    }

    public void reverse() {
        mReverse = !mReverse;
    }

    public boolean getMReverse() {
        return mReverse;
    }
}


下載地址(4.0以及以下不支持) setX()導致動畫無法播放

下載地址(支持到2.2及以上)

發佈了68 篇原創文章 · 獲贊 143 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章