android.graphics.Camera

Here are the examples of the java api android.graphics.Camera taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

83 Examples 7

19 Source : FlipCardAnimation.java
with Apache License 2.0
from zhangke3016

/**
 * A 3D Flip Card for Android
 */
public clreplaced FlipCardAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private Camera mCamera;

    // 用于确定内容是否开始变化
    private boolean isContentChange = false;

    private OnContentChangeListener listener;

    public FlipCardAnimation(float fromDegrees, float toDegrees, float centerX, float centerY) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
    }

    // //用于确定内容是否开始变化  在动画开始之前调用
    public void setCanContentChange() {
        this.isContentChange = false;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (degrees > 90 || degrees < -90) {
            if (!isContentChange) {
                if (listener != null) {
                    listener.contentChange();
                }
                isContentChange = true;
            }
            if (degrees > 0) {
                degrees = 270 + degrees - 90;
            } else if (degrees < 0) {
                degrees = -270 + (degrees + 90);
            }
        }
        camera.rotateX(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }

    public void setOnContentChangeListener(OnContentChangeListener listener) {
        this.listener = listener;
    }

    public interface OnContentChangeListener {

        void contentChange();
    }
}

19 Source : RotateAnimation.java
with Apache License 2.0
from Yuphee

/**
 * Created by zhangyf on 2015/10/31.
 */
public clreplaced RotateAnimation extends Animation {

    /**
     * 值为true时可明确查看动画的旋转方向。
     */
    public static final boolean DEBUG = false;

    /**
     * 沿Y轴正方向看,数值减1时动画逆时针旋转。
     */
    public static final boolean ROTATE_DECREASE = true;

    /**
     * 沿Y轴正方向看,数值减1时动画顺时针旋转。
     */
    public static final boolean ROTATE_INCREASE = false;

    /**
     * Z轴上最大深度。
     */
    public static final float DEPTH_Z = 310.0f;

    /**
     * 动画显示时长。
     */
    public static final long DURATION = 200l;

    /**
     * 图片翻转类型。
     */
    private final boolean type;

    private final float centerX;

    private final float centerY;

    private Camera camera;

    /**
     * 用于监听动画进度。当值过半时需更新txtNumber的内容。
     */
    private InterpolatedTimeListener listener;

    public RotateAnimation(float cX, float cY, boolean type) {
        centerX = cX;
        centerY = cY;
        this.type = type;
        setDuration(DURATION);
    }

    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        // 在构造函数之后、getTransformation()之前调用本方法。
        super.initialize(width, height, parentWidth, parentHeight);
        camera = new Camera();
    }

    public void setInterpolatedTimeListener(InterpolatedTimeListener listener) {
        this.listener = listener;
    }

    protected void applyTransformation(float interpolatedTime, Transformation transformation) {
        // interpolatedTime:动画进度值,范围为[0.0f,1.0f]
        if (listener != null) {
            listener.interpolatedTime(interpolatedTime);
        }
        // Log.i("debug",interpolatedTime+"");
        float from = 0.0f, to = 0.0f;
        if (type == ROTATE_DECREASE) {
            from = 0.0f;
            // 0~180
            to = 180.0f;
        } else if (type == ROTATE_INCREASE) {
            from = 360.0f;
            // 360~180
            to = 180.0f;
        }
        float degree = from + (to - from) * interpolatedTime;
        boolean overHalf = (interpolatedTime > 0.5f);
        if (overHalf) {
            // 翻转过半的情况下,为保证数字仍为可读的文字而非镜面效果的文字,需翻转180度。
            degree = degree - 180;
        }
        // float depth = 0.0f;
        float depth = (0.5f - Math.abs(interpolatedTime - 0.5f)) * DEPTH_Z;
        final Matrix matrix = transformation.getMatrix();
        camera.save();
        camera.translate(0.0f, 0.0f, depth);
        camera.rotateX(degree);
        camera.getMatrix(matrix);
        camera.restore();
        if (DEBUG) {
            if (overHalf) {
                matrix.preTranslate(-centerX * 2, -centerY);
                matrix.postTranslate(centerX * 2, centerY);
            }
        } else {
            // 确保图片的翻转过程一直处于组件的中心点位置
            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
        }
    }

    /**
     * 动画进度监听器。
     */
    public static interface InterpolatedTimeListener {

        public void interpolatedTime(float interpolatedTime);
    }
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from xujiaji

public clreplaced Rotate3dAnimation extends Animation {

    private int mPivotXType = ABSOLUTE;

    private int mPivotYType = ABSOLUTE;

    private float mPivotXValue = 0.0f;

    private float mPivotYValue = 0.0f;

    private float mFromDegrees;

    private float mToDegrees;

    private float mPivotX;

    private float mPivotY;

    private Camera mCamera;

    private int mRollType;

    public static final int ROLL_BY_X = 0;

    public static final int ROLL_BY_Y = 1;

    public static final int ROLL_BY_Z = 2;

    protected static clreplaced Description {

        public int type;

        public float value;
    }

    Description parseValue(TypedValue value) {
        Description d = new Description();
        if (value == null) {
            d.type = ABSOLUTE;
            d.value = 0;
        } else {
            if (value.type == TypedValue.TYPE_FRACTION) {
                d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? RELATIVE_TO_PARENT : RELATIVE_TO_SELF;
                d.value = TypedValue.complexToFloat(value.data);
                return d;
            } else if (value.type == TypedValue.TYPE_FLOAT) {
                d.type = ABSOLUTE;
                d.value = value.getFloat();
                return d;
            } else if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT) {
                d.type = ABSOLUTE;
                d.value = value.data;
                return d;
            }
        }
        d.type = ABSOLUTE;
        d.value = 0.0f;
        return d;
    }

    public Rotate3dAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Rotate3dAnimation);
        mFromDegrees = a.getFloat(R.styleable.Rotate3dAnimation_fromDeg, 0.0f);
        mToDegrees = a.getFloat(R.styleable.Rotate3dAnimation_toDeg, 0.0f);
        mRollType = a.getInt(R.styleable.Rotate3dAnimation_rollType, ROLL_BY_X);
        Description d = parseValue(a.peekValue(R.styleable.Rotate3dAnimation_pivotX));
        mPivotXType = d.type;
        mPivotXValue = d.value;
        d = parseValue(a.peekValue(R.styleable.Rotate3dAnimation_pivotY));
        mPivotYType = d.type;
        mPivotYValue = d.value;
        a.recycle();
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees) {
        mRollType = rollType;
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mPivotX = 0.0f;
        mPivotY = 0.0f;
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, float pivotX, float pivotY) {
        mRollType = rollType;
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mPivotXType = ABSOLUTE;
        mPivotYType = ABSOLUTE;
        mPivotXValue = pivotX;
        mPivotYValue = pivotY;
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
        mRollType = rollType;
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mPivotXValue = pivotXValue;
        mPivotXType = pivotXType;
        mPivotYValue = pivotYValue;
        mPivotYType = pivotYType;
        initializePivotPoint();
    }

    private void initializePivotPoint() {
        if (mPivotXType == ABSOLUTE) {
            mPivotX = mPivotXValue;
        }
        if (mPivotYType == ABSOLUTE) {
            mPivotY = mPivotYValue;
        }
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
        mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
        mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final Matrix matrix = t.getMatrix();
        mCamera.save();
        switch(mRollType) {
            case ROLL_BY_X:
                mCamera.rotateX(degrees);
                break;
            case ROLL_BY_Y:
                mCamera.rotateY(degrees);
                break;
            case ROLL_BY_Z:
                mCamera.rotateZ(degrees);
                break;
        }
        mCamera.getMatrix(matrix);
        mCamera.restore();
        matrix.preTranslate(-mPivotX, -mPivotY);
        matrix.postTranslate(mPivotX, mPivotY);
    }
}

19 Source : PCanvas.java
with GNU General Public License v3.0
from victordiaz

public Camera getCamera() {
    Camera camera = new Camera();
    return camera;
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from TutorialsAndroid

public clreplaced Rotate3dAnimation extends Animation {

    private int mPivotXType = ABSOLUTE;

    private int mPivotYType = ABSOLUTE;

    private float mPivotXValue = 0.0f;

    private float mPivotYValue = 0.0f;

    private final float fromDegrees, toDegrees;

    private float pivotX, pivotY;

    private Camera camera;

    private final int rollType;

    private static final int ROLL_BY_X = 0;

    private static final int ROLL_BY_Y = 1;

    private static final int ROLL_BY_Z = 2;

    static clreplaced Description {

        int type;

        float value;
    }

    private Description parseValue(TypedValue value) {
        Description d = new Description();
        if (value == null) {
            d.type = ABSOLUTE;
            d.value = 0;
        } else {
            if (value.type == TypedValue.TYPE_FRACTION) {
                d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? RELATIVE_TO_PARENT : RELATIVE_TO_SELF;
                d.value = TypedValue.complexToFloat(value.data);
                return d;
            } else if (value.type == TypedValue.TYPE_FLOAT) {
                d.type = ABSOLUTE;
                d.value = value.getFloat();
                return d;
            } else if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT) {
                d.type = ABSOLUTE;
                d.value = value.data;
                return d;
            }
        }
        d.type = ABSOLUTE;
        d.value = 0.0f;
        return d;
    }

    public Rotate3dAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Rotate3dAnimation);
        fromDegrees = a.getFloat(R.styleable.Rotate3dAnimation_fromDeg, 0.0f);
        toDegrees = a.getFloat(R.styleable.Rotate3dAnimation_toDeg, 0.0f);
        rollType = a.getInt(R.styleable.Rotate3dAnimation_rollType, ROLL_BY_X);
        Description d = parseValue(a.peekValue(R.styleable.Rotate3dAnimation_pivotX));
        mPivotXType = d.type;
        mPivotXValue = d.value;
        d = parseValue(a.peekValue(R.styleable.Rotate3dAnimation_pivotY));
        mPivotYType = d.type;
        mPivotYValue = d.value;
        a.recycle();
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        pivotX = 0.0f;
        pivotY = 0.0f;
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, float pivotX, float pivotY) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        mPivotXType = ABSOLUTE;
        mPivotYType = ABSOLUTE;
        mPivotXValue = pivotX;
        mPivotYValue = pivotY;
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        mPivotXValue = pivotXValue;
        mPivotXType = pivotXType;
        mPivotYValue = pivotYValue;
        mPivotYType = pivotYType;
        initializePivotPoint();
    }

    private void initializePivotPoint() {
        if (mPivotXType == ABSOLUTE) {
            pivotX = mPivotXValue;
        }
        if (mPivotYType == ABSOLUTE) {
            pivotY = mPivotYValue;
        }
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        camera = new Camera();
        pivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
        pivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = this.fromDegrees;
        float degrees = fromDegrees + ((toDegrees - fromDegrees) * interpolatedTime);
        final Matrix matrix = t.getMatrix();
        camera.save();
        switch(rollType) {
            case ROLL_BY_X:
                camera.rotateX(degrees);
                break;
            case ROLL_BY_Y:
                camera.rotateY(degrees);
                break;
            case ROLL_BY_Z:
                camera.rotateZ(degrees);
                break;
        }
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-pivotX, -pivotY);
        matrix.postTranslate(pivotX, pivotY);
    }
}

19 Source : Rotate3dAnimation.java
with MIT License
from shrikanth7698

public clreplaced Rotate3dAnimation extends Animation {

    private final float fromXDegrees;

    private final float toXDegrees;

    private final float fromYDegrees;

    private final float toYDegrees;

    private final float fromZDegrees;

    private final float toZDegrees;

    private Camera camera;

    private int width = 0;

    private int height = 0;

    public Rotate3dAnimation(float fromXDegrees, float toXDegrees, float fromYDegrees, float toYDegrees, float fromZDegrees, float toZDegrees) {
        this.fromXDegrees = fromXDegrees;
        this.toXDegrees = toXDegrees;
        this.fromYDegrees = fromYDegrees;
        this.toYDegrees = toYDegrees;
        this.fromZDegrees = fromZDegrees;
        this.toZDegrees = toZDegrees;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        this.width = width / 4;
        this.height = height / 4;
        camera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float xDegrees = fromXDegrees + ((toXDegrees - fromXDegrees) * interpolatedTime);
        float yDegrees = fromYDegrees + ((toYDegrees - fromYDegrees) * interpolatedTime);
        float zDegrees = fromZDegrees + ((toZDegrees - fromZDegrees) * interpolatedTime);
        final Matrix matrix = t.getMatrix();
        camera.save();
        camera.rotateX(xDegrees);
        camera.rotateY(yDegrees);
        camera.rotateZ(zDegrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-this.width * 2, -this.height / 2);
        matrix.postTranslate(this.width * 2, this.height / 2);
    }
}

19 Source : InfoGallery.java
with MIT License
from sherry10

/**
 * Created by yuxin on 2017/3/15.
 */
public clreplaced InfoGallery extends Gallery {

    private Camera mCamera = new Camera();

    private int mMaxRotationAngle = 60;

    private int mMaxZoom = -60;

    private int mCoveflowCenter;

    public InfoGallery(Context context) {
        super(context);
        this.setStaticTransformationsEnabled(true);
    }

    public InfoGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setStaticTransformationsEnabled(true);
    }

    public InfoGallery(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setStaticTransformationsEnabled(true);
    }

    public int getMaxRotationAngle() {
        return mMaxRotationAngle;
    }

    public void setMaxRotationAngle(int maxRotationAngle) {
        mMaxRotationAngle = maxRotationAngle;
    }

    public int getMaxZoom() {
        return mMaxZoom;
    }

    public void setMaxZoom(int maxZoom) {
        mMaxZoom = maxZoom;
    }

    private int getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
    }

    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }

    protected boolean getChildStaticTransformation(View child, Transformation t) {
        final int childCenter = getCenterOfView(child);
        final int childWidth = child.getWidth();
        int rotationAngle = 0;
        t.clear();
        t.setTransformationType(Transformation.TYPE_MATRIX);
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap(child, t, 0);
        } else {
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap(child, t, rotationAngle);
        }
        return true;
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCoveflowCenter = getCenterOfCoverflow();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    private void transformImageBitmap(View child, Transformation t, int rotationAngle) {
        mCamera.save();
        final Matrix imageMatrix = t.getMatrix();
        final int imageHeight = child.getLayoutParams().height;
        final int imageWidth = child.getLayoutParams().width;
        final int rotation = Math.abs(rotationAngle);
        mCamera.translate(0.0f, 0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
            mCamera.translate(0.0f, 0.0f, zoomAmount);
        }
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
        mCamera.restore();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            return true;
        } else {
            return false;
        }
    }
}

19 Source : FlipAnimation.java
with Apache License 2.0
from samlss

/**
 * @author SamLeung
 * @e-mail [email protected]
 * @github https://github.com/samlss
 * @description Flip-p-p-p animation...
 */
clreplaced FlipAnimation extends Animation {

    private float centerX;

    private float centerY;

    private float fromDegree;

    private float toDegree;

    private int duration;

    private Camera camera = new Camera();

    private boolean needToReduce;

    private float decayFactor;

    private float lastInterpolatedTime = 0;

    public FlipAnimation(float fromDegree, float toDegree, float x, float y, int duration, boolean needToReduce) {
        this.centerX = x;
        this.centerY = y;
        this.duration = duration;
        this.needToReduce = needToReduce;
        this.fromDegree = fromDegree;
        this.toDegree = toDegree;
        float abs = Math.abs(fromDegree) < Math.abs(toDegree) ? Math.abs(fromDegree) : Math.abs(toDegree);
        decayFactor = abs / 3 + 1;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(duration);
        if (needToReduce) {
            setRepeatCount(5);
            setRepeatMode(Animation.REVERSE);
        }
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float degrees = fromDegree + (toDegree - fromDegree) * interpolatedTime;
        Matrix matrix = t.getMatrix();
        boolean equals = false;
        if (Math.abs(fromDegree) == Math.abs(toDegree))
            equals = true;
        camera.save();
        if ((interpolatedTime != lastInterpolatedTime) && needToReduce) {
            if (degrees == toDegree) {
                if (fromDegree > 0) {
                    if (!equals)
                        fromDegree = -toDegree;
                    fromDegree -= decayFactor;
                    if (fromDegree < 0)
                        fromDegree = 0;
                } else {
                    if (!equals)
                        fromDegree = -toDegree;
                    fromDegree += decayFactor;
                    if (fromDegree > 0)
                        fromDegree = 0;
                }
            }
            if (degrees == fromDegree) {
                if (toDegree > 0) {
                    toDegree -= decayFactor;
                    if (toDegree < 0)
                        toDegree = 0;
                } else {
                    toDegree += decayFactor;
                    if (toDegree > 0) {
                        toDegree = 0;
                    }
                }
            }
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
        lastInterpolatedTime = interpolatedTime;
    }
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from oktavianto

public clreplaced Rotate3dAnimation extends Animation {

    private int mPivotXType = ABSOLUTE;

    private int mPivotYType = ABSOLUTE;

    private float mPivotXValue = 0.0f;

    private float mPivotYValue = 0.0f;

    private final float fromDegrees, toDegrees;

    private float pivotX, pivotY;

    private Camera camera;

    private final int rollType;

    private static final int ROLL_BY_X = 0;

    private static final int ROLL_BY_Y = 1;

    private static final int ROLL_BY_Z = 2;

    static clreplaced Description {

        int type;

        float value;
    }

    private Description parseValue(TypedValue value) {
        Description d = new Description();
        if (value == null) {
            d.type = ABSOLUTE;
            d.value = 0;
        } else {
            if (value.type == TypedValue.TYPE_FRACTION) {
                d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? RELATIVE_TO_PARENT : RELATIVE_TO_SELF;
                d.value = TypedValue.complexToFloat(value.data);
                return d;
            } else if (value.type == TypedValue.TYPE_FLOAT) {
                d.type = ABSOLUTE;
                d.value = value.getFloat();
                return d;
            } else if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT) {
                d.type = ABSOLUTE;
                d.value = value.data;
                return d;
            }
        }
        d.type = ABSOLUTE;
        d.value = 0.0f;
        return d;
    }

    public Rotate3dAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Rotate3D);
        fromDegrees = a.getFloat(R.styleable.Rotate3D_ion_fromDeg, 0.0f);
        toDegrees = a.getFloat(R.styleable.Rotate3D_ion_toDeg, 0.0f);
        rollType = a.getInt(R.styleable.Rotate3D_ion_rollType, ROLL_BY_X);
        Description d = parseValue(a.peekValue(R.styleable.Rotate3D_ion_pivotX));
        mPivotXType = d.type;
        mPivotXValue = d.value;
        d = parseValue(a.peekValue(R.styleable.Rotate3D_ion_pivotY));
        mPivotYType = d.type;
        mPivotYValue = d.value;
        a.recycle();
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        pivotX = 0.0f;
        pivotY = 0.0f;
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, float pivotX, float pivotY) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        mPivotXType = ABSOLUTE;
        mPivotYType = ABSOLUTE;
        mPivotXValue = pivotX;
        mPivotYValue = pivotY;
        initializePivotPoint();
    }

    public Rotate3dAnimation(int rollType, float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
        this.rollType = rollType;
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        mPivotXValue = pivotXValue;
        mPivotXType = pivotXType;
        mPivotYValue = pivotYValue;
        mPivotYType = pivotYType;
        initializePivotPoint();
    }

    private void initializePivotPoint() {
        if (mPivotXType == ABSOLUTE) {
            pivotX = mPivotXValue;
        }
        if (mPivotYType == ABSOLUTE) {
            pivotY = mPivotYValue;
        }
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        camera = new Camera();
        pivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
        pivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = this.fromDegrees;
        float degrees = fromDegrees + ((toDegrees - fromDegrees) * interpolatedTime);
        final Matrix matrix = t.getMatrix();
        camera.save();
        switch(rollType) {
            case ROLL_BY_X:
                camera.rotateX(degrees);
                break;
            case ROLL_BY_Y:
                camera.rotateY(degrees);
                break;
            case ROLL_BY_Z:
                camera.rotateZ(degrees);
                break;
        }
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-pivotX, -pivotY);
        matrix.postTranslate(pivotX, pivotY);
    }
}

19 Source : CourseInfoGallery.java
with Apache License 2.0
from nicolite

/**
 * Created by 高沛 on 2016/7/12.
 */
public clreplaced CourseInfoGallery extends Gallery {

    private Camera mCamera = new Camera();

    private int mMaxRotationAngle = 60;

    private int mMaxZoom = -60;

    private int mCoveflowCenter;

    public CourseInfoGallery(Context context) {
        super(context);
        this.setStaticTransformationsEnabled(true);
    }

    public CourseInfoGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setStaticTransformationsEnabled(true);
    }

    public CourseInfoGallery(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setStaticTransformationsEnabled(true);
    }

    public int getMaxRotationAngle() {
        return mMaxRotationAngle;
    }

    public void setMaxRotationAngle(int maxRotationAngle) {
        mMaxRotationAngle = maxRotationAngle;
    }

    public int getMaxZoom() {
        return mMaxZoom;
    }

    public void setMaxZoom(int maxZoom) {
        mMaxZoom = maxZoom;
    }

    private int getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
    }

    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }

    protected boolean getChildStaticTransformation(View child, Transformation t) {
        final int childCenter = getCenterOfView(child);
        final int childWidth = child.getWidth();
        int rotationAngle = 0;
        t.clear();
        t.setTransformationType(Transformation.TYPE_MATRIX);
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap(child, t, 0);
        } else {
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap(child, t, rotationAngle);
        }
        return true;
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCoveflowCenter = getCenterOfCoverflow();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    private void transformImageBitmap(View child, Transformation t, int rotationAngle) {
        mCamera.save();
        final Matrix imageMatrix = t.getMatrix();
        final int imageHeight = child.getLayoutParams().height;
        final int imageWidth = child.getLayoutParams().width;
        final int rotation = Math.abs(rotationAngle);
        mCamera.translate(0.0f, 0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
            mCamera.translate(0.0f, 0.0f, zoomAmount);
        }
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
        mCamera.restore();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            return true;
        } else {
            return false;
        }
    }
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from kingwang666

/**
 * Created on 2017/8/24.
 * Author: wang
 */
public clreplaced Rotate3dAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private final float mDepthZ;

    private final boolean mReverse;

    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation //起始角度
     * @param toDegrees the end angle of the 3D rotation //结束角度
     * @param centerX the X center of the 3D rotation //x中轴线
     * @param centerY the Y center of the 3D rotation //y中轴线
     * @param reverse true if the translation should be reversed, false otherwise//是否反转
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        // Z轴移动的距离,这个来影响视觉效果,可以解决flip animation那个给人看似放大的效果
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from jiyouliang

/**
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
public clreplaced Rotate3dAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private final float mDepthZ;

    private final boolean mReverse;

    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

19 Source : Rotate3dAnimation.java
with MIT License
from JingYeoh

/**
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 * <p>
 * <a href="https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/animation/Rotate3dAnimation.java">Rotate3dAnimation</a>
 */
