1. 程式人生 > >Android 書本開啟和關閉動畫

Android 書本開啟和關閉動畫

作者: Jooyer, 時間: 2018.12.08

Github地址,歡迎點贊,fork

我偶爾一次發現掌閱的開啟書本動畫不錯,然後度娘了一下,發現一個連結:download.csdn.net/download/we… , 下載下來學習膜拜了一下,發現有些動畫過度和掌閱有點不一樣,所以我就拷貝原始碼並略微修改了下,如果想看原著,上面已經貼了,這個效果是GIF,真機更流暢一些.

一共就是2個類+2個跳轉動畫

首先,看看 BookOpenView

public class BookOpenView extends FrameLayout implements
        Animator
.AnimatorListener
{ private BookOpenViewValue mStartValue; private AnimatorSet mAnimatorSet1, mAnimatorSet2; private TextView tv_book_name; private ImageView iv_book_content; private View iv_book_cover; private ConstraintLayout cl_book_container; // 預設開啟書本動畫是關閉的 private
AtomicBoolean isOpened = new AtomicBoolean(false); public BookOpenView(@NonNull Context context) { super(context); initView(context); } public BookOpenView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); initView(context); } public
BookOpenView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr)
{ super(context, attrs, defStyleAttr); initView(context); } public void initView(Context context) { LayoutInflater.from(context).inflate(R.layout.book_open_close, this); setBackgroundColor(Color.TRANSPARENT); tv_book_name = (TextView) findViewById(R.id.tv_book_name); iv_book_content = (ImageView) findViewById(R.id.iv_book_content); iv_book_cover = (View) findViewById(R.id.iv_book_cover); cl_book_container = (ConstraintLayout) findViewById(R.id.cl_book_container); } /** * 開啟動畫 */ public synchronized void startAnim(final BookOpenViewValue startValue, BookOpenViewValue endValue) { if (!isOpened.get()) { if (!TextUtils.isEmpty(startValue.getBookName())){ tv_book_name.setText(startValue.getBookName()); } // 如果有圖片,可以在此給 iv_book_cover 設定,圖解儘量不要太大,10K以內為佳 mStartValue = startValue; System.out.println("startAnim===========mStartValue: " + mStartValue.toString() + " ========startValue: " + startValue.toString()); LayoutParams layoutParams = (LayoutParams) cl_book_container.getLayoutParams(); layoutParams.width = startValue.getRight() - startValue.getLeft(); layoutParams.height = startValue.getBottom() - startValue.getTop(); cl_book_container.setLayoutParams(layoutParams); iv_book_content.setLayoutParams(layoutParams); cl_book_container.setTranslationX(startValue.getLeft()); cl_book_container.setTranslationY(startValue.getTop()); // 計算縮放的起始位置和縮放中心點 final int x1 = ((layoutParams.width * (endValue.getRight() - layoutParams.width)) - layoutParams.width * (endValue.getRight() - startValue.getRight())) / (endValue.getRight() - layoutParams.width); final float sX1 = (layoutParams.width - x1 + endValue.getRight() - startValue.getRight()) * 1.0f / (layoutParams.width - x1); final float sX2 = (x1 + startValue.getLeft()) * 1.0f / x1; final float sX = Math.max(sX1, sX2); final int y1 = ((layoutParams.height * (endValue.getBottom() - layoutParams.height)) - layoutParams.height * (endValue.getBottom() - startValue.getBottom())) / (endValue.getBottom() - layoutParams.height); final float sY1 = (layoutParams.height - y1 + endValue.getBottom() - startValue.getBottom()) * 1.0f / (layoutParams.height - y1); final float sY2 = (y1 + startValue.getTop()) * 1.0f / y1; final float sY = Math.max(sY1, sY2); mStartValue.setX(x1); mStartValue.setsX(sX); mStartValue.setY(y1); mStartValue.setsY(sY); cl_book_container.setPivotX(0); cl_book_container.setPivotY(y1); // 對 封面進行縮放 ObjectAnimator scaleX = ObjectAnimator.ofFloat(cl_book_container, "scaleX", 1.0f, sX * 0.8f); scaleX.setDuration(1000); ObjectAnimator scaleY = ObjectAnimator.ofFloat(cl_book_container, "scaleY", 1.0f, sY); scaleY.setDuration(1000); // 對 封面進行平移 ObjectAnimator translationLine = ObjectAnimator.ofFloat(cl_book_container, "translationX", startValue.getLeft(), 0); translationLine.setDuration(1000); // 對封面進行旋轉 ObjectAnimator rotationY = ObjectAnimator.ofFloat(cl_book_container, "rotationY", 0, -150); rotationY.setDuration(600); mAnimatorSet1 = new AnimatorSet(); mAnimatorSet1.playTogether(scaleX, scaleY, translationLine, rotationY); mAnimatorSet1.start(); /* ------------------------------------------------ */ // 對 內部內容進行縮放,必須和封面保持一致的動作 iv_book_content.setPivotX(x1); iv_book_content.setPivotY(y1); iv_book_content.setTranslationX(startValue.getLeft()); iv_book_content.setTranslationY(startValue.getTop()); ObjectAnimator scaleX2 = ObjectAnimator.ofFloat(iv_book_content, "scaleX", 1.0f, sX); scaleX2.setDuration(1000); ObjectAnimator scaleY2 = ObjectAnimator.ofFloat(iv_book_content, "scaleY", 1.0f, sY); scaleY2.setDuration(1000); mAnimatorSet2 = new AnimatorSet(); mAnimatorSet2.playTogether(scaleX2, scaleY2); mAnimatorSet2.addListener(this); mAnimatorSet2.start(); } } /** * 關閉動畫 , 邏輯和開始動畫相反 */ public synchronized void closeAnim() { if (isOpened.get()) { setVisibility(VISIBLE); setAlpha(1.0f); cl_book_container.setScaleX(mStartValue.getsX() * 0.8f); cl_book_container.setScaleY(mStartValue.getsY()); cl_book_container.setRotationY(-150); ObjectAnimator scaleX = ObjectAnimator.ofFloat(cl_book_container, "scaleX", mStartValue.getsX() * 0.8f, 1.0f); scaleX.setDuration(1000); ObjectAnimator scaleY = ObjectAnimator.ofFloat(cl_book_container, "scaleY", mStartValue.getsY(), 1.0f); scaleY.setDuration(1000); ObjectAnimator translationLine = ObjectAnimator.ofFloat(cl_book_container, "translationX", 0, mStartValue.getLeft()); translationLine.setDuration(1000); ObjectAnimator rotationY = ObjectAnimator.ofFloat(cl_book_container, "rotationY", -150, 0); rotationY.setDuration(600); rotationY.setStartDelay(400); mAnimatorSet1 = new AnimatorSet(); mAnimatorSet1.playTogether(scaleX, scaleY, translationLine, rotationY); mAnimatorSet1.start(); /* ------------------------------------------------ */ iv_book_content.setScaleX(mStartValue.getsX()); iv_book_content.setScaleY(mStartValue.getsY()); ObjectAnimator scaleX2 = ObjectAnimator.ofFloat(iv_book_content, "scaleX", mStartValue.getsX(), 1.0f); scaleX2.setDuration(1000); ObjectAnimator scaleY2 = ObjectAnimator.ofFloat(iv_book_content, "scaleY", mStartValue.getsY(), 1.0f); scaleY2.setDuration(1000); mAnimatorSet2 = new AnimatorSet(); mAnimatorSet2.playTogether(scaleX2, scaleY2); mAnimatorSet2.start(); mAnimatorSet2.addListener(this); } } @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { System.out.println("onAnimationEnd========== " + isOpened.get()); if (isOpened.get()) { // 關閉書本動畫執行了 isOpened.set(false); if (null != mEndListener) { mEndListener.onRemove(); } } else { // 開啟書本動畫 isOpened.set(true); if (null != mEndListener) { mEndListener.onAnimationEnd(); } } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } public void cancel() { mAnimatorSet1.cancel(); mAnimatorSet2.cancel(); } public interface OnAnimationEndListener { void onAnimationEnd(); void onRemove(); } private OnAnimationEndListener mEndListener; public void setEndListener(OnAnimationEndListener endListener) { mEndListener = endListener; } } 複製程式碼

內容略多,主要涉及計算,這個細節調整,大家可根據自己喜歡的效果調整試試

再來看一個類: BookOpenViewValue ,一目瞭然啊

public class BookOpenViewValue {
    private int left;
    private int top;
    private int right;
    private int bottom;
    private float x;
    private float y;
    private float sX;
    private float sY;
    private String bookName;
    private String bookCover;

    public BookOpenViewValue(){}

    public BookOpenViewValue(int left, int top, int right, int bottom){
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }


    public int getRight() {
        return right;
    }

    public void setRight(int right) {
        this.right = right;
    }

    public int getBottom() {
        return bottom;
    }

    public void setBottom(int bottom) {
        this.bottom = bottom;
    }

    public int getLeft() {
        return left;
    }

    public void setLeft(int left) {
        this.left = left;
    }

    public int getTop() {
        return top;
    }

    public void setTop(int top) {
        this.top = top;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getsX() {
        return sX;
    }

    public void setsX(float sX) {
        this.sX = sX;
    }

    public float getsY() {
        return sY;
    }

    public void setsY(float sY) {
        this.sY = sY;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookCover() {
        return bookCover;
    }

    public void setBookCover(String bookCover) {
        this.bookCover = bookCover;
    }
}
複製程式碼

最後來看看在 Activity 中用法,其實和一般普通 EditText 用法一致啦!

class MainActivity : AppCompatActivity() {
    private var mBookOpenView: BookOpenView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ll_contain.setOnClickListener {
            val window = window.decorView as ViewGroup
            val location = IntArray(2)
            ll_contain.getLocationInWindow(location)

            val startValue = BookOpenViewValue(location[0], location[1],
                    location[0] + (ll_contain.right - ll_contain.left),
                    location[1] + (ll_contain.bottom - ll_contain.top))


            val endValue = BookOpenViewValue(window.left,
                    window.top,
                    window.right,
                    window.bottom)

            mBookOpenView = BookOpenView([email protected])
            window.addView(mBookOpenView)
            mBookOpenView?.startAnim(startValue, endValue)

            mBookOpenView?.setEndListener(object : BookOpenView.OnAnimationEndListener {
                override fun onAnimationEnd() {
                    println("onAnimationEnd========== onAnimationEnd")
                    startActivity(Intent([email protected], ReadActivity::class.java))
                    overridePendingTransition(R.anim.read_fade_in, R.anim.read_fade_out)
                }

                override fun onRemove() {
                    println("onAnimationEnd========== onRemove")
                    window.removeView(mBookOpenView)
                }
            })
        }

    }

    override fun onResume() {
        super.onResume()
        println("onAnimationEnd========== onResume")
        mBookOpenView?.closeAnim()
    }
}

複製程式碼

跳轉的 Activity 更簡單了:

class ReadActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_read)
    }

  // 重寫主要是去掉系統預設跳轉動畫,方便那邊執行closeAnim
    override fun finish() {
        super.finish()
        overridePendingTransition(0, 0)
    }
}
複製程式碼

最後貼上2個跳轉動畫: res/anim/

read_fade_in.xml

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="1.0" >

</alpha>
複製程式碼

read_fade_out.xml

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="0.0" >

</alpha>
複製程式碼

喜歡記得點贊,收藏,轉發哈!