Android 书本打开和关闭动画

栏目: Android · 发布时间: 5年前

内容简介:我偶尔一次发现掌阅的打开书本动画不错,然后度娘了一下,发现一个链接:一共就是2个类+2个跳转动画
Android 书本打开和关闭动画

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(this@MainActivity)
            window.addView(mBookOpenView)
            mBookOpenView?.startAnim(startValue, endValue)

            mBookOpenView?.setEndListener(object : BookOpenView.OnAnimationEndListener {
                override fun onAnimationEnd() {
                    println("onAnimationEnd========== onAnimationEnd")
                    startActivity(Intent(this@MainActivity, 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>
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

法律论证理论

法律论证理论

罗伯特·阿列克西 / 舒国滢 / 中国法制出版社 / 2002-12-01 / 30.00

阿列克西的著作探讨的主要问题是如法律裁决之类的规范性陈述如何以理性的方式证立。阿列克西将规范性陈述的证立过程看作实践商谈或“实践言说”,而将法律裁决的证立过程视为“法律言说” 。由于支持法律规范的法律商谈是普遍实践言说的特定形式,所以法律论证理论应当立基于这种一般理论。 在阿列克西看来,如果裁决是理性言说的结果,那么这一规范性陈述就是真实的或可接受的。其基本观念在于法律裁决证立的合理性取决于......一起来看看 《法律论证理论》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具