public clreplaced Rotate3dAnimation extends Animation {

    private static final int TYPE_SCALE = 0;

    private static final int TYPE_PX = 1;

    private final float mFromDegrees;

    private final float mToDegrees;

    private float mCenterX;

    private float mCenterY;

    private float mDepthZ;

    private int mType = TYPE_PX;

    private final boolean mReverse;

    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees   the end angle of the 3D rotation
     * @param centerX     the X center of the 3D rotation
     * @param centerY     the Y center of the 3D rotation
     * @param reverse     true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse, int type) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
        mType = type;
    }

    public Rotate3dAnimation(float fromDegrees, float toDegrees, boolean reverse) {
        this(fromDegrees, toDegrees, 0.5f, 0.5f, 0.5f, reverse, TYPE_SCALE);
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
        if (mType == TYPE_SCALE) {
            mCenterX = width * mCenterX;
            mCenterY = height * mCenterY;
            mDepthZ = width * mDepthZ;
        }
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

19 Source : Rotate3dAnimation.java
with Apache License 2.0
from JasonFengIce

/**
 * 一个在指定了两个角度的在Y轴旋转的动画类.
 * 这个类也添加了一个z轴的属性用来提高效果.
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
public clreplaced Rotate3dAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private final float mDepthZ;

    private final boolean mReverse;

    private Camera mCamera;

    /**
     * 在Y轴创建了一个新的3D的旋转动画,这个旋转动画定义了它的开始角度和结束角度,
     * 两个角度的单位都是度数,这个旋转动画围绕在2D空间的中心点执行.
     * 你可以用X轴坐标(叫做centerX)和Y轴(叫做centerY)坐标来定义这个中心点.
     * 当动画开始时,对于z轴(深度)的转换就会被执行.转换的长度和转换正向反向都可以指定.
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation 开始的角度
     * @param toDegrees   the end angle of the 3D rotation 结束的角度
     * @param centerX     the X center of the 3D rotation 中心点X轴坐标
     * @param centerY     the Y center of the 3D rotation 中心点Y轴坐标
     * @param reverse     true if the translation should be reversed, false otherwise true表示反向,false表示正向
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

19 Source : Rotate3DAnimation.java
with Apache License 2.0
from InnoFang

/**
 * Author: Inno Fang
 * Time: 2017/4/15 15:26
 * Description:
 */
public clreplaced Rotate3DAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private final float mDepthZ;

    private final boolean mReverse;

    private Camera mCamera;

    // <------- 像素密度
    float scale = 1;

    public Rotate3DAnimation(Context context, float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
        // 获取手机像素密度 (即dp与px的比例)
        scale = context.getResources().getDisplayMetrics().density;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        // 调节深度
        if (mReverse)
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        else
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        // 绕y轴旋转
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
        float[] mValues = new float[9];
        // 获取数值
        matrix.getValues(mValues);
        // 数值修正
        mValues[6] = mValues[6] / scale;
        // 数值修正
        mValues[7] = mValues[7] / scale;
        // 重新赋值
        matrix.setValues(mValues);
        // 调节中心点
        matrix.preTranslate(-centerX, -centerY);
        matrix.postScale(centerX, centerY);
    }
}

19 Source : FancyCoverFlow.java
with Apache License 2.0
from iamvaliyev

public clreplaced FancyCoverFlow extends Gallery {

    // =============================================================================
    // Constants
    // =============================================================================
    public static final int ACTION_DISTANCE_AUTO = Integer.MAX_VALUE;

    public static final float SCALEDOWN_GRAVITY_TOP = 0.0f;

    public static final float SCALEDOWN_GRAVITY_CENTER = 0.5f;

    public static final float SCALEDOWN_GRAVITY_BOTTOM = 1.0f;

    // =============================================================================
    // Private members
    // =============================================================================
    private float reflectionRatio = 0.4f;

    private int reflectionGap = 20;

    private boolean reflectionEnabled = false;

    /**
     * TODO: Doc
     */
    private float unselectedAlpha;

    /**
     * Camera used for view transformation.
     */
    private Camera transformationCamera;

    /**
     * TODO: Doc
     */
    private int maxRotation = 75;

    /**
     * Factor (0-1) that defines how much the unselected children should be scaled down. 1 means no scaledown.
     */
    private float unselectedScale;

    /**
     * TODO: Doc
     */
    private float scaleDownGravity = SCALEDOWN_GRAVITY_CENTER;

    /**
     * Distance in pixels between the transformation effects (alpha, rotation, zoom) are applied.
     */
    private int actionDistance;

    /**
     * Saturation factor (0-1) of items that reach the outer effects distance.
     */
    private float unselectedSaturation;

    // =============================================================================
    // Constructors
    // =============================================================================
    public FancyCoverFlow(Context context) {
        super(context);
        this.initialize();
    }

    public FancyCoverFlow(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.initialize();
        this.applyXmlAttributes(attrs);
    }

    public FancyCoverFlow(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.initialize();
        this.applyXmlAttributes(attrs);
    }

    private void initialize() {
        this.transformationCamera = new Camera();
        this.setSpacing(0);
    }

    private void applyXmlAttributes(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FancyCoverFlow);
        this.actionDistance = a.getInteger(R.styleable.FancyCoverFlow_actionDistance, ACTION_DISTANCE_AUTO);
        this.scaleDownGravity = a.getFloat(R.styleable.FancyCoverFlow_scaleDownGravity, 1.0f);
        this.maxRotation = a.getInteger(R.styleable.FancyCoverFlow_maxRotation, 45);
        this.unselectedAlpha = a.getFloat(R.styleable.FancyCoverFlow_unselectedAlpha, 0.3f);
        this.unselectedSaturation = a.getFloat(R.styleable.FancyCoverFlow_unselectedSaturation, 0.0f);
        this.unselectedScale = a.getFloat(R.styleable.FancyCoverFlow_unselectedScale, 0.75f);
    }

    // =============================================================================
    // Getter / Setter
    // =============================================================================
    public float getReflectionRatio() {
        return reflectionRatio;
    }

    public void setReflectionRatio(float reflectionRatio) {
        if (reflectionRatio <= 0 || reflectionRatio > 0.5f) {
            throw new IllegalArgumentException("reflectionRatio may only be in the interval (0, 0.5]");
        }
        this.reflectionRatio = reflectionRatio;
        if (this.getAdapter() != null) {
            ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
        }
    }

    public int getReflectionGap() {
        return reflectionGap;
    }

    public void setReflectionGap(int reflectionGap) {
        this.reflectionGap = reflectionGap;
        if (this.getAdapter() != null) {
            ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
        }
    }

    public boolean isReflectionEnabled() {
        return reflectionEnabled;
    }

    public void setReflectionEnabled(boolean reflectionEnabled) {
        this.reflectionEnabled = reflectionEnabled;
        if (this.getAdapter() != null) {
            ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
        }
    }

    /**
     * Use this to provide a {@link FancyCoverFlowAdapter} to the coverflow. This
     * method will throw an {@link ClreplacedCastException} if the preplaceded adapter does not
     * subclreplaced {@link FancyCoverFlowAdapter}.
     *
     * @param adapter
     */
    @Override
    public void setAdapter(SpinnerAdapter adapter) {
        if (!(adapter instanceof FancyCoverFlowAdapter)) {
            throw new ClreplacedCastException(FancyCoverFlow.clreplaced.getSimpleName() + " only works in conjunction with a " + FancyCoverFlowAdapter.clreplaced.getSimpleName());
        }
        super.setAdapter(adapter);
    }

    /**
     * Returns the maximum rotation that is applied to items left and right of the center of the coverflow.
     *
     * @return
     */
    public int getMaxRotation() {
        return maxRotation;
    }

    /**
     * Sets the maximum rotation that is applied to items left and right of the center of the coverflow.
     *
     * @param maxRotation
     */
    public void setMaxRotation(int maxRotation) {
        this.maxRotation = maxRotation;
    }

    /**
     * TODO: Write doc
     *
     * @return
     */
    public float getUnselectedAlpha() {
        return this.unselectedAlpha;
    }

    /**
     * TODO: Write doc
     *
     * @return
     */
    public float getUnselectedScale() {
        return unselectedScale;
    }

    /**
     * TODO: Write doc
     *
     * @param unselectedScale
     */
    public void setUnselectedScale(float unselectedScale) {
        this.unselectedScale = unselectedScale;
    }

    /**
     * TODO: Doc
     *
     * @return
     */
    public float getScaleDownGravity() {
        return scaleDownGravity;
    }

    /**
     * TODO: Doc
     *
     * @param scaleDownGravity
     */
    public void setScaleDownGravity(float scaleDownGravity) {
        this.scaleDownGravity = scaleDownGravity;
    }

    /**
     * TODO: Write doc
     *
     * @return
     */
    public int getActionDistance() {
        return actionDistance;
    }

    /**
     * TODO: Write doc
     *
     * @param actionDistance
     */
    public void setActionDistance(int actionDistance) {
        this.actionDistance = actionDistance;
    }

    /**
     * TODO: Write doc
     *
     * @param unselectedAlpha
     */
    @Override
    public void setUnselectedAlpha(float unselectedAlpha) {
        super.setUnselectedAlpha(unselectedAlpha);
        this.unselectedAlpha = unselectedAlpha;
    }

    /**
     * TODO: Write doc
     *
     * @return
     */
    public float getUnselectedSaturation() {
        return unselectedSaturation;
    }

    /**
     * TODO: Write doc
     *
     * @param unselectedSaturation
     */
    public void setUnselectedSaturation(float unselectedSaturation) {
        this.unselectedSaturation = unselectedSaturation;
    }

    // =============================================================================
    // Supertype overrides
    // =============================================================================
    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        // We can cast here because FancyCoverFlowAdapter only creates wrappers.
        FancyCoverFlowItemWrapper item = (FancyCoverFlowItemWrapper) child;
        // Since Jelly Bean childs won't get invalidated automatically, needs to be added for the smooth coverflow animation
        if (android.os.Build.VERSION.SDK_INT >= 16) {
            item.invalidate();
        }
        final int coverFlowWidth = this.getWidth();
        final int coverFlowCenter = coverFlowWidth / 2;
        final int childWidth = item.getWidth();
        final int childHeight = item.getHeight();
        final int childCenter = item.getLeft() + childWidth / 2;
        // Use coverflow width when its defined as automatic.
        final int actionDistance = (this.actionDistance == ACTION_DISTANCE_AUTO) ? (int) ((coverFlowWidth + childWidth) / 2.0f) : this.actionDistance;
        // Calculate the abstract amount for all effects.
        final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - coverFlowCenter)));
        // Clear previous transformations and set transformation type (matrix + alpha).
        t.clear();
        t.setTransformationType(Transformation.TYPE_BOTH);
        // Alpha
        if (this.unselectedAlpha != 1) {
            final float alphaAmount = (this.unselectedAlpha - 1) * Math.abs(effectsAmount) + 1;
            t.setAlpha(alphaAmount);
        }
        // Saturation
        if (this.unselectedSaturation != 1) {
            // Preplaced over saturation to the wrapper.
            final float saturationAmount = (this.unselectedSaturation - 1) * Math.abs(effectsAmount) + 1;
            item.setSaturation(saturationAmount);
        }
        final Matrix imageMatrix = t.getMatrix();
        // Apply rotation.
        if (this.maxRotation != 0) {
            final int rotationAngle = (int) (-effectsAmount * this.maxRotation);
            this.transformationCamera.save();
            this.transformationCamera.rotateY(rotationAngle);
            this.transformationCamera.getMatrix(imageMatrix);
            this.transformationCamera.restore();
        }
        // Zoom.
        if (this.unselectedScale != 1) {
            final float zoomAmount = (this.unselectedScale - 1) * Math.abs(effectsAmount) + 1;
            // Calculate the scale anchor (y anchor can be altered)
            final float translateX = childWidth / 2.0f;
            final float translateY = childHeight * this.scaleDownGravity;
            imageMatrix.preTranslate(-translateX, -translateY);
            imageMatrix.postScale(zoomAmount, zoomAmount);
            imageMatrix.postTranslate(translateX, translateY);
        }
        return true;
    }

    // =============================================================================
    // Public clreplacedes
    // =============================================================================
    public static clreplaced LayoutParams extends Gallery.LayoutParams {

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int w, int h) {
            super(w, h);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }
}

19 Source : FlipAnimation.java
with MIT License
from ABTSoftware

public clreplaced FlipAnimation extends Animation {

    private final float fromDegrees;

    private final float toDegrees;

    private final float centerX;

    private final float centerY;

    private Camera mCamera;

    public FlipAnimation(float fromDegrees, float toDegrees, float centerX, float centerY) {
        this.fromDegrees = fromDegrees;
        this.toDegrees = toDegrees;
        this.centerX = centerX;
        this.centerY = centerY;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float degrees = fromDegrees + ((toDegrees - fromDegrees) * interpolatedTime);
        final Matrix matrix = t.getMatrix();
        final Camera camera = mCamera;
        camera.save();
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

18 Source : TabletTransformer.java
with Apache License 2.0
from wenchaosong

public clreplaced TabletTransformer extends ABaseTransformer {

    private static final Matrix OFFSET_MATRIX = new Matrix();

    private static final Camera OFFSET_CAMERA = new Camera();

    private static final float[] OFFSET_TEMP_FLOAT = new float[2];

    @Override
    protected void onTransform(View view, float position) {
        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));
        view.setPivotX(view.getWidth() * 0.5f);
        view.setPivotY(0);
        view.setRotationY(rotation);
    }

    protected static final float getOffsetXForRotation(float degrees, int width, int height) {
        OFFSET_MATRIX.reset();
        OFFSET_CAMERA.save();
        OFFSET_CAMERA.rotateY(Math.abs(degrees));
        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
        OFFSET_CAMERA.restore();
        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
        OFFSET_TEMP_FLOAT[0] = width;
        OFFSET_TEMP_FLOAT[1] = height;
        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
        return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
    }
}

18 Source : FlipAnimation.java
with MIT License
from riteshakya037

/**
 * Flip animation for cards view. Switching between to view while changing camera.
 * <p>
 * Created by Ritesh Shakya on 8/24/2016.
 */
public clreplaced FlipAnimation extends Animation {

    /**
     * Change the camera of view while animating.
     */
    private Camera camera;

    /**
     * Current active view
     */
    private View fromView;

    /**
     * View to rotate to.
     */
    private View toView;

    /**
     * Center X value of view
     */
    private float centerX;

    /**
     * Center Y value of view.
     */
    private float centerY;

    private boolean forward = true;

    public FlipAnimation(View fromView, View toView) {
        this.fromView = fromView;
        this.toView = toView;
        setDuration(700);
        setFillAfter(false);
        setInterpolator(new AccelerateDecelerateInterpolator());
    }

    /**
     * Play animation in reverse.
     */
    public void reverse() {
        forward = false;
        View switchView = toView;
        toView = fromView;
        fromView = switchView;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        centerX = width / 2;
        centerY = height / 2;
        camera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final double radians = Math.PI * interpolatedTime;
        float degrees = (float) (180.0 * radians / Math.PI);
        if (interpolatedTime >= 0.5f) {
            // Alternate the visibility of views at the exact half of animation duration.
            degrees -= 180.f;
            fromView.setVisibility(View.GONE);
            toView.setVisibility(View.VISIBLE);
        }
        if (forward)
            degrees = -degrees;
        final Matrix matrix = t.getMatrix();
        camera.save();
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

18 Source : CameraSubject.java
with Apache License 2.0
from pkware

/**
 * Propositions for {@link Camera} subjects.
 */
public clreplaced CameraSubject extends Subject {

    @Nullable
    private final Camera actual;

    public CameraSubject(@Nonnull FailureMetadata failureMetadata, @Nullable Camera actual) {
        super(failureMetadata, actual);
        this.actual = actual;
    }

    @TargetApi(JELLY_BEAN)
    public void hasLocationX(float location, float tolerance) {
        check("getLocationX()").that(actual.getLocationX()).isWithin(tolerance).of(location);
    }

    @TargetApi(JELLY_BEAN)
    public void hasLocationY(float location, float tolerance) {
        check("getLocationY()").that(actual.getLocationY()).isWithin(tolerance).of(location);
    }

    @TargetApi(JELLY_BEAN)
    public void hasLocationZ(float location, float tolerance) {
        check("getLocationZ()").that(actual.getLocationZ()).isWithin(tolerance).of(location);
    }
}

18 Source : TabletTransformer.java
with MIT License
from Omega-R

public clreplaced TabletTransformer implements ItemTransformer {

    private final Matrix mOffsetMatrix = new Matrix();

    private final Camera mOffsetCamera = new Camera();

    private final float[] mOffset = new float[2];

    @Override
    public void transformItem(View view, float position, boolean isHorizontal, int scrolled) {
        float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        int width = view.getWidth();
        int height = view.getHeight();
        if (isHorizontal) {
            view.setTranslationX(getOffsetForRotation(rotation, width, height, true));
            view.setPivotX(width * 0.5f);
            view.setPivotY(0);
            view.setRotationY(rotation);
        } else {
            view.setTranslationY(getOffsetForRotation(rotation, width, height, false));
            view.setPivotY(height * 0.5f);
            view.setPivotX(0);
            view.setRotationX(-rotation);
        }
    }

    private float getOffsetForRotation(float degrees, int width, int height, boolean isHorizontal) {
        mOffsetMatrix.reset();
        mOffsetCamera.save();
        if (isHorizontal) {
            mOffsetCamera.rotateY(Math.abs(degrees));
        } else {
            mOffsetCamera.rotateX(Math.abs(degrees));
        }
        mOffsetCamera.getMatrix(mOffsetMatrix);
        mOffsetCamera.restore();
        mOffsetMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
        mOffsetMatrix.postTranslate(width * 0.5f, height * 0.5f);
        mOffset[0] = width;
        mOffset[1] = height;
        mOffsetMatrix.mapPoints(mOffset);
        if (isHorizontal) {
            return (width - mOffset[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
        } else {
            return (height - mOffset[1]) * (degrees > 0.0f ? 1.0f : -1.0f);
        }
    }
}

18 Source : TabletTransformer.java
with Apache License 2.0
from myinnos

public clreplaced TabletTransformer extends BaseTransformer {

    private static final Matrix OFFSET_MATRIX = new Matrix();

    private static final Camera OFFSET_CAMERA = new Camera();

    private static final float[] OFFSET_TEMP_FLOAT = new float[2];

    @Override
    protected void onTransform(View view, float position) {
        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        ViewHelper.setTranslationX(view, getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));
        ViewHelper.setPivotX(view, view.getWidth() * 0.5f);
        ViewHelper.setPivotY(view, 0);
        ViewHelper.setRotationY(view, rotation);
    }

    protected static final float getOffsetXForRotation(float degrees, int width, int height) {
        OFFSET_MATRIX.reset();
        OFFSET_CAMERA.save();
        OFFSET_CAMERA.rotateY(Math.abs(degrees));
        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
        OFFSET_CAMERA.restore();
        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
        OFFSET_TEMP_FLOAT[0] = width;
        OFFSET_TEMP_FLOAT[1] = height;
        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
        return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
    }
}

18 Source : TriangleSkewSpinIndicator.java
with Apache License 2.0
from madreain

/**
 * Created by Jack on 2015/10/20.
 */
public clreplaced TriangleSkewSpinIndicator extends Indicator {

    private float rotateX;

    private float rotateY;

    private Camera mCamera;

    private Matrix mMatrix;

    public TriangleSkewSpinIndicator() {
        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(rotateX);
        mCamera.rotateY(rotateY);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        Path path = new Path();
        path.moveTo(getWidth() / 5, getHeight() * 4 / 5);
        path.lineTo(getWidth() * 4 / 5, getHeight() * 4 / 5);
        path.lineTo(getWidth() / 2, getHeight() / 5);
        path.close();
        canvas.drawPath(path, paint);
    }

    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators = new ArrayList<>();
        ValueAnimator animator = ValueAnimator.ofFloat(0, 180, 180, 0, 0);
        addUpdateListener(animator, new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateX = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(2500);
        ValueAnimator animator1 = ValueAnimator.ofFloat(0, 0, 180, 180, 0);
        addUpdateListener(animator1, new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateY = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator1.setInterpolator(new LinearInterpolator());
        animator1.setRepeatCount(-1);
        animator1.setDuration(2500);
        animators.add(animator);
        animators.add(animator1);
        return animators;
    }
}

18 Source : SquareSpinIndicator.java
with Apache License 2.0
from madreain

/**
 * Created by Jack on 2015/10/16.
 */
public clreplaced SquareSpinIndicator extends Indicator {

    private float rotateX;

    private float rotateY;

    private Camera mCamera;

    private Matrix mMatrix;

    public SquareSpinIndicator() {
        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(rotateX);
        mCamera.rotateY(rotateY);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        canvas.drawRect(new RectF(getWidth() / 5, getHeight() / 5, getWidth() * 4 / 5, getHeight() * 4 / 5), paint);
    }

    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators = new ArrayList<>();
        ValueAnimator animator = ValueAnimator.ofFloat(0, 180, 180, 0, 0);
        addUpdateListener(animator, new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateX = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(2500);
        ValueAnimator animator1 = ValueAnimator.ofFloat(0, 0, 180, 180, 0);
        addUpdateListener(animator1, new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateY = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator1.setInterpolator(new LinearInterpolator());
        animator1.setRepeatCount(-1);
        animator1.setDuration(2500);
        animators.add(animator);
        animators.add(animator1);
        return animators;
    }
}

18 Source : BallPulseRiseIndicator.java
with Apache License 2.0
from madreain

/**
 * Created by Jack on 2015/10/17.
 */
public clreplaced BallPulseRiseIndicator extends Indicator {

    private Camera mCamera;

    private Matrix mMatrix;

    private float degress;

    public BallPulseRiseIndicator() {
        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(degress);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        float radius = getWidth() / 10;
        canvas.drawCircle(getWidth() / 4, radius * 2, radius, paint);
        canvas.drawCircle(getWidth() * 3 / 4, radius * 2, radius, paint);
        canvas.drawCircle(radius, getHeight() - 2 * radius, radius, paint);
        canvas.drawCircle(getWidth() / 2, getHeight() - 2 * radius, radius, paint);
        canvas.drawCircle(getWidth() - radius, getHeight() - 2 * radius, radius, paint);
    }

    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators = new ArrayList<>();
        ValueAnimator animator = ValueAnimator.ofFloat(0, 360);
        addUpdateListener(animator, new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degress = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(1500);
        animators.add(animator);
        return animators;
    }
}

18 Source : TextView3D.java
with Apache License 2.0
from JustinRoom

/**
 * <br>Email:[email protected]
 * <br>QQ:1006368252
 * <br><a href="https://github.com/JustinRoom/WheelViewDemo" target="_blank">https://github.com/JustinRoom/WheelViewDemo</a>
 *
 * @author jiangshicheng
 */
public clreplaced TextView3D extends android.support.v7.widget.AppCompatTextView {

    Matrix matrix = new Matrix();

    Camera camera = new Camera();

    float angle;

    public TextView3D(Context context) {
        this(context, null);
    }

    public TextView3D(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TextView3D(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextView3D, defStyleAttr, 0);
        angle = a.getFloat(R.styleable.TextView3D_angle, 0);
        a.recycle();
        setGravity(Gravity.CENTER);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        float cx = getWidth() / 2.0f;
        float cy = getHeight() / 2.0f;
        matrix.reset();
        camera.save();
        camera.rotateX(angle);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.postTranslate(cx, cy);
        matrix.preTranslate(-cx, -cy);
        canvas.concat(matrix);
        super.onDraw(canvas);
    }
}

18 Source : TabletTransformer.java
with MIT License
from HamidrezaAmz

public clreplaced TabletTransformer extends BaseTransformer {

    private static final Matrix OFFSET_MATRIX = new Matrix();

    private static final Camera OFFSET_CAMERA = new Camera();

    private static final float[] OFFSET_TEMP_FLOAT = new float[2];

    @Override
    protected void onTransform(View view, float position) {
        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));
        view.setPivotX(view.getWidth() * 0.5f);
        view.setPivotY(0);
        view.setRotationY(rotation);
    }

    protected static final float getOffsetXForRotation(float degrees, int width, int height) {
        OFFSET_MATRIX.reset();
        OFFSET_CAMERA.save();
        OFFSET_CAMERA.rotateY(Math.abs(degrees));
        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
        OFFSET_CAMERA.restore();
        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
        OFFSET_TEMP_FLOAT[0] = width;
        OFFSET_TEMP_FLOAT[1] = height;
        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
        return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
    }
}

18 Source : TableTransformer.java
with Artistic License 2.0
from gdutxiaoxu

/**
 * @ explain:
 * @ author:xujun on 2016/8/15 10:45
 * @ email:[email protected]
 */
public clreplaced TableTransformer extends BaseTransformer {

    private static final Matrix OFFSET_MATRIX = new Matrix();

    private static final Camera OFFSET_CAMERA = new Camera();

    private static final float[] OFFSET_TEMP_FLOAT = new float[2];

    private static final float minScale = 0.6f;

    @Override
    protected void onTransform(View view, float position) {
        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));
        view.setPivotX(view.getWidth() * 0.5f);
        view.setPivotY(0);
        view.setRotationY(rotation);
        float scaleX = Math.max(1 - Math.abs(position), minScale);
        view.setScaleX(scaleX);
    }

    protected static final float getOffsetXForRotation(float degrees, int width, int height) {
        OFFSET_MATRIX.reset();
        OFFSET_CAMERA.save();
        OFFSET_CAMERA.rotateY(Math.abs(degrees));
        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
        OFFSET_CAMERA.restore();
        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
        OFFSET_TEMP_FLOAT[0] = width;
        OFFSET_TEMP_FLOAT[1] = height;
        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
        return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
    }
}

18 Source : TabletTransformer.java
with Apache License 2.0
from ckrgithub

public clreplaced TabletTransformer extends BaseTransformer {

    private static final Matrix OFFSET_MATRIX = new Matrix();

    private static final Camera OFFSET_CAMERA = new Camera();

    private static final float[] OFFSET_TEMP_FLOAT = new float[2];

    @Override
    protected void onTransform(View view, float position, boolean forwardDirection, int mOrientation) {
        final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
        if (mOrientation == OnPageDataListener.HORIZONTAL) {
            view.setTranslationX(getOffsetForRotation(rotation, view.getWidth(), view.getHeight(), mOrientation));
            view.setPivotX(view.getWidth() * 0.5f);
            view.setPivotY(0);
            view.setRotationY(rotation);
        } else {
            view.setTranslationY(getOffsetForRotation(rotation, view.getWidth(), view.getHeight(), mOrientation));
            view.setPivotY(view.getHeight() * 0.5f);
            view.setPivotX(0);
            view.setRotationX(-rotation);
        }
    }

    protected static final float getOffsetForRotation(float degrees, int width, int height, int mOrientation) {
        OFFSET_MATRIX.reset();
        OFFSET_CAMERA.save();
        if (mOrientation == OnPageDataListener.HORIZONTAL) {
            OFFSET_CAMERA.rotateY(Math.abs(degrees));
        } else {
            OFFSET_CAMERA.rotateX(-Math.abs(degrees));
        }
        OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
        OFFSET_CAMERA.restore();
        OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
        OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
        OFFSET_TEMP_FLOAT[0] = width;
        OFFSET_TEMP_FLOAT[1] = height;
        OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
        if (mOrientation == OnPageDataListener.HORIZONTAL) {
            return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
        } else {
            return (height - OFFSET_TEMP_FLOAT[1]) * (degrees > 0.0f ? 1.0f : -1.0f);
        }
    }
}

18 Source : Rotate3dAnimation.java
with Apache License 2.0
from akhasoft

/**
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
@SuppressWarnings("WeakerAccess")
public clreplaced Rotate3dAnimation extends Animation {

    private final float mFromDegrees;

    private final float mToDegrees;

    private final float mCenterX;

    private final float mCenterY;

    private final float mDepthZ;

    private final boolean mReverse;

    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, defined by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, @SuppressWarnings("SameParameterValue") float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

17 Source : FlipCard.java
with Apache License 2.0
from yiyuanliu

/**
 * Created by YiyuanLiu on 2016/12/15.
 */
public clreplaced FlipCard extends FrameLayout {

    private static final String TAG = "FlipCard";

    private Paint mScrimPaint;

    private Camera mCamera;

    private Matrix mMatrix;

    private boolean mIsForground;

    private float mPercent;

    public FlipCard(Context context) {
        this(context, null);
    }

    public FlipCard(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FlipCard(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScrimPaint = new Paint();
        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    public void setState(boolean isForground, float percent) {
        mIsForground = isForground;
        mPercent = percent;
    }

    @Override
    public void draw(Canvas canvas) {
        if (mPercent == 0) {
            super.draw(canvas);
            return;
        }
        final int height = canvas.getHeight();
        final int width = canvas.getWidth();
        final float percent = mPercent > 0 ? mPercent : -mPercent;
        if (mIsForground) {
            // clip card effect for forground view
            // draw part1
            int save1 = canvas.save();
            if (mPercent > 0) {
                canvas.clipRect(0, 0, width, height / 2);
            } else {
                canvas.clipRect(0, height / 2, width, height);
            }
            super.draw(canvas);
            canvas.restoreToCount(save1);
            // draw part2
            if (mPercent < 0) {
                canvas.clipRect(0, 0, width, height / 2);
            } else {
                canvas.clipRect(0, height / 2, width, height);
            }
            mCamera.save();
            mCamera.setLocation(0f, 0f, -80);
            mCamera.rotateX(mPercent * 180);
            mCamera.getMatrix(mMatrix);
            mCamera.restore();
            mMatrix.preTranslate(-width / 2, -height / 2);
            mMatrix.postTranslate(width / 2, height / 2);
            canvas.concat(mMatrix);
            super.draw(canvas);
            mScrimPaint.setColor(0x08000000);
            canvas.drawRect(0, 0, width, height, mScrimPaint);
        } else {
            // draw shadow for underground view
            final int scrimColor = (int) (0xff * (1 - percent * 2)) << 24;
            mScrimPaint.setColor(scrimColor);
            if (mPercent < 0) {
                canvas.clipRect(0, 0, width, height / 2);
            } else {
                canvas.clipRect(0, height / 2, width, height);
            }
            super.draw(canvas);
            canvas.drawRect(0, 0, width, height, mScrimPaint);
        }
    }
}

17 Source : SphereLayout.java
with MIT License
from thunderpunch

/**
 * Created by thunderpunch on 2017/2/20
 */
public clreplaced SphereLayout extends ViewGroup {

    public static final int HORIZONTAL = 0;

    public static final int VERTICAL = 1;

    private int mRadius;

    private Point mCenter;

    private Camera mCamera;

    private Matrix mMatrix;

    private float mDensity;

    private int mRotateDegree;

    private int mDirection;

    private float[] mValues = new float[9];

    private boolean mReverse;

    private boolean mHideBack;

    private ArrayList<View> mPositiveChildren, mNegativeChildren;

    private int mOrientation;

    private OnRotateListener mRotateListener;

    /**
     * @see #rotateDependsOn(SphereLayout)
     */
    private SphereLayout mDependency;

    /**
     * 自身翻转中心到依赖视图的翻转中心的偏移量
     *
     * @see #rotateDependsOn(SphereLayout)
     */
    private int[] mDependencyOffset;

    private boolean mCheckedDependencyOffset;

    public SphereLayout(Context context) {
        this(context, null);
    }

    public SphereLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SphereLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SphereLayout);
        // 球体半径
        mRadius = a.getDimensionPixelSize(R.styleable.SphereLayout_radius, 0);
        // 标记位于背面的视图是以Y轴水平翻转到达正面 或是以X轴竖直翻转可到达正面
        mOrientation = a.getInt(R.styleable.SphereLayout_snapOrientation, HORIZONTAL);
        // 是否隐藏处在背面的布局
        mHideBack = a.getBoolean(R.styleable.SphereLayout_hideBack, false);
        a.recycle();
        mCenter = new Point();
        mCamera = new Camera();
        mDependencyOffset = new int[2];
        // mCamera.setLocation(0, 0, -20);
        mMatrix = new Matrix();
        // depth为正的childview集合
        mPositiveChildren = new ArrayList<>();
        // depth为负的childview集合
        mNegativeChildren = new ArrayList<>();
        mDensity = getResources().getDisplayMetrics().density;
    }

    /**
     * @param hideBack 是否隐藏背面
     */
    public void hideBack(boolean hideBack) {
        if (mHideBack != hideBack) {
            mHideBack = hideBack;
            postInvalidate();
        }
    }

    /**
     * @param radius 球体半径
     */
    public void setRadius(int radius) {
        mRadius = radius;
        requestLayout();
    }

    public int getRadius() {
        return mRadius;
    }

    /**
     * @param isReverse 是否翻转
     */
    public void reverse(boolean isReverse) {
        if (isReverse != mReverse) {
            mReverse = isReverse;
            mRotateDegree = 0;
            invalidate();
        }
    }

    public boolean isReverse() {
        return mReverse;
    }

    public int getCenterX() {
        return mCenter.x;
    }

    public int getCenterY() {
        return mCenter.y;
    }

    /**
     * @param direction    翻转方向 (-180,180] 以布局中心为原点,向量与x轴正方向的夹角,顺加逆减
     * @param rotateDegree 翻转角度 (-180,180]
     */
    public void rotate(int direction, int rotateDegree) {
        mDirection = makeDirectionWithinRange(direction);
        mRotateDegree = makeRoatateDegreeWithinRange(rotateDegree);
        postInvalidate();
        if (mRotateListener != null) {
            mRotateListener.onRotate(direction, rotateDegree);
        }
    }

    /**
     * @param sphereLayout 翻转依赖
     */
    public void rotateDependsOn(SphereLayout sphereLayout) {
        mDependency = sphereLayout;
        mCheckedDependencyOffset = false;
        mDependency.mRotateListener = new OnRotateListener() {

            @Override
            public void onRotate(int direction, int degree) {
                rotate(direction, degree);
            }
        };
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mRadius == 0) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) {
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mRadius << 1, MeasureSpec.EXACTLY);
        }
        if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mRadius << 1, MeasureSpec.EXACTLY);
        }
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (lp.fitBounds) {
                    lp.depth = Math.max(Math.min(lp.depth, mRadius), -mRadius);
                    lp.bottomMargin = lp.leftMargin = lp.rightMargin = lp.topMargin = 0;
                    final int boundsSize = (int) Math.max(getMinimumBoundsSize(), 2 * Math.sqrt(mRadius * mRadius - lp.depth * lp.depth));
                    child.measure(MeasureSpec.makeMeasureSpec(boundsSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(boundsSize, MeasureSpec.EXACTLY));
                } else {
                    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                }
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenter.x = w >> 1;
        mCenter.y = h >> 1;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mPositiveChildren.clear();
        mNegativeChildren.clear();
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                final int width = child.getMeasuredWidth();
                final int height = child.getMeasuredHeight();
                int childLeft = (r - l - width) / 2 + lp.leftMargin - lp.rightMargin;
                int childTop = (b - t - height) / 2 + lp.topMargin - lp.bottomMargin;
                child.layout(childLeft, childTop, childLeft + width, childTop + height);
                if (lp.depth >= 0) {
                    mPositiveChildren.add(child);
                } else {
                    mNegativeChildren.add(child);
                }
            }
        }
        final Comparator<View> comparator = new Comparator<View>() {

            @Override
            public int compare(View o1, View o2) {
                Integer d0 = Math.abs(((LayoutParams) o1.getLayoutParams()).depth);
                Integer d1 = Math.abs(((LayoutParams) o2.getLayoutParams()).depth);
                return d0.compareTo(d1);
            }
        };
        // 按照depth绝对值排列绘制顺序
        Collections.sort(mPositiveChildren, comparator);
        Collections.sort(mNegativeChildren, comparator);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mRadius == 0) {
            super.dispatchDraw(canvas);
            return;
        }
        if (mDependency != null && !mCheckedDependencyOffset) {
            int[] location = new int[2];
            int[] dependencyLocation = new int[2];
            getLocationOnScreen(location);
            mDependency.getLocationOnScreen(dependencyLocation);
            mDependencyOffset[0] = dependencyLocation[0] + mDependency.getCenterX() - (location[0] + getCenterX());
            mDependencyOffset[1] = dependencyLocation[1] + mDependency.getCenterY() - (location[1] + getCenterY());
            mCheckedDependencyOffset = true;
        }
        if (!mReverse) {
            if (mRotateDegree > 90 || mRotateDegree <= -90) {
                drawChildren(canvas, mNegativeChildren, mPositiveChildren);
            } else {
                drawChildren(canvas, mPositiveChildren, mNegativeChildren);
            }
        } else {
            if (mRotateDegree >= 90 || mRotateDegree < -90) {
                drawChildren(canvas, mPositiveChildren, mNegativeChildren);
            } else {
                drawChildren(canvas, mNegativeChildren, mPositiveChildren);
            }
        }
    }

    private void drawChildren(Canvas canvas, List<View> frontChildren, List<View> backChildren) {
        if (!mHideBack) {
            final int c0 = backChildren.size();
            for (int i = c0 - 1; i >= 0; i--) {
                drawChild(canvas, backChildren.get(i));
            }
        }
        final int c1 = frontChildren.size();
        for (int i = 0; i < c1; i++) {
            drawChild(canvas, frontChildren.get(i));
        }
    }

    private void drawChild(Canvas canvas, View child) {
        final long drawingTime = getDrawingTime();
        final LayoutParams p = (LayoutParams) child.getLayoutParams();
        final int depth = mReverse ? -p.depth : p.depth;
        mCamera.save();
        mCamera.rotateY(mRotateDegree);
        mCamera.translate(0, 0, -depth);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        // fix camera bug
        mMatrix.getValues(mValues);
        mValues[6] = mValues[6] / mDensity;
        mValues[7] = mValues[7] / mDensity;
        mMatrix.setValues(mValues);
        mMatrix.postRotate(mDirection, 0, 0);
        mMatrix.postTranslate(mCenter.x + mDependencyOffset[0], mCenter.y + mDependencyOffset[1]);
        mMatrix.preRotate(-mDirection, 0, 0);
        mMatrix.preTranslate(-mCenter.x - mDependencyOffset[0], -mCenter.y - mDependencyOffset[1]);
        if (depth < 0) {
            if (mOrientation == HORIZONTAL) {
                mMatrix.preScale(-1, 1, mCenter.x, mCenter.y);
            } else if (mOrientation == VERTICAL) {
                mMatrix.preScale(1, -1, mCenter.x, mCenter.y);
            }
        }
        canvas.save();
        canvas.concat(mMatrix);
        drawChild(canvas, child, drawingTime);
        canvas.restore();
    }

    public int makeRoatateDegreeWithinRange(int degree) {
        while (degree <= -180) {
            degree += 360;
        }
        while (degree > 180) {
            degree -= 360;
        }
        return degree;
    }

    public int makeDirectionWithinRange(int direction) {
        while (direction <= -180) {
            direction += 360;
        }
        while (direction > 180) {
            direction -= 360;
        }
        return direction;
    }

    /**
     * @return 当fitBounds为true时, 该childview的最小宽高
     */
    public int getMinimumBoundsSize() {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getContext().getResources().getDisplayMetrics());
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        if (p instanceof LayoutParams) {
            return new LayoutParams((LayoutParams) p);
        } else if (p instanceof MarginLayoutParams) {
            return new LayoutParams((MarginLayoutParams) p);
        }
        return new LayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    public static clreplaced LayoutParams extends MarginLayoutParams {

        /**
         * 视图在z轴的位置
         * 该z轴以指向观察者的方向为正方向,与{@link Camera}的z轴方向相反
         * {@link SphereLayout}的直系子视图必须设置depth属性
         */
        public int depth;

        /**
         * 为true时,子视图会宽高适配当前所处{@link #depth}层级的圆的直径且无视自身margin属性
         */
        public boolean fitBounds;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.SphereLayout_Layout);
            depth = a.getLayoutDimension(R.styleable.SphereLayout_Layout_layout_depth, "layout_depth");
            fitBounds = a.getBoolean(R.styleable.SphereLayout_Layout_layout_fitBounds, false);
            a.recycle();
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(LayoutParams p) {
            super(p);
            depth = p.depth;
            fitBounds = p.fitBounds;
        }

        public LayoutParams(MarginLayoutParams p) {
            super(p);
        }

        public LayoutParams(ViewGroup.LayoutParams p) {
            super(p);
        }
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SphereSavedState ss = new SphereSavedState(superState);
        ss.radius = mRadius;
        ss.orientation = mOrientation;
        ss.hideBack = mHideBack;
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SphereSavedState ss = (SphereSavedState) state;
        mRadius = ss.radius;
        mOrientation = ss.orientation;
        mHideBack = ss.hideBack;
        super.onRestoreInstanceState(ss.getSuperState());
    }

    static clreplaced SphereSavedState extends BaseSavedState {

        int radius;

        int orientation;

        boolean hideBack;

        SphereSavedState(Parcelable superState) {
            super(superState);
        }

        /**
         * Constructor called from {@link #CREATOR}
         */
        private SphereSavedState(Parcel in) {
            super(in);
            radius = in.readInt();
            orientation = in.readInt();
            hideBack = in.readInt() == 0 ? false : true;
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(radius);
            out.writeInt(orientation);
            out.writeInt(hideBack ? 1 : 0);
        }

        public static final Creator<SphereSavedState> CREATOR = new Creator<SphereSavedState>() {

            public SphereSavedState createFromParcel(Parcel in) {
                return new SphereSavedState(in);
            }

            public SphereSavedState[] newArray(int size) {
                return new SphereSavedState[size];
            }
        };
    }

    private interface OnRotateListener {

        void onRotate(int direction, int degree);
    }
}

17 Source : FlipAnimation.java
with GNU Lesser General Public License v3.0
from starcor-company

/**
 * Created by hy on 2015/1/26.
 */
public clreplaced FlipAnimation implements IXulAnimation {

    Camera _camera = new Camera();

    Matrix _matrix = new Matrix();

    protected XulViewRender _render;

    float _angle = 0;

    public FlipAnimation(XulViewRender render) {
        this._render = render;
        _render.addAnimation(this);
    }

    @Override
    public boolean updateAnimation(long timestamp) {
        if (_render == null) {
            return false;
        }
        _angle += 3;
        _angle %= 360.0;
        _render.markDirtyView();
        return true;
    }

    public void setAngle(float angle) {
        _angle = angle;
    }

    public float getAngle() {
        return _angle;
    }

    public void preDraw(XulDC dc, float x, float y, float cx, float cy) {
        dc.save();
        _camera.save();
        _camera.rotateY(_angle);
        _camera.getMatrix(_matrix);
        _matrix.preTranslate(-x - cx / 2.0f, -y - cy / 2.0f);
        _matrix.postTranslate(+x + cx / 2.0f, y + cy / 2.0f);
        dc.setMatrix(_matrix);
    }

    public void postDraw(XulDC dc, float x, float y, float cx, float cy) {
        _camera.restore();
        dc.restore();
    }
}

17 Source : DiceLoadingView.java
with MIT License
from samlss

/**
 * @author SamLeung
 * @e-mail [email protected]
 * @github https://github.com/samlss
 * @csdn https://blog.csdn.net/Samlss
 * @description A dice 3D rotation loading view.
 */
public clreplaced DiceLoadingView extends ViewGroup {

    private final static int DEFAULT_DURATION = 2500;

    // 200 px
    private final static int DEFAULT_SIZE = 200;

    // The fixed child count.
    private final static int FIXED_CHILD_COUNT = 7;

    /**
     * The real width of this view.
     */
    private int mRealWidth;

    /**
     * The real height of this view.
     */
    private int mRealHeight;

    /**
     * The width of child, need to subtract {@link #getPaddingLeft()} ()}, {@link #getPaddingRight()}.
     */
    private int mChildWidth;

    /**
     * The height of child, need to subtract {@link #getPaddingTop()}, {@link #getPaddingBottom()}.
     */
    private int mChildHeight;

    private int mFirstSideDiceNumber = DiceView.NUMBER_ONE;

    private int mFirstSidePointColor = DiceView.DEFAULT_COLOR;

    private int mFirstSideDiceBgColor = DiceView.DEFAULT_BG_COLOR;

    private int mFirstSideDiceBorderColor = DiceView.DEFAULT_COLOR;

    private int mSecondSideDiceNumber = DiceView.NUMBER_FIVE;

    private int mSecondSidePointColor = DiceView.DEFAULT_COLOR;

    private int mSecondSideDiceBgColor = DiceView.DEFAULT_BG_COLOR;

    private int mSecondSideDiceBorderColor = DiceView.DEFAULT_COLOR;

    private int mThirdSideDiceNumber = DiceView.NUMBER_SIX;

    private int mThirdSidePointColor = DiceView.DEFAULT_COLOR;

    private int mThirdSideDiceBgColor = DiceView.DEFAULT_BG_COLOR;

    private int mThirdSideDiceBorderColor = DiceView.DEFAULT_COLOR;

    private int mFourthSideDiceNumber = DiceView.NUMBER_TWO;

    private int mFourthSidePointColor = DiceView.DEFAULT_COLOR;

    private int mFourthSideDiceBgColor = DiceView.DEFAULT_BG_COLOR;

    private int mFourthSideDiceBorderColor = DiceView.DEFAULT_COLOR;

    private Camera mCamera;

    private Matrix mMatrix;

    private ValueAnimator mValueAnimator;

    private int mAnimatedValue;

    private long mAnimatorPlayTime;

    private DiceView[] mDiceViews = new DiceView[FIXED_CHILD_COUNT];

    private TimeInterpolator mInterpolator = new AccelerateDecelerateInterpolator();

    private long mDuration = DEFAULT_DURATION;

    public DiceLoadingView(Context context) {
        this(context, null);
    }

    public DiceLoadingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DiceLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        parseAttr(attrs);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DiceLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        parseAttr(attrs);
        init();
    }

    private void parseAttr(AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.DiceLoadingView);
        mDuration = typedArray.getInteger(R.styleable.DiceLoadingView_animDuration, DEFAULT_DURATION);
        if (mDuration < 0) {
            mDuration = DEFAULT_DURATION;
        }
        int interpolatorValue = typedArray.getInt(R.styleable.DiceLoadingView_animInterpolator, 0);
        switch(interpolatorValue) {
            case 0:
                mInterpolator = new AccelerateDecelerateInterpolator();
                break;
            case 1:
                mInterpolator = new AccelerateInterpolator();
                break;
            case 2:
                mInterpolator = new DecelerateInterpolator();
                break;
            case 3:
                mInterpolator = new BounceInterpolator();
                break;
            case 4:
                mInterpolator = new CycleInterpolator(0.5f);
                break;
            case 5:
                mInterpolator = new LinearInterpolator();
                break;
            case 6:
                mInterpolator = new AnticipateOvershootInterpolator();
                break;
            case 7:
                mInterpolator = new AnticipateInterpolator();
                break;
            case 8:
                mInterpolator = new OvershootInterpolator();
                break;
            default:
                break;
        }
        mFirstSideDiceNumber = typedArray.getInteger(R.styleable.DiceLoadingView_firstSideDiceNumber, DiceView.NUMBER_ONE);
        mFirstSidePointColor = typedArray.getColor(R.styleable.DiceLoadingView_firstSideDicePointColor, DiceView.DEFAULT_COLOR);
        mFirstSideDiceBgColor = typedArray.getColor(R.styleable.DiceLoadingView_firstSideDiceBgColor, DiceView.DEFAULT_BG_COLOR);
        mFirstSideDiceBorderColor = typedArray.getColor(R.styleable.DiceLoadingView_firstSideDiceBorderColor, DiceView.DEFAULT_COLOR);
        mSecondSideDiceNumber = typedArray.getInteger(R.styleable.DiceLoadingView_secondSideDiceNumber, DiceView.NUMBER_FIVE);
        mSecondSidePointColor = typedArray.getColor(R.styleable.DiceLoadingView_secondSideDicePointColor, DiceView.DEFAULT_COLOR);
        mSecondSideDiceBgColor = typedArray.getColor(R.styleable.DiceLoadingView_secondSideDiceBgColor, DiceView.DEFAULT_BG_COLOR);
        mSecondSideDiceBorderColor = typedArray.getColor(R.styleable.DiceLoadingView_secondSideDiceBorderColor, DiceView.DEFAULT_COLOR);
        mThirdSideDiceNumber = typedArray.getInteger(R.styleable.DiceLoadingView_thirdSideDiceNumber, DiceView.NUMBER_SIX);
        mThirdSidePointColor = typedArray.getColor(R.styleable.DiceLoadingView_thirdSideDicePointColor, DiceView.DEFAULT_COLOR);
        mThirdSideDiceBgColor = typedArray.getColor(R.styleable.DiceLoadingView_thirdSideDiceBgColor, DiceView.DEFAULT_BG_COLOR);
        mThirdSideDiceBorderColor = typedArray.getColor(R.styleable.DiceLoadingView_thirdSideDiceBorderColor, DiceView.DEFAULT_COLOR);
        mFourthSideDiceNumber = typedArray.getInteger(R.styleable.DiceLoadingView_fourthSideDiceNumber, DiceView.NUMBER_TWO);
        mFourthSidePointColor = typedArray.getColor(R.styleable.DiceLoadingView_fourthSideDicePointColor, DiceView.DEFAULT_COLOR);
        mFourthSideDiceBgColor = typedArray.getColor(R.styleable.DiceLoadingView_fourthSideDiceBgColor, DiceView.DEFAULT_BG_COLOR);
        mFourthSideDiceBorderColor = typedArray.getColor(R.styleable.DiceLoadingView_fourthSideDiceBorderColor, DiceView.DEFAULT_COLOR);
        typedArray.recycle();
    }

    private void init() {
        mCamera = new Camera();
        mMatrix = new Matrix();
        addChildViews();
    }

    private void addChildViews() {
        mDiceViews[0] = new DiceView(getContext());
        mDiceViews[0].setNumber(mFourthSideDiceNumber);
        mDiceViews[0].setPointColor(mFourthSidePointColor);
        mDiceViews[0].setBgColor(mFourthSideDiceBgColor);
        mDiceViews[0].setBorderColor(mFourthSideDiceBorderColor);
        mDiceViews[1] = new DiceView(getContext());
        mDiceViews[1].setNumber(mFirstSideDiceNumber);
        mDiceViews[1].setPointColor(mFirstSidePointColor);
        mDiceViews[1].setBgColor(mFirstSideDiceBgColor);
        mDiceViews[1].setBorderColor(mFirstSideDiceBorderColor);
        mDiceViews[2] = new DiceView(getContext());
        mDiceViews[2].setNumber(mSecondSideDiceNumber);
        mDiceViews[2].setPointColor(mSecondSidePointColor);
        mDiceViews[2].setBgColor(mSecondSideDiceBgColor);
        mDiceViews[2].setBorderColor(mSecondSideDiceBorderColor);
        mDiceViews[3] = new DiceView(getContext());
        mDiceViews[3].setNumber(mThirdSideDiceNumber);
        mDiceViews[3].setPointColor(mThirdSidePointColor);
        mDiceViews[3].setBgColor(mThirdSideDiceBgColor);
        mDiceViews[3].setBorderColor(mThirdSideDiceBorderColor);
        mDiceViews[4] = new DiceView(getContext());
        mDiceViews[4].setNumber(mFourthSideDiceNumber);
        mDiceViews[4].setPointColor(mFourthSidePointColor);
        mDiceViews[4].setBgColor(mFourthSideDiceBgColor);
        mDiceViews[4].setBorderColor(mFourthSideDiceBorderColor);
        mDiceViews[5] = new DiceView(getContext());
        mDiceViews[5].setNumber(mFirstSideDiceNumber);
        mDiceViews[5].setPointColor(mFirstSidePointColor);
        mDiceViews[5].setBgColor(mFirstSideDiceBgColor);
        mDiceViews[5].setBorderColor(mFirstSideDiceBorderColor);
        mDiceViews[6] = new DiceView(getContext());
        mDiceViews[6].setNumber(mSecondSideDiceNumber);
        mDiceViews[6].setPointColor(mSecondSidePointColor);
        mDiceViews[6].setBgColor(mSecondSideDiceBgColor);
        mDiceViews[6].setBorderColor(mSecondSideDiceBorderColor);
        for (DiceView diceView : mDiceViews) {
            addView(diceView, -1);
        }
    }

    /**
     * In order not to cut off the dice border, check and set padding here.
     */
    private void checkPadding(int width, int height) {
        int minSize = Math.min(width, height);
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int defPadding = minSize / 8;
        if (paddingLeft < defPadding) {
            paddingLeft = defPadding;
        }
        if (paddingRight < defPadding) {
            paddingRight = defPadding;
        }
        if (paddingTop < defPadding) {
            paddingTop = defPadding;
        }
        if (paddingBottom < defPadding) {
            paddingBottom = defPadding;
        }
        setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    }

    @Override
    public void addView(View child, int index, LayoutParams params) {
        if (child instanceof DiceView == false) {
            return;
        }
        super.addView(child, index, params);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int w = widthSpecSize;
        int h = heightSpecSize;
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            w = DEFAULT_SIZE;
            h = DEFAULT_SIZE;
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            w = DEFAULT_SIZE;
            h = heightSpecSize;
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            w = widthSpecSize;
            h = DEFAULT_SIZE;
        }
        mRealWidth = w;
        mRealHeight = h;
        setMeasuredDimension(w, h);
        checkPadding(w, h);
        mChildWidth = w - getPaddingLeft() - getPaddingRight();
        mChildHeight = h - getPaddingTop() - getPaddingBottom();
        measureChildren(MeasureSpec.makeMeasureSpec(mRealWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mRealHeight, MeasureSpec.EXACTLY));
    }

    @Override
    protected void onLayout(boolean b, int left, int top, int right, int bottom) {
        int childLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                child.layout(childLeft, paddingTop, childLeft + child.getMeasuredWidth(), paddingTop + child.getMeasuredHeight());
                childLeft = childLeft + child.getMeasuredWidth();
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setupAnimator();
    }

    private void setupAnimator() {
        release();
        if (getChildCount() < FIXED_CHILD_COUNT) {
            return;
        }
        mValueAnimator = ValueAnimator.ofInt(0, mChildWidth * 4);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatedValue = (int) valueAnimator.getAnimatedValue();
                scrollTo(mAnimatedValue + mChildWidth, 0);
                invalidate();
            }
        });
        mValueAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationRepeat(Animator animation) {
                scrollTo(mChildWidth, 0);
            }
        });
        mValueAnimator.setInterpolator(mInterpolator);
        mValueAnimator.setDuration(mDuration);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.start();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        for (int i = 0; i < getChildCount(); i++) {
            drawChild(canvas, i, getChildAt(i));
        }
    }

    /**
     * Draw the child.
     *
     * @param canvas
     * @param index
     * @param child
     */
    private void drawChild(Canvas canvas, int index, View child) {
        int childLeft = mChildWidth * index + getPaddingLeft();
        int scrollX = getScrollX() + getPaddingLeft();
        if (scrollX + mChildWidth < childLeft) {
            return;
        }
        if (childLeft < scrollX - mChildWidth) {
            return;
        }
        float centerX = (scrollX > childLeft) ? childLeft + mChildWidth : childLeft;
        float centerY = mChildHeight / 2;
        float degree = -90 * (scrollX - childLeft) / mChildWidth;
        if (degree > 90 || degree < -90) {
            return;
        }
        canvas.save();
        mCamera.save();
        mCamera.rotateY(degree);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX, -centerY);
        mMatrix.postTranslate(centerX, centerY);
        canvas.concat(mMatrix);
        drawChild(canvas, child, getDrawingTime());
        canvas.restore();
    }

    /**
     * Pause the animation.
     */
    public void pause() {
        if (mValueAnimator != null && mValueAnimator.isRunning()) {
            mAnimatorPlayTime = mValueAnimator.getCurrentPlayTime();
            mValueAnimator.cancel();
        }
    }

    /**
     * Resume the animation.
     */
    public void resume() {
        if (mValueAnimator != null && !mValueAnimator.isRunning()) {
            mValueAnimator.setCurrentPlayTime(mAnimatorPlayTime);
            mValueAnimator.start();
        }
    }

    /**
     * Start the animation.
     */
    public void start() {
        mAnimatorPlayTime = 0;
        if (mValueAnimator != null) {
            mValueAnimator.start();
        }
    }

    /**
     * Cancel the animation.
     */
    public void stop() {
        if (mValueAnimator != null) {
            mValueAnimator.cancel();
        }
    }

    /**
     * Release this view when you do not need it.
     */
    public void release() {
        stop();
        if (mValueAnimator != null) {
            mValueAnimator.removeAllUpdateListeners();
            mValueAnimator.removeAllListeners();
        }
    }

    /**
     * Get the dice number of the first dice side.
     */
    public int getFirstSideDiceNumber() {
        return mFirstSideDiceNumber;
    }

    /**
     * Set the dice number{1-6} of the first dice side.
     */
    public void setFirstSideDiceNumber(int firstSideDiceNumber) {
        this.mFirstSideDiceNumber = firstSideDiceNumber;
        mDiceViews[1].setNumber(mFirstSideDiceNumber);
        mDiceViews[5].setNumber(mFirstSideDiceNumber);
    }

    /**
     * Get the point color of the first dice side.
     */
    public int getFirstSidePointColor() {
        return mFirstSidePointColor;
    }

    /**
     * Set the point color of the first dice side.
     */
    public void setFirstSidePointColor(int firstSidePointColor) {
        this.mFirstSidePointColor = firstSidePointColor;
        mDiceViews[1].setPointColor(mFirstSidePointColor);
        mDiceViews[5].setPointColor(mFirstSidePointColor);
    }

    /**
     * Get the bg color of the first dice side.
     */
    public int getFirstSideDiceBgColor() {
        return mFirstSideDiceBgColor;
    }

    /**
     * Set the bg color of the first dice side.
     */
    public void setFirstSideDiceBgColor(int firstSideDiceBgColor) {
        this.mFirstSideDiceBgColor = firstSideDiceBgColor;
        mDiceViews[1].setBgColor(mFirstSideDiceBgColor);
        mDiceViews[5].setBgColor(mFirstSideDiceBgColor);
    }

    /**
     * Get the border color of the first dice side.
     */
    public int getFirstSideDiceBorderColor() {
        return mFirstSideDiceBorderColor;
    }

    /**
     * Set the border color of the first dice side.
     */
    public void setFirstSideDiceBorderColor(int firstSideDiceBorderColor) {
        this.mFirstSideDiceBorderColor = firstSideDiceBorderColor;
        mDiceViews[1].setBorderColor(mFirstSideDiceBorderColor);
        mDiceViews[5].setBorderColor(mFirstSideDiceBorderColor);
    }

    /**
     * Set the dice number of the second dice side.
     */
    public int getSecondSideDiceNumber() {
        return mSecondSideDiceNumber;
    }

    /**
     * Set the dice number{1-6} of the second dice side.
     */
    public void setSecondSideDiceNumber(int secondSideDiceNumber) {
        this.mSecondSideDiceNumber = secondSideDiceNumber;
        mDiceViews[2].setNumber(mSecondSideDiceNumber);
        mDiceViews[6].setNumber(mSecondSideDiceNumber);
    }

    /**
     * Get the point color of the second dice side.
     */
    public int getSecondSidePointColor() {
        return mSecondSidePointColor;
    }

    /**
     * Set the point color of the second dice side.
     */
    public void setSecondSidePointColor(int secondSidePointColor) {
        this.mSecondSidePointColor = secondSidePointColor;
        mDiceViews[2].setPointColor(mSecondSidePointColor);
        mDiceViews[6].setPointColor(mSecondSidePointColor);
    }

    /**
     * Get the bg color of the second dice side.
     */
    public int getSecondSideDiceBgColor() {
        return mSecondSideDiceBgColor;
    }

    /**
     * Set the bg color of the second dice side.
     */
    public void setSecondSideDiceBgColor(int secondSideDiceBgColor) {
        this.mSecondSideDiceBgColor = secondSideDiceBgColor;
        mDiceViews[2].setBgColor(mSecondSideDiceBgColor);
        mDiceViews[6].setBgColor(mSecondSideDiceBgColor);
    }

    /**
     * Get the border color of the second dice side.
     */
    public int getSecondSideDiceBorderColor() {
        return mSecondSideDiceBorderColor;
    }

    /**
     * Set the border color of the second dice side.
     */
    public void setSecondSideDiceBorderColor(int secondSideDiceBorderColor) {
        this.mSecondSideDiceBorderColor = secondSideDiceBorderColor;
        mDiceViews[2].setBorderColor(mSecondSideDiceBorderColor);
        mDiceViews[6].setBorderColor(mSecondSideDiceBorderColor);
    }

    /**
     * Get the dice number of the third dice side.
     */
    public int getThirdSideDiceNumber() {
        return mThirdSideDiceNumber;
    }

    /**
     * Set the dice number{1-6} of the third dice side.
     */
    public void setThirdSideDiceNumber(int thirdSideDiceNumber) {
        this.mThirdSideDiceNumber = thirdSideDiceNumber;
        mDiceViews[3].setNumber(mThirdSideDiceNumber);
    }

    /**
     * Get the point color of the third dice side.
     */
    public int getThirdSidePointColor() {
        return mThirdSidePointColor;
    }

    /**
     * Set the point color of the third dice side.
     */
    public void setThirdSidePointColor(int thirdSidePointColor) {
        this.mThirdSidePointColor = thirdSidePointColor;
        mDiceViews[3].setPointColor(mThirdSidePointColor);
    }

    /**
     * Get the bg color of the third dice side.
     */
    public int getThirdSideDiceBgColor() {
        return mThirdSideDiceBgColor;
    }

    /**
     * Set the bg color of the third dice side.
     */
    public void setThirdSideDiceBgColor(int thirdSideDiceBgColor) {
        this.mThirdSideDiceBgColor = thirdSideDiceBgColor;
        mDiceViews[3].setBgColor(mThirdSideDiceBgColor);
    }

    /**
     * Get the border color of the third dice side.
     */
    public int getThirdSideDiceBorderColor() {
        return mThirdSideDiceBorderColor;
    }

    /**
     * Set the border color of the third dice side.
     */
    public void setThirdSideDiceBorderColor(int thirdSideDiceBorderColor) {
        this.mThirdSideDiceBorderColor = thirdSideDiceBorderColor;
        mDiceViews[3].setBorderColor(mThirdSideDiceBorderColor);
    }

    /**
     * Get the dice number of the fourth dice side.
     */
    public int getFourthSideDiceNumber() {
        return mFourthSideDiceNumber;
    }

    /**
     * Set the dice number{1-6} of the fourth dice side.
     */
    public void setFourthSideDiceNumber(int fourthSideDiceNumber) {
        this.mFourthSideDiceNumber = fourthSideDiceNumber;
        mDiceViews[0].setNumber(mFourthSideDiceNumber);
        mDiceViews[4].setNumber(mFourthSideDiceNumber);
    }

    /**
     * Get the point color of the fourth dice side.
     */
    public int getFourthSidePointColor() {
        return mFourthSidePointColor;
    }

    /**
     * Set the point color of the fourth dice side.
     */
    public void setFourthSidePointColor(int fourthSidePointColor) {
        this.mFourthSidePointColor = fourthSidePointColor;
        mDiceViews[0].setPointColor(mFourthSidePointColor);
        mDiceViews[4].setPointColor(mFourthSidePointColor);
    }

    /**
     * Get the bg color of the fourth dice side.
     */
    public int getFourthSideDiceBgColor() {
        return mFourthSideDiceBgColor;
    }

    /**
     * Set the bg color of the fourth dice side.
     */
    public void setFourthSideDiceBgColor(int fourthSideDiceBgColor) {
        this.mFourthSideDiceBgColor = fourthSideDiceBgColor;
        mDiceViews[0].setBgColor(mFourthSideDiceBgColor);
        mDiceViews[4].setBgColor(mFourthSideDiceBgColor);
    }

    /**
     * Get the border color of the fourth dice side.
     */
    public int getFourthSideDiceBorderColor() {
        return mFourthSideDiceBorderColor;
    }

    /**
     * Set the border color of the fourth dice side.
     */
    public void setFourthSideDiceBorderColor(int fourthSideDiceBorderColor) {
        this.mFourthSideDiceBorderColor = fourthSideDiceBorderColor;
        mDiceViews[0].setBorderColor(mFourthSideDiceBorderColor);
        mDiceViews[4].setBorderColor(mFourthSideDiceBorderColor);
    }

    /**
     * Get the animation's interpolator.
     */
    public TimeInterpolator getInterpolator() {
        return mInterpolator;
    }

    /**
     * Set the animation's interpolator.
     */
    public void setInterpolator(TimeInterpolator mInterpolator) {
        this.mInterpolator = mInterpolator;
        setupAnimator();
    }

    /**
     * Get the animation 's duration.
     */
    public long getDuration() {
        return mDuration;
    }

    /**
     * Set the animation 's duration.
     */
    public void setDuration(long duration) {
        this.mDuration = duration;
        setupAnimator();
    }
}

17 Source : CubeLoadingView.java
with MIT License
from samlss

/**
 * @author SamLeung
 * @e-mail [email protected]
 * @github https://github.com/samlss
 * @csdn https://blog.csdn.net/Samlss
 * @description A cube 3D rotation loading view.
 */
public clreplaced CubeLoadingView extends ViewGroup {

    // 200 px
    private final static int DEFAULT_SIZE = 200;

    // The fixed child count.
    private final static int FIXED_CHILD_COUNT = 5;

    private final static int DEFAULT_FIRST_COLOR = Color.parseColor("#F8C66B");

    private final static int DEFAULT_SECOND_COLOR = Color.parseColor("#00AACF");

    private final static int DEFAULT_THIRD_COLOR = Color.parseColor("#214C59");

    private final static int DEFAULT_FOURTH_COLOR = Color.parseColor("#00B39F");

    private int mWidth;

    private int mHeight;

    private Camera mCamera;

    private Matrix mMatrix;

    private ValueAnimator mValueAnimator;

    private int mAnimatedValue;

    private long mAnimatorPlayTime;

    private View mSide1View;

    private View mSide2View;

    private View mSide3View;

    private View mSide4View;

    private View mSide5View;

    private int mFirstSideColor = DEFAULT_FIRST_COLOR;

    private int mSecondSideColor = DEFAULT_SECOND_COLOR;

    private int mThirdSideColor = DEFAULT_THIRD_COLOR;

    private int mFourthSideColor = DEFAULT_FOURTH_COLOR;

    public CubeLoadingView(Context context) {
        this(context, null);
    }

    public CubeLoadingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CubeLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        parseAttr(attrs);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CubeLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        parseAttr(attrs);
        init();
    }

    private void parseAttr(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CubeLoadingView);
        mFirstSideColor = typedArray.getColor(R.styleable.CubeLoadingView_firstSideColor, DEFAULT_FIRST_COLOR);
        mSecondSideColor = typedArray.getInteger(R.styleable.CubeLoadingView_secondSideColor, DEFAULT_SECOND_COLOR);
        mThirdSideColor = typedArray.getInteger(R.styleable.CubeLoadingView_thirdSideColor, DEFAULT_THIRD_COLOR);
        mFourthSideColor = typedArray.getInteger(R.styleable.CubeLoadingView_fourthSideColor, DEFAULT_FOURTH_COLOR);
        typedArray.recycle();
    }

    private void init() {
        mCamera = new Camera();
        mMatrix = new Matrix();
        addChildViews();
    }

    private void addChildViews() {
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mSide1View = new View(getContext());
        mSide2View = new View(getContext());
        mSide3View = new View(getContext());
        mSide4View = new View(getContext());
        mSide5View = new View(getContext());
        mSide1View.setBackgroundColor(mFirstSideColor);
        mSide5View.setBackgroundColor(mFirstSideColor);
        mSide2View.setBackgroundColor(mSecondSideColor);
        mSide3View.setBackgroundColor(mThirdSideColor);
        mSide4View.setBackgroundColor(mFourthSideColor);
        addViewInLayout(mSide1View, -1, layoutParams);
        addViewInLayout(mSide2View, -1, layoutParams);
        addViewInLayout(mSide3View, -1, layoutParams);
        addViewInLayout(mSide4View, -1, layoutParams);
        addViewInLayout(mSide5View, -1, layoutParams);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int mWidth = DEFAULT_SIZE;
        int mHeight = DEFAULT_SIZE;
        boolean isWidthWrap = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
        boolean isHeightWrap = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
        if (!isWidthWrap && !isHeightWrap) {
            return;
        }
        setMeasuredDimension(isWidthWrap ? mWidth : widthSize, isHeightWrap ? mHeight : heightSize);
    }

    @Override
    protected void onLayout(boolean b, int left, int top, int right, int bottom) {
        int childTop = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                child.layout(0, childTop, child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
                childTop = childTop + child.getMeasuredHeight();
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        release();
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        setupAnimator();
    }

    private void setupAnimator() {
        if (getChildCount() < FIXED_CHILD_COUNT) {
            return;
        }
        mValueAnimator = ValueAnimator.ofInt(0, mHeight * 4);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatedValue = (int) valueAnimator.getAnimatedValue();
                scrollTo(0, mAnimatedValue);
                invalidate();
            }
        });
        mValueAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationRepeat(Animator animation) {
                scrollTo(0, 0);
            }
        });
        mValueAnimator.setInterpolator(new AnticipateOvershootInterpolator(0.8f));
        mValueAnimator.setDuration(2500);
        mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.start();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        for (int i = 0; i < getChildCount(); i++) {
            drawChild(canvas, i, getChildAt(i));
        }
    }

    /**
     * Draw the child.
     *
     * @param canvas
     * @param index
     * @param child
     */
    private void drawChild(Canvas canvas, int index, View child) {
        int childTop = mHeight * index;
        if (getScrollY() + mHeight < childTop) {
            return;
        }
        if (childTop < getScrollY() - mHeight) {
            return;
        }
        float centerX = mWidth / 2;
        float centerY = (getScrollY() > childTop) ? childTop + mHeight : childTop;
        float degree = 90 * (getScrollY() - childTop) / mHeight;
        if (degree > 90 || degree < -90) {
            return;
        }
        canvas.save();
        mCamera.save();
        mCamera.rotateX(degree);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX, -centerY);
        mMatrix.postTranslate(centerX, centerY);
        canvas.concat(mMatrix);
        drawChild(canvas, child, getDrawingTime());
        canvas.restore();
    }

    public int getFirstSideColor() {
        return mFirstSideColor;
    }

    public int getSecondSideColor() {
        return mSecondSideColor;
    }

    public int getThirdSideColor() {
        return mThirdSideColor;
    }

    public int getFourthSideColor() {
        return mFourthSideColor;
    }

    /**
     * Set the color of first side.
     */
    public void setFirstSideColor(int firstSideColor) {
        this.mFirstSideColor = firstSideColor;
        mSide1View.setBackgroundColor(mFirstSideColor);
        mSide5View.setBackgroundColor(mFirstSideColor);
        invalidate();
    }

    /**
     * Set the color of second side.
     */
    public void setSecondSideColor(int secondSideColor) {
        this.mSecondSideColor = secondSideColor;
        mSide2View.setBackgroundColor(mSecondSideColor);
        invalidate();
    }

    /**
     * Set the color of third side.
     */
    public void setThirdSideColor(int thirdSideColor) {
        this.mThirdSideColor = thirdSideColor;
        mSide3View.setBackgroundColor(mThirdSideColor);
        invalidate();
    }

    /**
     * Set the color of fourth side.
     */
    public void setFourthSideColor(int fourthSideColor) {
        this.mFourthSideColor = fourthSideColor;
        mSide4View.setBackgroundColor(mFourthSideColor);
        invalidate();
    }

    /**
     * Pause the animation.
     */
    public void pause() {
        if (mValueAnimator != null && mValueAnimator.isRunning()) {
            mAnimatorPlayTime = mValueAnimator.getCurrentPlayTime();
            mValueAnimator.cancel();
        }
    }

    /**
     * Resume the animation.
     */
    public void resume() {
        if (mValueAnimator != null && !mValueAnimator.isRunning()) {
            mValueAnimator.setCurrentPlayTime(mAnimatorPlayTime);
            mValueAnimator.start();
        }
    }

    /**
     * Start the animation.
     */
    public void start() {
        mAnimatorPlayTime = 0;
        if (mValueAnimator != null) {
            mValueAnimator.start();
        }
    }

    /**
     * Cancel the animation.
     */
    public void stop() {
        if (mValueAnimator != null) {
            mValueAnimator.cancel();
        }
    }

    /**
     * Release this view when you do not need it.
     */
    public void release() {
        stop();
        if (mValueAnimator != null) {
            mValueAnimator.removeAllUpdateListeners();
            mValueAnimator.removeAllListeners();
        }
    }
}

17 Source : ShuttersConsumer.java
with Apache License 2.0
from luckybilly

/**
 * looks like shutters open and close
 * @author billy.qi
 */
public clreplaced ShuttersConsumer extends SwipeConsumer {

    protected final Camera mCamera;

    protected Paint mPaint;

    protected boolean mHorizontalSwiping;

    protected int mBaseAlpha;

    protected int lastScreenDirection = DIRECTION_NONE;

    /**
     * internal mark: refreshBitmapRunnable is working or not
     */
    protected volatile boolean mRefreshing;

    protected volatile Bitmap[] mScreenshots;

    protected int mScrimColor;

    protected int mLeavesCount = 5;

    protected volatile boolean mRefreshable = true;

    protected boolean mWaitForScreenshot = true;

    /**
     * refresh rate: 30 frames per second
     */
    protected int refreshDelay = 1000 / 30;

    public ShuttersConsumer() {
        setReleaseMode(RELEASE_MODE_AUTO_OPEN_CLOSE);
        mCamera = new Camera();
        mCamera.setLocation(0, 0, -20);
        mPaint = new Paint();
    }

    @Override
    public void onDetachFromWrapper() {
        super.onDetachFromWrapper();
        setRefreshing(false);
        recycleScreenshots();
        layoutChildren();
    }

    @Override
    public void onSwipeAccepted(int activePointerId, boolean settling, float initialMotionX, float initialMotionY) {
        if (lastScreenDirection != mDirection) {
            recycleScreenshots();
        }
        lastScreenDirection = mDirection;
        lastRefreshTime = 0;
        if ((mCurSwipeDistanceX == 0 && mCurSwipeDistanceY == 0)) {
            int halfWidth = mWidth >> 1;
            int halfHeight = mHeight >> 1;
            mHorizontalSwiping = isHorizontalDirection();
            if (!mOpenDistanceSpecified) {
                if (mHorizontalSwiping) {
                    mOpenDistance = halfWidth;
                } else {
                    mOpenDistance = halfHeight;
                }
            }
        }
        super.onSwipeAccepted(activePointerId, settling, initialMotionX, initialMotionY);
        layoutChildren();
        if (!mRefreshing) {
            setRefreshing(true);
            SwipeUtil.runInThreadPool(refreshBitmapRunnable);
        }
    }

    private Runnable refreshWrapperRunnable = new Runnable() {

        @Override
        public void run() {
            layoutChildren();
            mWrapper.postInvalidate();
        }
    };

    private Runnable refreshBitmapRunnable = new Runnable() {

        @Override
        public void run() {
            refreshBitmap();
        }
    };

    private clreplaced ScreenshotCreateRunnable implements Runnable {

        int width, height;

        int index;

        Bitmap[] array;

        CountDownLatch latch;

        View srcView;

        int scrollX, scrollY;

        ScreenshotCreateRunnable(int width, int height, int index, Bitmap[] array, CountDownLatch latch, View srcView, int scrollX, int scrollY) {
            this.width = width;
            this.height = height;
            this.index = index;
            this.array = array;
            this.latch = latch;
            this.srcView = srcView;
            this.scrollX = scrollX;
            this.scrollY = scrollY;
        }

        @Override
        public void run() {
            boolean switchToMainThread = false;
            try {
                Bitmap screenshot = array[index];
                if (screenshot == null || screenshot.isRecycled() || screenshot.getWidth() != width || screenshot.getHeight() != height) {
                    screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                }
                Canvas canvas = new Canvas(screenshot);
                canvas.translate(-srcView.getScrollX() - scrollX, -srcView.getScrollY() - scrollY);
                // Draw background
                Drawable bgDrawable = srcView.getBackground();
                if (bgDrawable != null) {
                    bgDrawable.draw(canvas);
                }
                try {
                    srcView.draw(canvas);
                    array[index] = screenshot;
                } catch (Exception e) {
                    if (Looper.myLooper() != Looper.getMainLooper()) {
                        switchToMainThread = true;
                        srcView.post(this);
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
                if (!switchToMainThread) {
                    latch.countDown();
                }
            }
        }
    }

    private long lastRefreshTime;

    protected void refreshBitmap() {
        if (lastRefreshTime == 0) {
            lastRefreshTime = SystemClock.elapsedRealtime();
        }
        View v = mWrapper.getContentView();
        final int leavesCount = this.mLeavesCount;
        int width = (int) (mWidth * 1F / (mHorizontalSwiping ? leavesCount : 1) + 0.5F);
        int height = (int) (mHeight * 1F / (mHorizontalSwiping ? 1 : leavesCount) + 0.5F);
        int lastWidth = mHorizontalSwiping ? (mWidth - width * (leavesCount - 1)) : width;
        int lastHeight = mHorizontalSwiping ? height : (mHeight - height * (leavesCount - 1));
        // TODO reuse bitmap array. Tried to use buffer bitmap array, but a blink bug happens when refreshable enabled
        Bitmap[] array = new Bitmap[leavesCount];
        CountDownLatch latch = new CountDownLatch(leavesCount);
        int scrollX = 0, scrollY = 0;
        for (int i = 0; i < leavesCount; i++) {
            if (mHorizontalSwiping) {
                scrollX = width * i;
            } else {
                scrollY = height * i;
            }
            if (i == leavesCount - 1) {
                if (lastWidth <= 0 || lastHeight <= 0) {
                    latch.countDown();
                } else {
                    SwipeUtil.runInThreadPool(new ScreenshotCreateRunnable(lastWidth, lastHeight, i, array, latch, v, scrollX, scrollY));
                }
            } else {
                SwipeUtil.runInThreadPool(new ScreenshotCreateRunnable(width, height, i, array, latch, v, scrollX, scrollY));
            }
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!mSwiping && (mProgress <= 0 || mProgress >= 1)) {
            setRefreshing(false);
        }
        if (!mRefreshing) {
            return;
        }
        boolean hasNull = false;
        for (Bitmap bitmap : array) {
            if (bitmap == null) {
                hasNull = true;
                break;
            }
        }
        if (!hasNull) {
            this.mScreenshots = array;
        }
        v.post(refreshWrapperRunnable);
        if (mRefreshable) {
            long timePreplaced = SystemClock.elapsedRealtime() - lastRefreshTime;
            lastRefreshTime = SystemClock.elapsedRealtime();
            if (timePreplaced < refreshDelay) {
                v.postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        SwipeUtil.runInThreadPool(refreshBitmapRunnable);
                    }
                }, refreshDelay - timePreplaced);
            } else {
                SwipeUtil.runInThreadPool(refreshBitmapRunnable);
            }
        } else {
            setRefreshing(false);
        }
    }

    private void setRefreshing(boolean refreshing) {
        mRefreshing = refreshing;
    }

    private void layoutChildren() {
        View contentView = mWrapper.getContentView();
        if (mDirection == DIRECTION_NONE || mScreenshots == null && mWaitForScreenshot) {
            contentView.layout(0, 0, mWidth, mHeight);
            contentView.setVisibility(View.VISIBLE);
        } else {
            if (mRefreshable) {
                contentView.layout(-9999, -9999, mWidth - 9999, mHeight - 9999);
            } else {
                contentView.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        final Bitmap[] screenshots = this.mScreenshots;
        if (mDirection == DIRECTION_NONE || screenshots == null || screenshots.length == 0) {
            return;
        }
        if (mScrimColor != 0 && mBaseAlpha != 0) {
            canvas.drawRect(0, 0, mWidth, mHeight, mPaint);
        }
        int halfW = mWidth >> 1;
        int halfH = mHeight >> 1;
        int leafSize = (int) ((mHorizontalSwiping ? mWidth : mHeight) * 1F / screenshots.length + 0.5F);
        int halfLeafSize = leafSize >> 1;
        int dir = (mDirection == DIRECTION_LEFT || mDirection == DIRECTION_BOTTOM) ? 1 : -1;
        for (int i = 0; i < screenshots.length; i++) {
            Bitmap screenshot = screenshots[i];
            if (screenshot == null || screenshot.isRecycled()) {
                continue;
            }
            canvas.save();
            mCamera.save();
            if (mHorizontalSwiping) {
                canvas.translate(leafSize * i + halfLeafSize, halfH);
                mCamera.rotateY(dir * 90 * mProgress);
                mCamera.applyToCanvas(canvas);
                canvas.translate(-halfLeafSize, 0);
                canvas.drawBitmap(screenshot, 0, -halfH, null);
            } else {
                canvas.translate(halfW, leafSize * i + halfLeafSize);
                mCamera.rotateX(dir * 90 * mProgress);
                mCamera.applyToCanvas(canvas);
                canvas.translate(0, -halfLeafSize);
                canvas.drawBitmap(screenshot, -halfW, 0, null);
            }
            mCamera.restore();
            canvas.restore();
        }
    }

    @Override
    public boolean onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren();
        return true;
    }

    @Override
    protected void onClosed() {
        super.onClosed();
        recycleScreenshots();
        setRefreshing(false);
        layoutChildren();
    }

    protected void recycleScreenshots() {
        lastScreenDirection = DIRECTION_NONE;
        mScreenshots = null;
    }

    @Override
    protected void onDisplayDistanceChanged(int distanceXToDisplay, int distanceYToDisplay, int dx, int dy) {
        if (mScrimColor != 0 && mBaseAlpha != 0) {
            float progress = SmartSwipe.ensureBetween(mProgress, 0, 1F);
            int alpha = (int) (mBaseAlpha * (1 - progress));
            mPaint.setAlpha(alpha);
        }
        if (!mRefreshable) {
            mWrapper.postInvalidate();
        }
    }

    @Override
    public int clampDistanceHorizontal(int distanceX, int dx) {
        if (mScreenshots != null || !mWaitForScreenshot) {
            return super.clampDistanceHorizontal(distanceX, dx);
        }
        return 0;
    }

    @Override
    public int clampDistanceVertical(int distanceY, int dy) {
        if (mScreenshots != null || !mWaitForScreenshot) {
            return super.clampDistanceVertical(distanceY, dy);
        }
        return 0;
    }

    public int getScrimColor() {
        return mScrimColor;
    }

    public ShuttersConsumer setScrimColor(int scrimColor) {
        this.mScrimColor = scrimColor;
        this.mPaint.setColor(scrimColor);
        mBaseAlpha = (mScrimColor & 0xFF000000) >>> 24;
        return this;
    }

    public int getLeavesCount() {
        return mLeavesCount;
    }

    public ShuttersConsumer setLeavesCount(int leavesCount) {
        int newCount = SmartSwipe.ensureBetween(leavesCount, 1, 100);
        if (newCount != mLeavesCount) {
            this.mLeavesCount = newCount;
            recycleScreenshots();
        }
        return this;
    }

    public boolean isRefreshable() {
        return mRefreshable;
    }

    public ShuttersConsumer setRefreshable(boolean refreshable) {
        this.mRefreshable = refreshable;
        return this;
    }

    public boolean isWaitForScreenshot() {
        return mWaitForScreenshot;
    }

    /**
     * if content view draw coat too much time, wait for screenshot is useful
     * @param wait default is false, if set as true, do real swipe after screenshot has been done
     * @return this
     */
    public ShuttersConsumer setWaitForScreenshot(boolean wait) {
        this.mWaitForScreenshot = wait;
        return this;
    }

    public ShuttersConsumer setRefreshFrameRate(int frameRate) {
        frameRate = SmartSwipe.ensureBetween(frameRate, 1, 60);
        refreshDelay = 1000 / frameRate;
        return this;
    }
}

17 Source : FancyFlipView.java
with Apache License 2.0
from hencoder

public clreplaced FancyFlipView extends View {

    private static final float IMAGE_SIZE = Utils.dpToPixel(150);

    private static final float PADDING = Utils.dpToPixel(50);

    private static final float FLIP_ANGLE = 45;

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    Bitmap bitmap;

    Camera camera = new Camera();

    private float leftFlip;

    private float rightFlip;

    private float flipRotation;

    public float getLeftFlip() {
        return leftFlip;
    }

    public void setLeftFlip(float leftFlip) {
        this.leftFlip = leftFlip;
        invalidate();
    }

    public float getRightFlip() {
        return rightFlip;
    }

    public void setRightFlip(float rightFlip) {
        this.rightFlip = rightFlip;
        invalidate();
    }

    public float getFlipRotation() {
        return flipRotation;
    }

    public void setFlipRotation(float flipRotation) {
        this.flipRotation = flipRotation;
        invalidate();
    }

    public FancyFlipView(Context context) {
        super(context);
    }

    public FancyFlipView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FancyFlipView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    {
        bitmap = Utils.getAvatar(getResources(), (int) IMAGE_SIZE);
        camera.setLocation(0, 0, Utils.getCameraZ());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float offset = IMAGE_SIZE / 2 + PADDING;
        // 左半边
        camera.save();
        camera.rotateY(leftFlip * FLIP_ANGLE);
        canvas.save();
        canvas.translate(offset, offset);
        canvas.rotate(-flipRotation);
        camera.applyToCanvas(canvas);
        canvas.clipRect(0, -IMAGE_SIZE, -IMAGE_SIZE, IMAGE_SIZE);
        canvas.rotate(flipRotation);
        canvas.translate(-offset, -offset);
        canvas.drawBitmap(bitmap, PADDING, PADDING, paint);
        canvas.restore();
        camera.restore();
        // 右半边
        camera.save();
        camera.rotateY(-rightFlip * FLIP_ANGLE);
        canvas.save();
        canvas.translate(offset, offset);
        canvas.rotate(-flipRotation);
        camera.applyToCanvas(canvas);
        canvas.clipRect(0, -IMAGE_SIZE, IMAGE_SIZE, IMAGE_SIZE);
        canvas.rotate(flipRotation);
        canvas.translate(-offset, -offset);
        canvas.drawBitmap(bitmap, PADDING, PADDING, paint);
        canvas.restore();
        camera.restore();
    }
}

17 Source : CameraView.java
with Apache License 2.0
from hencoder

public clreplaced CameraView extends View {

    private static final float IMAGE_SIZE = Utils.dpToPixel(250);

    private static final float OFFSET = Utils.dpToPixel(80);

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    Bitmap bitmap;

    Camera camera = new Camera();

    public CameraView(Context context) {
        super(context);
    }

    public CameraView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CameraView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    {
        bitmap = Utils.getAvatar(getResources(), (int) IMAGE_SIZE);
        camera.rotateX(45);
        // 8 * 72 = 576
        camera.setLocation(0, 0, Utils.getCameraZ());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate((OFFSET + IMAGE_SIZE / 2), (OFFSET + IMAGE_SIZE / 2));
        camera.applyToCanvas(canvas);
        canvas.translate(-(OFFSET + IMAGE_SIZE / 2), -(OFFSET + IMAGE_SIZE / 2));
        canvas.drawBitmap(bitmap, OFFSET, OFFSET, paint);
        canvas.restore();
    }
}

17 Source : BmpOverturnView.java
with Apache License 2.0
from faith-hb

public clreplaced BmpOverturnView extends View {

    public static final int IMAGE_WIDTH = DensityUtil.dp2px(180);

    Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    Bitmap image;

    Camera mCamera = new Camera();

    float left = 0f, top = 0f;

    float topFlip = 0f;

    float bottomFlip = 0f;

    float flipRotation = 0f;

    // 将属性名单独包装下,便于外部和谐引用
    public String getPropIsTopFlip() {
        return "topFlip";
    }

    public String getPropIsBottomFlip() {
        return "bottomFlip";
    }

    public String getPropFlipRotation() {
        return "flipRotation";
    }

    public float getTopFlip() {
        return topFlip;
    }

    public void setTopFlip(float topFlip) {
        this.topFlip = topFlip;
        invalidate();
    }

    public float getBottomFlip() {
        return bottomFlip;
    }

    public void setBottomFlip(float bottomFlip) {
        this.bottomFlip = bottomFlip;
        invalidate();
    }

    public float getFlipRotation() {
        return flipRotation;
    }

    public void setFlipRotation(float flipRotation) {
        this.flipRotation = flipRotation;
        invalidate();
    }

    public void propReset() {
        setBottomFlip(0f);
        setTopFlip(0f);
        setFlipRotation(0f);
    }

    public BmpOverturnView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    {
        image = Util.getAvatar(getResources(), IMAGE_WIDTH);
        mCamera.setLocation(0, 0, Util.getZForCamera());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension((int) (IMAGE_WIDTH * 1.5f), (int) (IMAGE_WIDTH * 1.5f));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        super.onSizeChanged(w, h, oldW, oldH);
        left = (getWidth() - IMAGE_WIDTH) / 2;
        top = (getHeight() - IMAGE_WIDTH) / 2 - DensityUtil.dp2px(50);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 上半部分
        canvas.save();
        canvas.translate(left + IMAGE_WIDTH / 2, top + IMAGE_WIDTH / 2);
        canvas.rotate(-flipRotation);
        mCamera.save();
        mCamera.rotateX(topFlip);
        mCamera.applyToCanvas(canvas);
        mCamera.restore();
        canvas.clipRect(-IMAGE_WIDTH, -IMAGE_WIDTH, IMAGE_WIDTH, 0);
        canvas.rotate(flipRotation);
        canvas.translate(-(left + IMAGE_WIDTH / 2), -(top + IMAGE_WIDTH / 2));
        canvas.drawBitmap(image, left, top, mPaint);
        canvas.restore();
        // 下半部分
        canvas.save();
        canvas.translate(left + IMAGE_WIDTH / 2, top + IMAGE_WIDTH / 2);
        canvas.rotate(-flipRotation);
        mCamera.save();
        mCamera.rotateX(bottomFlip);
        mCamera.applyToCanvas(canvas);
        mCamera.restore();
        canvas.clipRect(-IMAGE_WIDTH, 0, IMAGE_WIDTH, IMAGE_WIDTH);
        canvas.rotate(flipRotation);
        canvas.translate(-(left + IMAGE_WIDTH / 2), -(top + IMAGE_WIDTH / 2));
        canvas.drawBitmap(image, left, top, mPaint);
        canvas.restore();
    }
}

16 Source : FaceFilterActivity.java
with Apache License 2.0
from gaetanozappi

public clreplaced FaceFilterActivity extends AppCompatActivity {

    TextGraphic mTextGraphic;

    private final Thread observer = new Thread("observer") {

        {
            setDaemon(true);
        }

        public void run() {
            while (!isInterrupted()) {
            /*
                TextGraphic mTextGraphic = new TextGraphic(mGraphicOverlay);
                mGraphicOverlay.add(mTextGraphic);*/
            // mTextGraphic.updateText(2);
            }
        }
    };

    private static final String TAG = "FaceTracker";

    private CameraSource mCameraSource = null;

    private int typeFace = 0;

    private int typeFlash = 0;

    private boolean flashmode = false;

    private Camera camera;

    private static final int[] MASK = { R.id.no_filter, R.id.hair, R.id.op, R.id.snap, R.id.glreplacedes2, R.id.glreplacedes3, R.id.glreplacedes4, R.id.glreplacedes5, R.id.mask, R.id.mask2, R.id.mask3, R.id.dog, R.id.cat2 };

    private CameraSourcePreview mPreview;

    private GraphicOverlay mGraphicOverlay;

    private static final int RC_HANDLE_GMS = 9001;

    // permission request codes need to be < 256
    private static final int RC_HANDLE_CAMERA_PERM = 2;

    // ==============================================================================================
    // Activity Methods
    // ==============================================================================================
    /**
     * Initializes the UI and initiates the creation of a face detector.
     */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_face_filter);
        mPreview = (CameraSourcePreview) findViewById(R.id.preview);
        mGraphicOverlay = (GraphicOverlay) findViewById(R.id.faceOverlay);
        // mTextGraphic = new TextGraphic(mGraphicOverlay);
        // mGraphicOverlay.add(mTextGraphic);
        ImageButton face = (ImageButton) findViewById(R.id.face);
        face.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                if (findViewById(R.id.scrollView).getVisibility() == GONE) {
                    findViewById(R.id.scrollView).setVisibility(View.VISIBLE);
                    ((ImageButton) findViewById(R.id.face)).setImageResource(R.drawable.face_select);
                } else {
                    findViewById(R.id.scrollView).setVisibility(GONE);
                    ((ImageButton) findViewById(R.id.face)).setImageResource(R.drawable.face);
                }
            }
        });
        ImageButton no_filter = (ImageButton) findViewById(R.id.no_filter);
        no_filter.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 0;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton hair = (ImageButton) findViewById(R.id.hair);
        hair.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 1;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton op = (ImageButton) findViewById(R.id.op);
        op.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 2;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton snap = (ImageButton) findViewById(R.id.snap);
        snap.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 3;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton glreplacedes2 = (ImageButton) findViewById(R.id.glreplacedes2);
        glreplacedes2.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 4;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton glreplacedes3 = (ImageButton) findViewById(R.id.glreplacedes3);
        glreplacedes3.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 5;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton glreplacedes4 = (ImageButton) findViewById(R.id.glreplacedes4);
        glreplacedes4.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 6;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton glreplacedes5 = (ImageButton) findViewById(R.id.glreplacedes5);
        glreplacedes5.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 7;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton mask = (ImageButton) findViewById(R.id.mask);
        mask.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 8;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton mask2 = (ImageButton) findViewById(R.id.mask2);
        mask2.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 9;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton mask3 = (ImageButton) findViewById(R.id.mask3);
        mask3.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 10;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton dog = (ImageButton) findViewById(R.id.dog);
        dog.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 11;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton cat2 = (ImageButton) findViewById(R.id.cat2);
        cat2.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background);
                typeFace = 12;
                findViewById(MASK[typeFace]).setBackgroundResource(R.drawable.round_background_select);
            }
        });
        ImageButton button = (ImageButton) findViewById(R.id.change);
        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
            }
        });
        final ImageButton flash = (ImageButton) findViewById(R.id.flash);
        flash.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                int blue;
                if (flashmode == false) {
                    flashmode = true;
                    blue = 0;
                } else {
                    flashmode = false;
                    blue = 255;
                }
                flash.setColorFilter(Color.argb(255, 255, 255, blue));
            }
        });
        ImageButton camera = (ImageButton) findViewById(R.id.camera);
        camera.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // takeImage();
                onPause();
            }
        });
        // Check for the camera permission before accessing the camera.  If the
        // permission is not granted yet, request permission.
        int rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (rc == PackageManager.PERMISSION_GRANTED) {
            createCameraSource();
        } else {
            requestCameraPermission();
        }
    }

    private void takeImage() {
        try {
            // openCamera(CameraInfo.CAMERA_FACING_BACK);
            // releaseCameraSource();
            // releaseCamera();
            // openCamera(CameraInfo.CAMERA_FACING_BACK);
            // setUpCamera(camera);
            // Thread.sleep(1000);
            mCameraSource.takePicture(null, new CameraSource.PictureCallback() {

                private File imageFile;

                @Override
                public void onPictureTaken(byte[] bytes) {
                    try {
                        // convert byte array into bitmap
                        Bitmap loadedImage = null;
                        Bitmap rotatedBitmap = null;
                        loadedImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                        // rotate Image
                        Matrix rotateMatrix = new Matrix();
                        rotateMatrix.postRotate(getWindowManager().getDefaultDisplay().getRotation());
                        rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0, loadedImage.getWidth(), loadedImage.getHeight(), rotateMatrix, false);
                        String state = Environment.getExternalStorageState();
                        File folder = null;
                        if (state.contains(Environment.MEDIA_MOUNTED)) {
                            folder = new File(Environment.getExternalStorageDirectory() + "/faceFilter");
                        } else {
                            folder = new File(Environment.getExternalStorageDirectory() + "/faceFilter");
                        }
                        boolean success = true;
                        if (!folder.exists()) {
                            success = folder.mkdirs();
                        }
                        if (success) {
                            java.util.Date date = new java.util.Date();
                            imageFile = new File(folder.getAbsolutePath() + File.separator + // + new Timestamp(date.getTime()).toString()
                            "Image.jpg");
                            imageFile.createNewFile();
                        } else {
                            Toast.makeText(getBaseContext(), "Image Not saved", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        ByteArrayOutputStream ostream = new ByteArrayOutputStream();
                        // save image into gallery
                        rotatedBitmap = resize(rotatedBitmap, 800, 600);
                        rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
                        FileOutputStream fout = new FileOutputStream(imageFile);
                        fout.write(ostream.toByteArray());
                        fout.close();
                        ContentValues values = new ContentValues();
                        values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
                        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
                        values.put(MediaStore.MediaColumns.DATA, imageFile.getAbsolutePath());
                        // add this
                        setResult(Activity.RESULT_OK);
                        finish();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception ex) {
        }
    }

    private Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
        if (maxHeight > 0 && maxWidth > 0) {
            int width = image.getWidth();
            int height = image.getHeight();
            float ratioBitmap = (float) width / (float) height;
            float ratioMax = (float) maxWidth / (float) maxHeight;
            int finalWidth = maxWidth;
            int finalHeight = maxHeight;
            if (ratioMax > 1) {
                finalWidth = (int) ((float) maxHeight * ratioBitmap);
            } else {
                finalHeight = (int) ((float) maxWidth / ratioBitmap);
            }
            image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
            return image;
        } else {
            return image;
        }
    }

    /**
     * Handles the requesting of the camera permission.  This includes
     * showing a "Snackbar" message of why the permission is needed then
     * sending the request.
     */
    private void requestCameraPermission() {
        Log.w(TAG, "Camera permission is not granted. Requesting permission");
        final String[] permissions = new String[] { Manifest.permission.CAMERA };
        if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
            ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
            return;
        }
        final Activity thisActivity = this;
        View.OnClickListener listener = new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                ActivityCompat.requestPermissions(thisActivity, permissions, RC_HANDLE_CAMERA_PERM);
            }
        };
        Snackbar.make(mGraphicOverlay, R.string.permission_camera_rationale, Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, listener).show();
    }

    /**
     * Creates and starts the camera.  Note that this uses a higher resolution in comparison
     * to other detection examples to enable the barcode detector to detect small barcodes
     * at long distances.
     */
    private void createCameraSource() {
        Context context = getApplicationContext();
        FaceDetector detector = new FaceDetector.Builder(context).setClreplacedificationType(FaceDetector.ALL_CLreplacedIFICATIONS).setLandmarkType(FaceDetector.ALL_LANDMARKS).setMode(FaceDetector.ACCURATE_MODE).build();
        detector.setProcessor(new MultiProcessor.Builder<>(new GraphicFaceTrackerFactory()).build());
        // new MultiProcessor.Builder<>(new GraphicTextTrackerFactory()).build();
        if (!detector.isOperational()) {
            // Note: The first time that an app using face API is installed on a device, GMS will
            // download a native library to the device in order to do detection.  Usually this
            // completes before the app is run for the first time.  But if that download has not yet
            // completed, then the above call will not detect any faces.
            // 
            // isOperational() can be used to check if the required native library is currently
            // available.  The detector will automatically become operational once the library
            // download completes on device.
            Log.w(TAG, "Face detector dependencies are not yet available.");
        }
        mCameraSource = new CameraSource.Builder(context, detector).setRequestedPreviewSize(640, 480).setAutoFocusEnabled(true).setFacing(CameraSource.CAMERA_FACING_BACK).setRequestedFps(30.0f).build();
    // observer.start();
    /*
        TextGraphic mTextGraphic = new TextGraphic(mGraphicOverlay);
        mGraphicOverlay.add(mTextGraphic);
        mTextGraphic.updateText(2);*/
    }

    /**
     * Restarts the camera.
     */
    @Override
    protected void onResume() {
        super.onResume();
        startCameraSource();
    }

    /**
     * Stops the camera.
     */
    @Override
    protected void onPause() {
        super.onPause();
        mPreview.stop();
    }

    /**
     * Releases the resources replacedociated with the camera source, the replacedociated detector, and the
     * rest of the processing pipeline.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mCameraSource != null) {
            mCameraSource.release();
        }
    }

    /**
     * Callback for the result from requesting permissions. This method
     * is invoked for every call on {@link #requestPermissions(String[], int)}.
     * <p>
     * <strong>Note:</strong> It is possible that the permissions request interaction
     * with the user is interrupted. In this case you will receive empty permissions
     * and results arrays which should be treated as a cancellation.
     * </p>
     *
     * @param requestCode  The request code preplaceded in {@link #requestPermissions(String[], int)}.
     * @param permissions  The requested permissions. Never null.
     * @param grantResults The grant results for the corresponding permissions
     *                     which is either {@link PackageManager#PERMISSION_GRANTED}
     *                     or {@link PackageManager#PERMISSION_DENIED}. Never null.
     * @see #requestPermissions(String[], int)
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode != RC_HANDLE_CAMERA_PERM) {
            Log.d(TAG, "Got unexpected permission result: " + requestCode);
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            return;
        }
        if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Camera permission granted - initialize the camera source");
            // we have permission, so create the camerasource
            createCameraSource();
            return;
        }
        Log.e(TAG, "Permission not granted: results len = " + grantResults.length + " Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)"));
        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int id) {
                finish();
            }
        };
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setreplacedle("Face Tracker sample").setMessage(R.string.no_camera_permission).setPositiveButton(R.string.ok, listener).show();
    }

    // ==============================================================================================
    // Camera Source Preview
    // ==============================================================================================
    /**
     * Starts or restarts the camera source, if it exists.  If the camera source doesn't exist yet
     * (e.g., because onResume was called before the camera source was created), this will be called
     * again when the camera source is created.
     */
    private void startCameraSource() {
        // check that the device has play services available.
        int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getApplicationContext());
        if (code != ConnectionResult.SUCCESS) {
            Dialog dlg = GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS);
            dlg.show();
        }
        if (mCameraSource != null) {
            try {
                mPreview.start(mCameraSource, mGraphicOverlay);
            } catch (IOException e) {
                Log.e(TAG, "Unable to start camera source.", e);
                mCameraSource.release();
                mCameraSource = null;
            }
        }
    }

    private clreplaced GraphicTextTrackerFactory implements MultiProcessor.Factory<String> {

        @Override
        public Tracker<String> create(String face) {
            return new GraphicTextTracker(mGraphicOverlay);
        }
    }

    private clreplaced GraphicTextTracker extends Tracker<String> {

        private GraphicOverlay mOverlay;

        private TextGraphic mTextGraphic;

        GraphicTextTracker(GraphicOverlay overlay) {
            mOverlay = overlay;
            mTextGraphic = new TextGraphic(overlay);
        }

        public void onUpdate() {
            mOverlay.add(mTextGraphic);
            mTextGraphic.updateText(3);
        }

        @Override
        public void onDone() {
            mOverlay.remove(mTextGraphic);
        }
    }

    // ==============================================================================================
    // Graphic Face Tracker
    // ==============================================================================================
    /**
     * Factory for creating a face tracker to be replacedociated with a new face.  The multiprocessor
     * uses this factory to create face trackers as needed -- one for each individual.
     */
    private clreplaced GraphicFaceTrackerFactory implements MultiProcessor.Factory<Face> {

        @Override
        public Tracker<Face> create(Face face) {
            return new GraphicFaceTracker(mGraphicOverlay);
        }
    }

    /**
     * Face tracker for each detected individual. This maintains a face graphic within the app's
     * replacedociated face overlay.
     */
    private clreplaced GraphicFaceTracker extends Tracker<Face> {

        private GraphicOverlay mOverlay;

        private FaceGraphic mFaceGraphic;

        GraphicFaceTracker(GraphicOverlay overlay) {
            mOverlay = overlay;
            mFaceGraphic = new FaceGraphic(overlay, typeFace);
        }

        /**
         * Start tracking the detected face instance within the face overlay.
         */
        @Override
        public void onNewItem(int faceId, Face item) {
            mFaceGraphic.setId(faceId);
        }

        /**
         * Update the position/characteristics of the face within the overlay.
         */
        @Override
        public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
            mOverlay.add(mFaceGraphic);
            mFaceGraphic.updateFace(face, typeFace);
        }

        /**
         * Hide the graphic when the corresponding face was not detected.  This can happen for
         * intermediate frames temporarily (e.g., if the face was momentarily blocked from
         * view).
         */
        @Override
        public void onMissing(FaceDetector.Detections<Face> detectionResults) {
            mOverlay.remove(mFaceGraphic);
        }

        /**
         * Called when the face is replacedumed to be gone for good. Remove the graphic annotation from
         * the overlay.
         */
        @Override
        public void onDone() {
            mOverlay.remove(mFaceGraphic);
        }
    }
}

16 Source : JazzyViewPager.java
with Apache License 2.0
from Demidong

public clreplaced JazzyViewPager extends ViewPager {

    public static final String TAG = "JazzyViewPager";

    float x = 0, y = 0;

    private boolean mEnabled = true;

    private boolean mFadeEnabled = false;

    private boolean mOutlineEnabled = false;

    public static int sOutlineColor = Color.WHITE;

    private TransitionEffect mEffect = TransitionEffect.Standard;

    private HashMap<Integer, Object> mObjs = new LinkedHashMap<Integer, Object>();

    private static final float SCALE_MAX = 0.5f;

    private static final float ZOOM_MAX = 0.5f;

    private static final float ROT_MAX = 15.0f;

    public enum TransitionEffect {

        Standard,
        Tablet,
        CubeIn,
        CubeOut,
        FlipVertical,
        FlipHorizontal,
        Stack,
        ZoomIn,
        ZoomOut,
        RotateUp,
        RotateDown,
        Accordion
    }

    private static final boolean API_11;

    static {
        API_11 = Build.VERSION.SDK_INT >= 11;
    }

    public JazzyViewPager(Context context) {
        this(context, null);
    }

    /**
     * 获得所有的自定义的样式
     *
     * @param context
     * @param attrs
     */
    @SuppressWarnings("incomplete-switch")
    public JazzyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setClipChildren(false);
        // now style everything!
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.JazzyViewPager);
        int effect = ta.getInt(R.styleable.JazzyViewPager_style, 0);
        String[] transitions = getResources().getStringArray(R.array.jazzy_effects);
        setTransitionEffect(TransitionEffect.valueOf(transitions[effect]));
        setFadeEnabled(ta.getBoolean(R.styleable.JazzyViewPager_fadeEnabled, false));
        setOutlineEnabled(ta.getBoolean(R.styleable.JazzyViewPager_outlineEnabled, false));
        setOutlineColor(ta.getColor(R.styleable.JazzyViewPager_outlineColor, Color.WHITE));
        switch(mEffect) {
            case Stack:
            case ZoomOut:
                setFadeEnabled(true);
        }
        ta.recycle();
    }

    public void setTransitionEffect(TransitionEffect effect) {
        mEffect = effect;
    // reset();
    }

    public void setPagingEnabled(boolean enabled) {
        mEnabled = enabled;
    }

    public void setFadeEnabled(boolean enabled) {
        mFadeEnabled = enabled;
    }

    public boolean getFadeEnabled() {
        return mFadeEnabled;
    }

    public void setOutlineEnabled(boolean enabled) {
        mOutlineEnabled = enabled;
        wrapWithOutlines();
    }

    public void setOutlineColor(int color) {
        sOutlineColor = color;
    }

    private void wrapWithOutlines() {
        for (int i = 0; i < getChildCount(); i++) {
            View v = getChildAt(i);
            if (!(v instanceof OutlineContainer)) {
                removeView(v);
                super.addView(wrapChild(v), i);
            }
        }
    }

    private View wrapChild(View child) {
        if (!mOutlineEnabled || child instanceof OutlineContainer)
            return child;
        OutlineContainer out = new OutlineContainer(getContext());
        out.setLayoutParams(generateDefaultLayoutParams());
        child.setLayoutParams(new OutlineContainer.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        out.addView(child);
        return out;
    }

    public void addView(View child) {
        super.addView(wrapChild(child));
    }

    public void addView(View child, int index) {
        super.addView(wrapChild(child), index);
    }

    public void addView(View child, LayoutParams params) {
        super.addView(wrapChild(child), params);
    }

    public void addView(View child, int width, int height) {
        super.addView(wrapChild(child), width, height);
    }

    public void addView(View child, int index, LayoutParams params) {
        super.addView(wrapChild(child), index, params);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        return mEnabled ? super.onInterceptTouchEvent(arg0) : false;
    }

    private State mState;

    private int oldPage;

    private View mLeft;

    private View mRight;

    private float mRot;

    private float mTrans;

    private float mScale;

    private enum State {

        IDLE, GOING_LEFT, GOING_RIGHT
    }

    // public void reset() {
    // resetPrivate();
    // int curr = getCurrenreplacedem();
    // onPageScrolled(curr, 0.0f, 0);
    // }
    // 
    // private void resetPrivate() {
    // for (int i = 0; i < getChildCount(); i++) {
    // View v = getChildAt(i);
    // // ViewHelper.setRotation(v, -ViewHelper.getRotation(v));
    // // ViewHelper.setRotationX(v, -ViewHelper.getRotationX(v));
    // // ViewHelper.setRotationY(v, -ViewHelper.getRotationY(v));
    // //
    // // ViewHelper.setTranslationX(v, -ViewHelper.getTranslationX(v));
    // // ViewHelper.setTranslationY(v, -ViewHelper.getTranslationY(v));
    // 
    // ViewHelper.setRotation(v, 0);
    // ViewHelper.setRotationX(v, 0);
    // ViewHelper.setRotationY(v, 0);
    // 
    // ViewHelper.setTranslationX(v, 0);
    // ViewHelper.setTranslationY(v, 0);
    // 
    // ViewHelper.setAlpha(v, 1.0f);
    // 
    // ViewHelper.setScaleX(v, 1.0f);
    // ViewHelper.setScaleY(v, 1.0f);
    // 
    // ViewHelper.setPivotX(v, 0);
    // ViewHelper.setPivotY(v, 0);
    // 
    // logState(v, "Child " + i);
    // }
    // }
    private void logState(View v, String replacedle) {
        Log.v(TAG, replacedle + ": ROT (" + ViewHelper.getRotation(v) + ", " + ViewHelper.getRotationX(v) + ", " + ViewHelper.getRotationY(v) + "), TRANS (" + ViewHelper.getTranslationX(v) + ", " + ViewHelper.getTranslationY(v) + "), SCALE (" + ViewHelper.getScaleX(v) + ", " + ViewHelper.getScaleY(v) + "), ALPHA " + ViewHelper.getAlpha(v));
    }

    protected void animateScroll(int position, float positionOffset) {
        if (mState != State.IDLE) {
            mRot = (float) (1 - Math.cos(2 * Math.PI * positionOffset)) / 2 * 30.0f;
            ViewHelper.setRotationY(this, mState == State.GOING_RIGHT ? mRot : -mRot);
            ViewHelper.setPivotX(this, getMeasuredWidth() * 0.5f);
            ViewHelper.setPivotY(this, getMeasuredHeight() * 0.5f);
        }
    }

    protected void animateTablet(View left, View right, float positionOffset) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = 30.0f * positionOffset;
                mTrans = getOffsetXForRotation(mRot, left.getMeasuredWidth(), left.getMeasuredHeight());
                ViewHelper.setPivotX(left, left.getMeasuredWidth() / 2);
                ViewHelper.setPivotY(left, left.getMeasuredHeight() / 2);
                ViewHelper.setTranslationX(left, mTrans);
                ViewHelper.setRotationY(left, mRot);
                logState(left, "Left");
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = -30.0f * (1 - positionOffset);
                mTrans = getOffsetXForRotation(mRot, right.getMeasuredWidth(), right.getMeasuredHeight());
                ViewHelper.setPivotX(right, right.getMeasuredWidth() * 0.5f);
                ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                ViewHelper.setTranslationX(right, mTrans);
                ViewHelper.setRotationY(right, mRot);
                logState(right, "Right");
            }
        }
    }

    private void animateAccordion(View left, View right, float positionOffset) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                ViewHelper.setPivotX(left, left.getMeasuredWidth());
                ViewHelper.setPivotY(left, 0);
                ViewHelper.setScaleX(left, 1 - positionOffset);
            }
            if (right != null) {
                manageLayer(right, true);
                ViewHelper.setPivotX(right, 0);
                ViewHelper.setPivotY(right, 0);
                ViewHelper.setScaleX(right, positionOffset);
            }
        }
    }

    private void animateCubeIn(View left, View right, float positionOffset) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = 90.0f * positionOffset;
                Log.e(TAG, "left.getMeasuredWidth()= " + left.getMeasuredWidth() + " ,left.getMeasuredHeight() = " + left.getMeasuredHeight());
                ViewHelper.setPivotX(left, left.getMeasuredWidth());
                ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
                ViewHelper.setScaleX(left, 1 - positionOffset);
                ViewHelper.setScaleY(left, 1 - positionOffset);
                ViewHelper.setRotationY(left, mRot);
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = -90.0f * (1 - positionOffset);
                Log.e(TAG, "right.getMeasuredWidth()= " + right.getMeasuredWidth() + " ,right.getMeasuredHeight() = " + right.getMeasuredHeight());
                ViewHelper.setPivotX(right, 0);
                ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                ViewHelper.setScaleX(right, positionOffset);
                ViewHelper.setScaleY(right, positionOffset);
                ViewHelper.setRotationY(right, mRot);
            }
        }
    }

    private void animateCubeOut(View left, View right, float positionOffset) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = -70.0f * positionOffset;
                ViewHelper.setPivotX(left, left.getMeasuredWidth());
                ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
                // ViewHelper.setScaleX(left,1 - positionOffset);
                // ViewHelper.setScaleY(left,1 - positionOffset);
                ViewHelper.setRotationY(left, mRot);
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = 70.0f * (1 - positionOffset);
                ViewHelper.setPivotX(right, 0);
                ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                // ViewHelper.setScaleX(right,positionOffset);
                // ViewHelper.setScaleY(right,positionOffset);
                ViewHelper.setRotationY(right, mRot);
            }
        }
    }

    private void animateZoom(View left, View right, float positionOffset, boolean in) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mScale = in ? ZOOM_MAX + (1 - ZOOM_MAX) * (1 - positionOffset) : 1 + ZOOM_MAX - ZOOM_MAX * (1 - positionOffset);
                ViewHelper.setPivotX(left, left.getMeasuredWidth());
                ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
                ViewHelper.setScaleX(left, mScale);
                ViewHelper.setScaleY(left, mScale);
            }
            if (right != null) {
                manageLayer(right, true);
                mScale = in ? ZOOM_MAX + (1 - ZOOM_MAX) * positionOffset : 1 + ZOOM_MAX - ZOOM_MAX * positionOffset;
                ViewHelper.setPivotX(right, 0);
                ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                ViewHelper.setScaleX(right, mScale);
                ViewHelper.setScaleY(right, mScale);
            }
        }
    }

    private void animateRotate(View left, View right, float positionOffset, boolean up) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = (up ? 1 : -1) * (ROT_MAX * positionOffset);
                mTrans = (up ? -1 : 1) * (float) (getMeasuredHeight() - getMeasuredHeight() * Math.cos(mRot * Math.PI / 180.0f));
                ViewHelper.setPivotX(left, left.getMeasuredWidth() * 0.5f);
                ViewHelper.setPivotY(left, up ? 0 : left.getMeasuredHeight());
                ViewHelper.setTranslationY(left, mTrans);
                ViewHelper.setRotation(left, mRot);
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = (up ? 1 : -1) * (-ROT_MAX + ROT_MAX * positionOffset);
                mTrans = (up ? -1 : 1) * (float) (getMeasuredHeight() - getMeasuredHeight() * Math.cos(mRot * Math.PI / 180.0f));
                ViewHelper.setPivotX(right, right.getMeasuredWidth() * 0.5f);
                ViewHelper.setPivotY(right, up ? 0 : right.getMeasuredHeight());
                ViewHelper.setTranslationY(right, mTrans);
                ViewHelper.setRotation(right, mRot);
            }
        }
    }

    private void animateFlipHorizontal(View left, View right, float positionOffset, int positionOffsetPixels) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = 180.0f * positionOffset;
                if (mRot > 90.0f) {
                    left.setVisibility(View.INVISIBLE);
                } else {
                    if (left.getVisibility() == View.INVISIBLE)
                        left.setVisibility(View.VISIBLE);
                    mTrans = positionOffsetPixels;
                    ViewHelper.setPivotX(left, left.getMeasuredWidth() * 0.5f);
                    ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
                    ViewHelper.setTranslationX(left, mTrans);
                    ViewHelper.setRotationY(left, mRot);
                }
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = -180.0f * (1 - positionOffset);
                if (mRot < -90.0f) {
                    right.setVisibility(View.INVISIBLE);
                } else {
                    if (right.getVisibility() == View.INVISIBLE)
                        right.setVisibility(View.VISIBLE);
                    mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
                    ViewHelper.setPivotX(right, right.getMeasuredWidth() * 0.5f);
                    ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                    ViewHelper.setTranslationX(right, mTrans);
                    ViewHelper.setRotationY(right, mRot);
                }
            }
        }
    }

    private void animateFlipVertical(View left, View right, float positionOffset, int positionOffsetPixels) {
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                mRot = 180.0f * positionOffset;
                if (mRot > 90.0f) {
                    left.setVisibility(View.INVISIBLE);
                } else {
                    if (left.getVisibility() == View.INVISIBLE)
                        left.setVisibility(View.VISIBLE);
                    mTrans = positionOffsetPixels;
                    ViewHelper.setPivotX(left, left.getMeasuredWidth() * 0.5f);
                    ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
                    ViewHelper.setTranslationX(left, mTrans);
                    ViewHelper.setRotationX(left, mRot);
                }
            }
            if (right != null) {
                manageLayer(right, true);
                mRot = -180.0f * (1 - positionOffset);
                if (mRot < -90.0f) {
                    right.setVisibility(View.INVISIBLE);
                } else {
                    if (right.getVisibility() == View.INVISIBLE)
                        right.setVisibility(View.VISIBLE);
                    mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
                    ViewHelper.setPivotX(right, right.getMeasuredWidth() * 0.5f);
                    ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
                    ViewHelper.setTranslationX(right, mTrans);
                    ViewHelper.setRotationX(right, mRot);
                }
            }
        }
    }

    protected void animateStack(View left, View right, float positionOffset, int positionOffsetPixels) {
        if (mState != State.IDLE) {
            if (right != null) {
                manageLayer(right, true);
                mScale = (1 - SCALE_MAX) * positionOffset + SCALE_MAX;
                mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
                ViewHelper.setScaleX(right, mScale);
                ViewHelper.setScaleY(right, mScale);
                ViewHelper.setTranslationX(right, mTrans);
            }
            if (left != null) {
                left.bringToFront();
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void manageLayer(View v, boolean enableHardware) {
        if (!API_11)
            return;
        int layerType = enableHardware ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE;
        if (layerType != v.getLayerType())
            v.setLayerType(layerType, null);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void disableHardwareLayer() {
        if (!API_11)
            return;
        View v;
        for (int i = 0; i < getChildCount(); i++) {
            v = getChildAt(i);
            if (v.getLayerType() != View.LAYER_TYPE_NONE)
                v.setLayerType(View.LAYER_TYPE_NONE, null);
        }
    }

    private Matrix mMatrix = new Matrix();

    private Camera mCamera = new Camera();

    private float[] mTempFloat2 = new float[2];

    protected float getOffsetXForRotation(float degrees, int width, int height) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateY(Math.abs(degrees));
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
        mMatrix.postTranslate(width * 0.5f, height * 0.5f);
        mTempFloat2[0] = width;
        mTempFloat2[1] = height;
        mMatrix.mapPoints(mTempFloat2);
        return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
    }

    protected void animateFade(View left, View right, float positionOffset) {
        if (left != null) {
            ViewHelper.setAlpha(left, 1 - positionOffset);
        }
        if (right != null) {
            ViewHelper.setAlpha(right, positionOffset);
        }
    }

    protected void animateOutline(View left, View right) {
        if (!(left instanceof OutlineContainer))
            return;
        if (mState != State.IDLE) {
            if (left != null) {
                manageLayer(left, true);
                ((OutlineContainer) left).setOutlineAlpha(1.0f);
            }
            if (right != null) {
                manageLayer(right, true);
                ((OutlineContainer) right).setOutlineAlpha(1.0f);
            }
        } else {
            if (left != null)
                ((OutlineContainer) left).start();
            if (right != null)
                ((OutlineContainer) right).start();
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // Log.e(TAG, "position= " + position + " ,positionOffset = "
        // + positionOffset + ",positionOffsetPixels =  "
        // + positionOffsetPixels);
        if (mState == State.IDLE && positionOffset > 0) {
            oldPage = getCurrenreplacedem();
            mState = position == oldPage ? State.GOING_RIGHT : State.GOING_LEFT;
        }
        boolean goingRight = position == oldPage;
        if (mState == State.GOING_RIGHT && !goingRight)
            mState = State.GOING_LEFT;
        else if (mState == State.GOING_LEFT && goingRight)
            mState = State.GOING_RIGHT;
        float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
        // mLeft = getChildAt(position);
        // mRight = getChildAt(position+1);
        mLeft = findViewFromObject(position);
        mRight = findViewFromObject(position + 1);
        if (mFadeEnabled)
            animateFade(mLeft, mRight, effectOffset);
        if (mOutlineEnabled)
            animateOutline(mLeft, mRight);
        switch(mEffect) {
            case Standard:
                // animateScroll(position,effectOffset);
                break;
            case Tablet:
                animateTablet(mLeft, mRight, effectOffset);
                break;
            case CubeIn:
                animateCubeIn(mLeft, mRight, effectOffset);
                break;
            case CubeOut:
                animateCubeOut(mLeft, mRight, effectOffset);
                break;
            case FlipVertical:
                animateFlipVertical(mLeft, mRight, positionOffset, positionOffsetPixels);
                break;
            case FlipHorizontal:
                animateFlipHorizontal(mLeft, mRight, effectOffset, positionOffsetPixels);
            case Stack:
                animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
                break;
            case ZoomIn:
                animateZoom(mLeft, mRight, effectOffset, true);
                break;
            case ZoomOut:
                animateZoom(mLeft, mRight, effectOffset, false);
                break;
            case RotateUp:
                animateRotate(mLeft, mRight, effectOffset, true);
                break;
            case RotateDown:
                animateRotate(mLeft, mRight, effectOffset, false);
                break;
            case Accordion:
                animateAccordion(mLeft, mRight, effectOffset);
                break;
        }
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);
        if (effectOffset == 0) {
            disableHardwareLayer();
            mState = State.IDLE;
        }
    }

    private boolean isSmall(float positionOffset) {
        return Math.abs(positionOffset) < 0.0001;
    }

    public void setObjectForPosition(Object obj, int position) {
        mObjs.put(Integer.valueOf(position), obj);
    }

    public View findViewFromObject(int position) {
        Object o = mObjs.get(Integer.valueOf(position));
        if (o == null) {
            return null;
        }
        PagerAdapter a = getAdapter();
        View v;
        for (int i = 0; i < getChildCount(); i++) {
            v = getChildAt(i);
            if (a.isViewFromObject(v, o))
                return v;
        }
        return null;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch(ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                x = ev.getX();
                y = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(ev.getX() - x) > Math.abs(ev.getY() - y)) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                } else {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.onTouchEvent(ev);
    }
}

16 Source : RotateView.java
with Apache License 2.0
from CoderLengary

/**
 * Created by CoderLengary
 */
public clreplaced RotateView extends android.support.v7.widget.AppCompatImageView {

    private int canvasDegree;

    public int getCanvasDegree() {
        return canvasDegree;
    }

    public void setCanvasDegree(int canvasDegree) {
        this.canvasDegree = canvasDegree;
        invalidate();
    }

    public int getLeftCameraDegree() {
        return leftCameraDegree;
    }

    public void setLeftCameraDegree(int leftCameraDegree) {
        this.leftCameraDegree = leftCameraDegree;
        invalidate();
    }

    public int getRightCameraDegree() {
        return rightCameraDegree;
    }

    public void setRightCameraDegree(int rightCameraDegree) {
        this.rightCameraDegree = rightCameraDegree;
        invalidate();
    }

    private int leftCameraDegree;

    private int rightCameraDegree;

    private Bitmap bitmap;

    Paint paint;

    Camera camera;

    private int bitmapWidth;

    private int bitmapHeight;

    AnimatorSet animatorSet;

    public RotateView(Context context) {
        super(context);
    }

    public RotateView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RotateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RotateView);
        BitmapDrawable bitmapDrawable = (BitmapDrawable) array.getDrawable(R.styleable.RotateView_viewBackgound2);
        array.recycle();
        if (bitmapDrawable != null) {
            bitmap = bitmapDrawable.getBitmap();
            byte[] bytes = BitmapUtil.bitmap2Bytes(bitmap);
            bitmap = BitmapUtil.resizeBitmapBytes(bytes);
        } else {
            bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        }
        camera = new Camera();
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        float newZ = -metrics.density * 6;
        camera.setLocation(0, 0, newZ);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        ObjectAnimator rotateAnimator = ObjectAnimator.ofInt(this, "canvasDegree", 0, 270);
        ObjectAnimator leftCameraAnimator = ObjectAnimator.ofInt(this, "leftCameraDegree", 0, 45);
        ObjectAnimator rightCameraAnimator = ObjectAnimator.ofInt(this, "rightCameraDegree", 0, -45);
        rotateAnimator.setDuration(2000);
        leftCameraAnimator.setDuration(1000);
        rightCameraAnimator.setDuration(1000);
        animatorSet = new AnimatorSet();
        animatorSet.playSequentially(rightCameraAnimator, rotateAnimator, leftCameraAnimator);
        animatorSet.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        animatorSet.cancel();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        bitmapWidth = bitmap.getWidth();
        bitmapHeight = bitmap.getHeight();
        int x = width / 2 - bitmapWidth / 2;
        int y = height / 2 - bitmapHeight / 2;
        // 右半部分绘制
        camera.save();
        canvas.save();
        canvas.translate(width / 2, height / 2);
        canvas.rotate(-canvasDegree);
        camera.rotateY(rightCameraDegree);
        camera.applyToCanvas(canvas);
        canvas.clipRect(0, -height, width, height);
        canvas.rotate(canvasDegree);
        canvas.translate(-width / 2, -height / 2);
        canvas.drawBitmap(bitmap, x, y, paint);
        canvas.restore();
        camera.restore();
        // 左半部分绘制
        camera.save();
        canvas.save();
        canvas.translate(width / 2, height / 2);
        canvas.rotate(-canvasDegree);
        camera.rotateY(leftCameraDegree);
        camera.applyToCanvas(canvas);
        canvas.clipRect(-width, -height, 0, height);
        canvas.rotate(canvasDegree);
        canvas.translate(-width / 2, -height / 2);
        canvas.drawBitmap(bitmap, x, y, paint);
        canvas.restore();
        camera.restore();
    }
}

16 Source : DashView.java
with Apache License 2.0
from aohanyao

/**
 * Created by 江俊超 on 2018/11/3.
 * Version:1.0
 * Description: 转动的图片
 * ChangeLog:
 */
public clreplaced DashView extends View {

    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private final float BITMAP_SIZE = Utils.dp2px(200);

    private Camera mCamera;

    private Bitmap mBitmap;

    private float mCenterY;

    private float mCenterX;

    private float degrees = 0;

    private float degX = 0;

    private float degY = 0;

    private AnimatorSet animatorSet;

    public DashView(Context context) {
        super(context);
    }

    public DashView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DashView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    {
        mBitmap = Utils.getDrawableBitmap(getContext(), R.drawable.icon_android_road, BITMAP_SIZE);
        mCamera = new Camera();
        mCamera.setLocation(0, 0, -8 * getResources().getDisplayMetrics().density);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = BITMAP_SIZE;
        mCenterY = BITMAP_SIZE;
    // mCenterX = getWidth() / 2 - BITMAP_SIZE / 2;
    // mCenterY = getHeight() / 2 - BITMAP_SIZE / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(0xffcccccc);
        // -------------------------绘制上半部分 start
        canvas.save();
        // 将原点移动到中心去
        canvas.translate(mCenterX, mCenterY);
        canvas.rotate(-degrees);
        // 进行裁剪,现在是居中了,所以底部就是0,顶部是负数
        canvas.clipRect(-BITMAP_SIZE, -BITMAP_SIZE, BITMAP_SIZE, 0);
        mCamera.save();
        mCamera.rotateX(-degY);
        mCamera.applyToCanvas(canvas);
        canvas.rotate(degrees);
        // 将原点移动回到0.0
        canvas.translate(-mCenterX, -mCenterY);
        // 绘制 图片
        canvas.drawBitmap(mBitmap, mCenterX - BITMAP_SIZE / 2, mCenterY - BITMAP_SIZE / 2, mPaint);
        canvas.restore();
        mCamera.restore();
        // -------------------------绘制上半部分 end
        // -------------------------绘制下半部分 start
        canvas.save();
        // 将原点移动到中心
        canvas.translate(mCenterX, mCenterY);
        canvas.rotate(-degrees);
        // 进行裁剪
        canvas.clipRect(-BITMAP_SIZE, 0, BITMAP_SIZE, BITMAP_SIZE);
        mCamera.save();
        mCamera.rotateX(degX);
        mCamera.applyToCanvas(canvas);
        canvas.rotate(degrees);
        // 将原点移动回到 0,0
        canvas.translate(-mCenterX, -mCenterX);
        // 绘制bitmap
        canvas.drawBitmap(mBitmap, mCenterX - BITMAP_SIZE / 2, mCenterY - BITMAP_SIZE / 2, mPaint);
        canvas.restore();
        mCamera.restore();
    // -------------------------绘制下半部分 end
    }

    public float getDegrees() {
        return degrees;
    }

    public void setDegrees(float degrees) {
        this.degrees = degrees;
        postInvalidate();
    }

    public float getDegX() {
        return degX;
    }

    public void setDegX(float degX) {
        this.degX = degX;
        postInvalidate();
    }

    public float getDegY() {
        return degY;
    }

    public void setDegY(float degY) {
        this.degY = degY;
        postInvalidate();
    }

    public void start() {
        if (animatorSet != null) {
            animatorSet.cancel();
            animatorSet = null;
        }
        // 恢复初始状态
        setDegrees(0);
        setDegX(0);
        setDegY(0);
        // 先旋转X轴,然后进行转动,最后进行Y轴选准
        // 翻页动画
        ObjectAnimator degXAnimator = ObjectAnimator.ofFloat(this, "degX", 0, 45);
        degXAnimator.setDuration(1200);
        // 整个旋转动画
        ObjectAnimator degreesAnimator = ObjectAnimator.ofFloat(this, "degrees", 0, 270);
        degreesAnimator.setDuration(3000);
        ObjectAnimator degYAnimator = ObjectAnimator.ofFloat(this, "degY", 0, 45);
        degYAnimator.setDuration(1200);
        animatorSet = new AnimatorSet();
        animatorSet.playSequentially(degXAnimator, degreesAnimator, degYAnimator);
        animatorSet.start();
    }
}

16 Source : CameraRotaeView.java
with Apache License 2.0
from aohanyao

/**
 * Created by 江俊超 on 2018/10/31.
 * Version:1.0
 * Description: 旋转图
 * ChangeLog:
 */
public clreplaced CameraRotaeView extends View {

    private final String TAG = "ImageTextView";

    /**
     * 画笔
     */
    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private Bitmap mBitmap;

    private Camera mCamera;

    private float degrees = 20;

    private Animator animator;

    /**
     * 图片的宽度
     */
    private final float BITMAP_WIDTH = Utils.dp2px(200);

    {
        mPaint.setTextSize(Utils.dp2px(20));
        mBitmap = Utils.getDrawableBitmap(getContext(), R.drawable.icon_android_road, BITMAP_WIDTH);
        mCamera = new Camera();
        mCamera.rotateX(45);
        mCamera.setLocation(0, 0, -8 * getResources().getDisplayMetrics().density);
    }

    public CameraRotaeView(Context context) {
        super(context);
    }

    public CameraRotaeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CameraRotaeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        float centerX = BITMAP_WIDTH;
        float centerY = BITMAP_WIDTH;
        // ----绘制上半部分
        canvas.save();
        canvas.translate(centerX, centerX);
        canvas.rotate(-degrees);
        canvas.clipRect(-BITMAP_WIDTH, -BITMAP_WIDTH, BITMAP_WIDTH, 0);
        canvas.rotate(degrees);
        canvas.translate(-centerX, -centerY);
        canvas.drawBitmap(mBitmap, centerX - BITMAP_WIDTH / 2, centerY - BITMAP_WIDTH / 2, mPaint);
        canvas.restore();
        // 绘制下半部分
        canvas.save();
        // 其实是把 x0 y0 移动到了中心点
        // canvas.translate 移动的是坐标原点,而不是画布
        canvas.translate(centerX, centerY);
        canvas.rotate(-degrees);
        // 然后将重心点移动到原点附近
        // if (degrees != 0)
        mCamera.applyToCanvas(canvas);
        canvas.clipRect(-BITMAP_WIDTH, 0, BITMAP_WIDTH, BITMAP_WIDTH);
        canvas.rotate(degrees);
        canvas.translate(-centerX, -centerY);
        canvas.drawBitmap(mBitmap, centerX - BITMAP_WIDTH / 2, centerY - BITMAP_WIDTH / 2, mPaint);
        canvas.restore();
    }

    public float getDegrees() {
        return degrees;
    }

    public void setDegrees(float degrees) {
        this.degrees = degrees;
        invalidate();
    }

    /**
     * 应该使用更多的动画来完善
     */
    @Deprecated
    public void startAmin() {
        if (animator != null) {
            animator.cancel();
            animator = null;
        }
        animator = ObjectAnimator.ofFloat(this, "degrees", 20, 360);
        animator.setDuration(3500);
        animator.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            // setDegrees(0);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
        animator.start();
    }
}

15 Source : ITHomeLoadingView.java
with Apache License 2.0
from zyyoona7

/**
 * Created by zyyoona7 on 2017/6/22.
 */
public clreplaced ITHomeLoadingView extends BaseProgressView {

    // 画笔
    private Paint mPaint;

    // 矩阵
    private Matrix mMatrix;

    // Camera,配合矩阵左各种旋转
    private Camera mCamera;

    // 字体颜色
    private int mFontColor = Color.WHITE;

    // 关键字
    private String mKeyword = "IT";

    // 字体大小
    private float mFontSize = 15f;

    // 主颜色
    private int mHomeColor = DEFAULT_COLOR;

    // 测量字体边界的rect
    private Rect mRect = null;

    // 画圆弧时需要
    private RectF mRectF = null;

    private float degree;

    // 圆环与圆的间距
    private float mRingSpacing = DEFAULT_PAINT_WIDTH;

    // 圆环宽度
    private float mStrokeWidth = DEFAULT_PAINT_WIDTH;

    public ITHomeLoadingView(Context context) {
        super(context);
    }

    public ITHomeLoadingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected int setMaxProgress() {
        return 360;
    }

    @Override
    protected void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        // 粗体
        mPaint.setFakeBoldText(true);
        mPaint.setColor(DEFAULT_COLOR);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(dp2px(mStrokeWidth));
        // 测量字体边界
        // mRect = new Rect();
        mMatrix = new Matrix();
        mCamera = new Camera();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float spacing = 10;
        float centerX = getWidth() / 2;
        float centerY = getHeight() / 2;
        // 画实心圆
        mPaint.setStrokeWidth(dp2px(mStrokeWidth));
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(centerX, centerX, centerX - dp2px(mStrokeWidth) - spacing - dp2px(mRingSpacing), mPaint);
        mPaint.setTextSize(sp2px(mFontSize));
        mPaint.setColor(mFontColor);
        if (mRect == null) {
            mRect = new Rect();
        }
        mPaint.getTextBounds(mKeyword, 0, mKeyword.length(), mRect);
        float textWidth = mPaint.measureText(mKeyword);
        // 画文字,居中
        canvas.drawText(mKeyword, (getWidth() - textWidth) / 2, (getHeight() - mRect.height()) / 2 + mRect.height(), mPaint);
        if (mCurrentMode == MODE_PROGRESS) {
            // 下拉过程
            mPaint.setColor(mHomeColor);
            mPaint.setStyle(Paint.Style.STROKE);
            if (mRectF == null) {
                // 有边距,否则圆弧会不完全
                mRectF = new RectF(spacing, spacing, getWidth() - spacing, getHeight() - spacing);
            }
            canvas.drawArc(mRectF, 0, mCurrentProgress, false, mPaint);
        } else {
            // loading过程
            // 矩阵+Camera 控制旋转
            mMatrix.reset();
            mCamera.save();
            mCamera.rotateY(degree);
            mCamera.getMatrix(mMatrix);
            mCamera.restore();
            mMatrix.preTranslate(-centerX, -centerY);
            mMatrix.postTranslate(centerX, centerY);
            canvas.concat(mMatrix);
            mPaint.setColor(mHomeColor);
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(centerX, centerX, centerX - spacing, mPaint);
        }
    }

    @Override
    public void setColor(int color) {
        this.mHomeColor = color;
        postInvalidate();
    }

    /**
     * 设置字体颜色
     *
     * @param color
     */
    public void setFontColor(int color) {
        this.mFontColor = color;
        postInvalidate();
    }

    /**
     * 设置字体大小
     *
     * @param fontSize
     */
    public void setFontSize(float fontSize) {
        this.mFontSize = fontSize;
        mPaint.setTextSize(mFontSize);
        postInvalidate();
    }

    /**
     * 设置绘画文字
     *
     * @param keyword
     */
    public void setKeyword(String keyword) {
        mKeyword = keyword;
        mPaint.getTextBounds(mKeyword, 0, mKeyword.length(), mRect);
        postInvalidate();
    }

    /**
     * 设置圆与圆环之间的间距
     *
     * @param spacing
     */
    public void setRingSpacing(float spacing) {
        this.mRingSpacing = spacing;
        postInvalidate();
    }

    /**
     * 设置圆环的宽度
     *
     * @param strokeWidth
     */
    public void setStrokeWidth(float strokeWidth) {
        this.mStrokeWidth = strokeWidth;
        postInvalidate();
    }

    @Override
    public void startAnim() {
        stopAnim();
        setMode(MODE_ROTATE);
        startAnim(0, 180, 500);
    }

    @Override
    public void startAnim(long time) {
        stopAnim();
        setMode(MODE_ROTATE);
        startAnim(0, 180, time);
    }

    @Override
    protected int getRepeatCount() {
        return ValueAnimator.INFINITE;
    }

    @Override
    protected int getRepeatMode() {
        return ValueAnimator.RESTART;
    }

    @Override
    protected void onAnimatorUpdate(ValueAnimator animator) {
        degree = (float) animator.getAnimatedValue();
        postInvalidate();
    }
}

15 Source : AnimatorProxy.java
with Apache License 2.0
from triline3

/**
 * A proxy clreplaced to allow for modifying post-3.0 view properties on all pre-3.0
 * platforms. <strong>DO NOT</strong> wrap your views with this clreplaced if you
 * are using {@code ObjectAnimator} as it will handle that itself.
 */
public final clreplaced AnimatorProxy extends Animation {

    /**
     * Whether or not the current running platform needs to be proxied.
     */
    public static final boolean NEEDS_PROXY = Integer.valueOf(Build.VERSION.SDK).intValue() < Build.VERSION_CODES.HONEYCOMB;

    private static final WeakHashMap<View, AnimatorProxy> PROXIES = new WeakHashMap<View, AnimatorProxy>();

    private final WeakReference<View> mView;

    private final Camera mCamera = new Camera();

    private final RectF mBefore = new RectF();

    private final RectF mAfter = new RectF();

    private final Matrix mTempMatrix = new Matrix();

    private boolean mHasPivot;

    private float mAlpha = 1;

    private float mPivotX;

    private float mPivotY;

    private float mRotationX;

    private float mRotationY;

    private float mRotationZ;

    private float mScaleX = 1;

    private float mScaleY = 1;

    private float mTranslationX;

    private float mTranslationY;

    private AnimatorProxy(View view) {
        // perform transformation immediately
        setDuration(0);
        // persist transformation beyond duration
        setFillAfter(true);
        view.setAnimation(this);
        mView = new WeakReference<View>(view);
    }

    /**
     * Create a proxy to allow for modifying post-3.0 view properties on all
     * pre-3.0 platforms. <strong>DO NOT</strong> wrap your views if you are
     * using {@code ObjectAnimator} as it will handle that itself.
     *
     * @param view View to wrap.
     *
     * @return Proxy to post-3.0 properties.
     */
    public static AnimatorProxy wrap(View view) {
        AnimatorProxy proxy = PROXIES.get(view);
        // This checks if the proxy already exists and whether it still is the animation of the given view
        if (proxy == null || proxy != view.getAnimation()) {
            proxy = new AnimatorProxy(view);
            PROXIES.put(view, proxy);
        }
        return proxy;
    }

    public float getAlpha() {
        return mAlpha;
    }

    public void setAlpha(float alpha) {
        if (mAlpha != alpha) {
            mAlpha = alpha;
            View view = mView.get();
            if (view != null) {
                view.invalidate();
            }
        }
    }

    public float getPivotX() {
        return mPivotX;
    }

    public void setPivotX(float pivotX) {
        if (!mHasPivot || mPivotX != pivotX) {
            prepareForUpdate();
            mHasPivot = true;
            mPivotX = pivotX;
            invalidateAfterUpdate();
        }
    }

    public float getPivotY() {
        return mPivotY;
    }

    public void setPivotY(float pivotY) {
        if (!mHasPivot || mPivotY != pivotY) {
            prepareForUpdate();
            mHasPivot = true;
            mPivotY = pivotY;
            invalidateAfterUpdate();
        }
    }

    public float getRotation() {
        return mRotationZ;
    }

    public void setRotation(float rotation) {
        if (mRotationZ != rotation) {
            prepareForUpdate();
            mRotationZ = rotation;
            invalidateAfterUpdate();
        }
    }

    public float getRotationX() {
        return mRotationX;
    }

    public void setRotationX(float rotationX) {
        if (mRotationX != rotationX) {
            prepareForUpdate();
            mRotationX = rotationX;
            invalidateAfterUpdate();
        }
    }

    public float getRotationY() {
        return mRotationY;
    }

    public void setRotationY(float rotationY) {
        if (mRotationY != rotationY) {
            prepareForUpdate();
            mRotationY = rotationY;
            invalidateAfterUpdate();
        }
    }

    public float getScaleX() {
        return mScaleX;
    }

    public void setScaleX(float scaleX) {
        if (mScaleX != scaleX) {
            prepareForUpdate();
            mScaleX = scaleX;
            invalidateAfterUpdate();
        }
    }

    public float getScaleY() {
        return mScaleY;
    }

    public void setScaleY(float scaleY) {
        if (mScaleY != scaleY) {
            prepareForUpdate();
            mScaleY = scaleY;
            invalidateAfterUpdate();
        }
    }

    public int getScrollX() {
        View view = mView.get();
        if (view == null) {
            return 0;
        }
        return view.getScrollX();
    }

    public void setScrollX(int value) {
        View view = mView.get();
        if (view != null) {
            view.scrollTo(value, view.getScrollY());
        }
    }

    public int getScrollY() {
        View view = mView.get();
        if (view == null) {
            return 0;
        }
        return view.getScrollY();
    }

    public void setScrollY(int value) {
        View view = mView.get();
        if (view != null) {
            view.scrollTo(view.getScrollX(), value);
        }
    }

    public float getTranslationX() {
        return mTranslationX;
    }

    public void setTranslationX(float translationX) {
        if (mTranslationX != translationX) {
            prepareForUpdate();
            mTranslationX = translationX;
            invalidateAfterUpdate();
        }
    }

    public float getTranslationY() {
        return mTranslationY;
    }

    public void setTranslationY(float translationY) {
        if (mTranslationY != translationY) {
            prepareForUpdate();
            mTranslationY = translationY;
            invalidateAfterUpdate();
        }
    }

    public float getX() {
        View view = mView.get();
        if (view == null) {
            return 0;
        }
        return view.getLeft() + mTranslationX;
    }

    public void setX(float x) {
        View view = mView.get();
        if (view != null) {
            setTranslationX(x - view.getLeft());
        }
    }

    public float getY() {
        View view = mView.get();
        if (view == null) {
            return 0;
        }
        return view.getTop() + mTranslationY;
    }

    public void setY(float y) {
        View view = mView.get();
        if (view != null) {
            setTranslationY(y - view.getTop());
        }
    }

    private void prepareForUpdate() {
        View view = mView.get();
        if (view != null) {
            computeRect(mBefore, view);
        }
    }

    private void invalidateAfterUpdate() {
        View view = mView.get();
        if (view == null || view.getParent() == null) {
            return;
        }
        final RectF after = mAfter;
        computeRect(after, view);
        after.union(mBefore);
        ((View) view.getParent()).invalidate((int) Math.floor(after.left), (int) Math.floor(after.top), (int) Math.ceil(after.right), (int) Math.ceil(after.bottom));
    }

    private void computeRect(final RectF r, View view) {
        // compute current rectangle according to matrix transformation
        final float w = view.getWidth();
        final float h = view.getHeight();
        // use a rectangle at 0,0 to make sure we don't run into issues with scaling
        r.set(0, 0, w, h);
        final Matrix m = mTempMatrix;
        m.reset();
        transformMatrix(m, view);
        mTempMatrix.mapRect(r);
        r.offset(view.getLeft(), view.getTop());
        // Straighten coords if rotations flipped them
        if (r.right < r.left) {
            final float f = r.right;
            r.right = r.left;
            r.left = f;
        }
        if (r.bottom < r.top) {
            final float f = r.top;
            r.top = r.bottom;
            r.bottom = f;
        }
    }

    private void transformMatrix(Matrix m, View view) {
        final float w = view.getWidth();
        final float h = view.getHeight();
        final boolean hasPivot = mHasPivot;
        final float pX = hasPivot ? mPivotX : w / 2f;
        final float pY = hasPivot ? mPivotY : h / 2f;
        final float rX = mRotationX;
        final float rY = mRotationY;
        final float rZ = mRotationZ;
        if ((rX != 0) || (rY != 0) || (rZ != 0)) {
            final Camera camera = mCamera;
            camera.save();
            camera.rotateX(rX);
            camera.rotateY(rY);
            camera.rotateZ(-rZ);
            camera.getMatrix(m);
            camera.restore();
            m.preTranslate(-pX, -pY);
            m.postTranslate(pX, pY);
        }
        final float sX = mScaleX;
        final float sY = mScaleY;
        if ((sX != 1.0f) || (sY != 1.0f)) {
            m.postScale(sX, sY);
            final float sPX = -(pX / w) * ((sX * w) - w);
            final float sPY = -(pY / h) * ((sY * h) - h);
            m.postTranslate(sPX, sPY);
        }
        m.postTranslate(mTranslationX, mTranslationY);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        View view = mView.get();
        if (view != null) {
            t.setAlpha(mAlpha);
            transformMatrix(t.getMatrix(), view);
        }
    }
}

15 Source : TransformView.java
with Apache License 2.0
from REBOOTERS

/**
 * Created by engineer on 2017/9/2.
 */
public clreplaced TransformView extends View {

    private static final String TAG = "TransformView";

    private Paint mPaint;

    private Matrix mMatrix;

    private Camera mCamera;

    private Paint helpPaint;

    // 
    private Bitmap mBitmap;

    // 
    private Point center;

    private int viewW, viewH;

    // 
    private float degreeX, degreeY, degreeZ;

    private float scaleX = 1, scaleY = 1;

    private boolean isFixed = true;

    private boolean UpDownFlipView = true, LeftRightFlipView;

    public TransformView(Context context) {
        super(context);
        init();
    }

    public TransformView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TransformView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 
        mPaint = new Paint();
        mCamera = new Camera();
        mMatrix = new Matrix();
        initBitmap();
        // 
        helpPaint = new Paint();
        helpPaint.setStyle(Paint.Style.STROKE);
    }

    private void initBitmap() {
        if (UpDownFlipView || LeftRightFlipView) {
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.cat);
            center = new Point((viewW - mBitmap.getWidth()) / 2, (viewH - mBitmap.getHeight()) / 2);
            // 
            DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
            float newZ = -displayMetrics.density * 6;
            mCamera.setLocation(0, 0, newZ);
        } else {
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android_robot);
            center = new Point((viewW - mBitmap.getWidth()) / 2, (viewH - mBitmap.getHeight()) / 2);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCamera.save();
        mMatrix.reset();
        mCamera.rotateX(degreeX);
        mCamera.rotateY(degreeY);
        mCamera.rotateZ(degreeZ);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        if (isFixed) {
            mMatrix.preTranslate(-center.x - mBitmap.getWidth() / 2, -center.y - mBitmap.getHeight() / 2);
            mMatrix.postTranslate(center.x + mBitmap.getWidth() / 2, center.y + mBitmap.getHeight() / 2);
        }
        mMatrix.postScale(scaleX, scaleY, center.x + mBitmap.getWidth() / 2, center.y + mBitmap.getHeight() / 2);
        // 上下翻转的FlipView
        if (UpDownFlipView) {
            canvas.save();
            canvas.clipRect(center.x, center.y, center.x + mBitmap.getWidth(), center.y + mBitmap.getHeight() / 2);
            canvas.drawBitmap(mBitmap, center.x, center.y, mPaint);
            canvas.restore();
            canvas.save();
            canvas.concat(mMatrix);
            canvas.clipRect(center.x, center.y + mBitmap.getHeight() / 2, center.x + mBitmap.getWidth(), center.y + mBitmap.getHeight());
            canvas.drawBitmap(mBitmap, center.x, center.y, mPaint);
            canvas.restore();
        } else if (LeftRightFlipView) {
            canvas.save();
            canvas.clipRect(center.x + mBitmap.getWidth() / 2, center.y, center.x + mBitmap.getWidth(), center.y + mBitmap.getHeight());
            canvas.drawBitmap(mBitmap, center.x, center.y, mPaint);
            canvas.restore();
            canvas.save();
            canvas.concat(mMatrix);
            canvas.clipRect(center.x, center.y, center.x + mBitmap.getWidth() / 2, center.y + mBitmap.getHeight());
            canvas.drawBitmap(mBitmap, center.x, center.y, mPaint);
            canvas.restore();
        } else {
            canvas.save();
            canvas.concat(mMatrix);
            canvas.drawBitmap(mBitmap, center.x, center.y, mPaint);
            canvas.restore();
        }
        canvas.drawRect(center.x, center.y, center.x + mBitmap.getWidth(), center.y + mBitmap.getHeight(), helpPaint);
    }

    public void setDegreeX(float degree) {
        this.degreeX = degree;
        invalidate();
    }

    public void setDegreeY(float degree) {
        this.degreeY = degree;
        invalidate();
    }

    public void setDegreeZ(float degreeZ) {
        this.degreeZ = degreeZ;
        invalidate();
    }

    @Override
    public void setScaleX(float scaleX) {
        this.scaleX = scaleX;
        invalidate();
    }

    @Override
    public void setScaleY(float scaleY) {
        this.scaleY = scaleY;
        invalidate();
    }

    public void setFixed(boolean fixed) {
        isFixed = fixed;
    }

    public void setUpDownFlipView(boolean upDownFlipView) {
        UpDownFlipView = upDownFlipView;
        initBitmap();
        invalidate();
    }

    public void setLeftRightFlipView(boolean leftRightFlipView) {
        LeftRightFlipView = leftRightFlipView;
        initBitmap();
        invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        viewW = w;
        viewH = h;
        center = new Point((w - mBitmap.getWidth()) / 2, (h - mBitmap.getHeight()) / 2);
    }
}

15 Source : AnimationDrawable.java
with Apache License 2.0
from liuwei1993

/**
 * Created by simon on 17-6-5.
 */
public abstract clreplaced AnimationDrawable extends Drawable implements ValueAnimator.AnimatorUpdateListener, Animatable, Drawable.Callback {

    private static final Rect ZERO_BOUNDS_RECT = new Rect();

    private ValueAnimator animator;

    private Camera mCamera;

    private Matrix mMatrix;

    private float scale = 1;

    private float scaleX = 1;

    private float scaleY = 1;

    private float pivotX;

    private float pivotY;

    private int animationDelay;

    private float rotationX;

    private float rotationY;

    private float translationX;

    private float translationY;

    private float rotation;

    private float translationXPercentage;

    private float translationYPercentage;

    @IntRange(from = 0, to = 255)
    private int alpha = 255;

    protected Rect drawBounds = ZERO_BOUNDS_RECT;

    @Override
    public int getAlpha() {
        return alpha;
    }

    public AnimationDrawable() {
        mCamera = new Camera();
        mMatrix = new Matrix();
    }

    public abstract ValueAnimator createAnimator();

    protected abstract void drawSelf(@NonNull Canvas canvas);

    @Override
    public void draw(@NonNull Canvas canvas) {
        float tx = getTranslationX();
        tx = tx == 0 ? (int) (getBounds().width() * getTranslationXPercentage()) : tx;
        float ty = getTranslationY();
        ty = ty == 0 ? (int) (getBounds().height() * getTranslationYPercentage()) : ty;
        canvas.translate(tx, ty);
        canvas.scale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
        canvas.rotate(getRotation(), getPivotX(), getPivotY());
        if (getRotationX() != 0 || getRotationY() != 0) {
            mCamera.save();
            mCamera.rotateX(getRotationX());
            mCamera.rotateY(getRotationY());
            mCamera.getMatrix(mMatrix);
            mMatrix.preTranslate(-getPivotX(), -getPivotY());
            mMatrix.postTranslate(getPivotX(), getPivotY());
            mCamera.restore();
            canvas.concat(mMatrix);
        }
        drawSelf(canvas);
    }

    @Override
    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        this.alpha = alpha;
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
    // do nothing
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    @Override
    public void invalidateDrawable(@NonNull Drawable who) {
        invalidateSelf();
    }

    @Override
    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
        scheduleSelf(what, when);
    }

    @Override
    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
        unscheduleSelf(what);
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        final Callback callback = getCallback();
        if (callback != null) {
            callback.invalidateDrawable(this);
        }
    }

    public void reset() {
        scale = 1;
        rotationX = 0;
        rotationY = 0;
        translationX = 0;
        translationY = 0;
        rotation = 0;
        translationXPercentage = 0f;
        translationYPercentage = 0f;
    }

    @Override
    public void start() {
        animator = createAnimator();
        if (animator != null) {
            animator.addUpdateListener(this);
            animator.setStartDelay(getAnimationDelay());
            AnimUtils.start(animator);
        }
    }

    @Override
    public void stop() {
        AnimUtils.stop(animator);
        reset();
        if (animator != null) {
            animator.removeUpdateListener(this);
            animator = null;
        }
    }

    @Override
    public boolean isRunning() {
        return AnimUtils.isRunning(animator);
    }

    // getters and setters
    public float getScale() {
        return scale;
    }

    public void setScale(float scale) {
        this.scale = scale;
    }

    public float getScaleX() {
        return scaleX;
    }

    public void setScaleX(float scaleX) {
        this.scaleX = scaleX;
    }

    public float getScaleY() {
        return scaleY;
    }

    public void setScaleY(float scaleY) {
        this.scaleY = scaleY;
    }

    public float getPivotX() {
        return pivotX;
    }

    public float getPivotY() {
        return pivotY;
    }

    public int getAnimationDelay() {
        return animationDelay;
    }

    public void setAnimationDelay(int animationDelay) {
        this.animationDelay = animationDelay;
    }

    public float getRotationX() {
        return rotationX;
    }

    public void setRotationX(float rotationX) {
        this.rotationX = rotationX;
    }

    public float getRotationY() {
        return rotationY;
    }

    public void setRotationY(float rotateY) {
        this.rotationY = rotateY;
    }

    public float getTranslationX() {
        return translationX;
    }

    public void setTranslationX(float translationX) {
        this.translationX = translationX;
    }

    public float getTranslationY() {
        return translationY;
    }

    public void setTranslationY(float translationY) {
        this.translationY = translationY;
    }

    public float getRotation() {
        return rotation;
    }

    public void setRotation(float rotate) {
        this.rotation = rotate;
    }

    public float getTranslationXPercentage() {
        return translationXPercentage;
    }

    public void setTranslationXPercentage(float translationXPercentage) {
        this.translationXPercentage = translationXPercentage;
    }

    public float getTranslationYPercentage() {
        return translationYPercentage;
    }

    public void setTranslationYPercentage(float translationYPercentage) {
        this.translationYPercentage = translationYPercentage;
    }

    public void setPivotX(float pivotX) {
        this.pivotX = pivotX;
    }

    public void setPivotY(float pivotY) {
        this.pivotY = pivotY;
    }

    public Rect getDrawBounds() {
        return drawBounds;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        this.setDrawBounds(bounds);
    }

    public void setDrawBounds(@NonNull Rect drawBounds) {
        setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom);
    }

    public void setDrawBounds(int left, int top, int right, int bottom) {
        this.drawBounds = new Rect(left, top, right, bottom);
        pivotX = drawBounds.centerX();
        pivotY = drawBounds.centerY();
    }
}

15 Source : Rotate3DAnimation.java
with Apache License 2.0
from InnoFang

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    final float fromDegrees = mFromDegrees;
    float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
    final float centerX = mCenterX;
    final float centerY = mCenterY;
    final Camera camera = mCamera;
    final Matrix matrix = t.getMatrix();
    camera.save();
    // 调节深度
    if (mReverse)
        camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
    else
        camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
    // 绕y轴旋转
    camera.rotateY(degrees);
    camera.getMatrix(matrix);
    camera.restore();
    // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
    float[] mValues = new float[9];
    // 获取数值
    matrix.getValues(mValues);
    // 数值修正
    mValues[6] = mValues[6] / scale;
    // 数值修正
    mValues[7] = mValues[7] / scale;
    // 重新赋值
    matrix.setValues(mValues);
    // 调节中心点
    matrix.preTranslate(-centerX, -centerY);
    matrix.postScale(centerX, centerY);
}

15 Source : PressFrameLayout.java
with MIT License
from CeuiLiSA

public clreplaced PressFrameLayout extends RelativeLayout {

    // 父布局宽度
    private int width = 0;

    // 父布局高度
    private int height = 0;

    // 为阴影和按压变形预留位置
    private int padding;

    // 控件圆角
    private int cornerRadius;

    // 阴影偏移
    private float shadeOffset;

    Paint paintBg = new Paint(Paint.ANTI_ALIAS_FLAG);

    Camera camera = new Camera();

    // 触摸点x轴方向偏移比例
    float cameraX = 0f;

    // 触摸点y轴方向偏移比例
    float cameraY = 0f;

    // 背景色
    private int colorBg;

    // 背景阴影透明度
    private int shadeAlpha = 0xaa000000;

    // 按压缩放动画控制
    private float touchProgress = 1f;

    // 相机旋转(按压偏移)动画控制
    private float cameraProgress = 0f;

    // 按压效果区域
    TouchArea pressArea = new TouchArea(0, 0, 0, 0);

    // 按压位置是在内圈还是外圈
    boolean isInPressArea = true;

    // 倾斜时的相机最大倾斜角度,deg
    private int maxAngle = 5;

    // 整体按压时的形变控制
    private float scale = 0.98f;

    // 计算按压时间,小于500毫秒响应onClick()
    private long pressTime = 0;

    // background为图片时
    Bitmap bitmap;

    Rect srcRectF = new Rect();

    RectF dstRectF = new RectF();

    public PressFrameLayout(Context context) {
        super(context);
    }

    public PressFrameLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public PressFrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    {
        // 开启viewGroup的onDraw()
        setWillNotDraw(false);
        padding = new DensityUtil().dip2px(20);
        cornerRadius = new DensityUtil().dip2px(5);
        shadeOffset = new DensityUtil().dip2px(5);
        // View的background为颜色或者图片的两种情况
        Drawable background = getBackground();
        if (background instanceof ColorDrawable) {
            colorBg = ((ColorDrawable) background).getColor();
            paintBg.setColor(colorBg);
        } else if (background instanceof BitmapDrawable) {
            bitmap = ((BitmapDrawable) background).getBitmap();
            srcRectF = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        }
        setBackground(null);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!isInPressArea) {
            camera.save();
            // 相机在控件中心上方,在x,y轴方向旋转,形成控件倾斜效果
            camera.rotateX(maxAngle * cameraX * cameraProgress);
            camera.rotateY(maxAngle * cameraY * cameraProgress);
            canvas.translate(width / 2f, height / 2f);
            camera.applyToCanvas(canvas);
            // 还原canvas坐标系
            canvas.translate(-width / 2f, -height / 2f);
            camera.restore();
        }
        // 绘制阴影和背景
        paintBg.setShadowLayer(shadeOffset * touchProgress, 0, 0, (colorBg & 0x00FFFFFF) | shadeAlpha);
        if (bitmap != null) {
            canvas.drawBitmap(bitmap, srcRectF, dstRectF, paintBg);
        } else {
            canvas.drawRoundRect(dstRectF, cornerRadius, cornerRadius, paintBg);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        dstRectF.set(padding, padding, width - padding, height - padding);
        // 计算输入按压的内部范围,布局中心部分为内圈,其他为外圈
        pressArea.set((width - 2 * padding) / 4f + padding, (height - 2 * padding) / 4f + padding, width - (width - 2 * padding) / 4f - padding, height - (width - 2 * padding) / 4f - padding);
    }

    /**
     * 判断是按压内圈还是外圈
     * @return true:按压内圈;false:按压外圈
     */
    private boolean isInPressArea(float x, float y) {
        return x > pressArea.getLeft() && x < pressArea.getRight() && y > pressArea.getTop() && y < pressArea.getBottom();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        AnimatorSet animatorSet = new AnimatorSet();
        // 按压动画时长
        int duration = 100;
        int type = 0;
        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                pressTime = System.currentTimeMillis();
                type = 1;
                isInPressArea = isInPressArea(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_CANCEL:
                type = 2;
                break;
            case MotionEvent.ACTION_UP:
                if ((System.currentTimeMillis() - pressTime) < 500) {
                    performClick();
                }
                type = 2;
                break;
        }
        if (isInPressArea) {
            // 内圈按压效果
            if (type != 0) {
                ObjectAnimator animX = ObjectAnimator.ofFloat(this, "scaleX", type == 1 ? 1 : scale, type == 1 ? scale : 1).setDuration(duration);
                ObjectAnimator animY = ObjectAnimator.ofFloat(this, "scaleY", type == 1 ? 1 : scale, type == 1 ? scale : 1).setDuration(duration);
                ObjectAnimator animZ = ObjectAnimator.ofFloat(this, "touchProgress", type == 1 ? 1 : 0, type == 1 ? 0 : 1).setDuration(duration);
                animX.setInterpolator(new DecelerateInterpolator());
                animY.setInterpolator(new DecelerateInterpolator());
                animZ.setInterpolator(new DecelerateInterpolator());
                animatorSet.playTogether(animX, animY, animZ);
                animatorSet.start();
            }
        } else {
            // 外圈按压效果
            cameraX = (event.getX() - width / 2f) / ((width - 2 * padding) / 2f);
            if (cameraX > 1)
                cameraX = 1;
            if (cameraX < -1)
                cameraX = -1;
            cameraY = (event.getY() - height / 2f) / ((height - 2 * padding) / 2f);
            if (cameraY > 1)
                cameraY = 1;
            if (cameraY < -1)
                cameraY = -1;
            // 坐标系调整
            float tmp = cameraX;
            cameraX = -cameraY;
            cameraY = tmp;
            switch(type) {
                case // 按下动画
                1:
                    ObjectAnimator.ofFloat(this, "cameraProgress", 0, 1).setDuration(duration).start();
                    break;
                case // 还原动画
                2:
                    ObjectAnimator.ofFloat(this, "cameraProgress", 1, 0).setDuration(duration).start();
                    break;
                default:
                    break;
            }
            invalidate();
        }
        return true;
    }

    public float getTouchProgress() {
        return touchProgress;
    }

    public void setTouchProgress(float touchProgress) {
        this.touchProgress = touchProgress;
        invalidate();
    }

    public float getCameraProgress() {
        return cameraProgress;
    }

    public void setCameraProgress(float cameraProgress) {
        this.cameraProgress = cameraProgress;
        invalidate();
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }
}

See More Examples