笔记24 | 一个中间打开界面的动画

一.前言

更新技术公号的好处之一是它会逼着你去学习一个新的东西,今天是一个中间打开Activity效果的动画,可以保存当工具类直接使用!


二.类下载地址

http://download.csdn.net/download/xiangyong_1521/10040916


三.先来看实现效果


四.主要代码

  • MainActivity
findViewById(R.id.one).setOnClickListener(new View.OnClickListener() { 

            @Override
            public void onClick(View v) {
                ActivitySplitAnimationUtil.startActivity(Activity1.this, new Intent(Activity1.this, Activity2.class));
            }
        });
  • ActivitySplitAnimationUtil.java
/**
 * Utility class to create a split activity animation
 *
 * @author Udi Cohen (@udinic)
 */
public class ActivitySplitAnimationUtil {

    public static Bitmap mBitmap = null;
    private static int[] mLoc1;
    private static int[] mLoc2;
    private static ImageView mTopImage;
    private static ImageView mBottomImage;
    private static AnimatorSet mSetAnim;

    /**
     * Start a new Activity with a Split animation
     *
     * @param currActivity The current Activity
     * @param intent       The Intent needed tot start the new Activity
     * @param splitYCoord  The Y coordinate where we want to split the Activity on the animation. -1 will split the Activity equally
     */
    public static void startActivity(Activity currActivity, Intent intent, int splitYCoord) {

        // Preparing the bitmaps that we need to show
        prepare(currActivity, splitYCoord);

        currActivity.startActivity(intent);
        currActivity.overridePendingTransition(0, 0);
    }

    /**
     * Start a new Activity with a Split animation right in the middle of the Activity
     *
     * @param currActivity The current Activity
     * @param intent       The Intent needed tot start the new Activity
     */
    public static void startActivity(Activity currActivity, Intent intent) {
        startActivity(currActivity, intent, -1);
    }

    /**
     * Preparing the graphics on the destination Activity.
     * Should be called on the destination activity on Activity#onCreate() BEFORE setContentView()
     *
     * @param destActivity the destination Activity
     */
    public static void prepareAnimation(final Activity destActivity) {
        mTopImage = createImageView(destActivity, mBitmap, mLoc1);
        mBottomImage = createImageView(destActivity, mBitmap, mLoc2);
    }

    /**
     * 启动动画,显示目标Activity
     * Should be called on the destination activity on Activity#onCreate() AFTER setContentView()
     *
     * @param destActivity the 目标 Activity
     * @param duration The 持续时间 of the animation
     * @param interpolator The interpulator to use for the animation. null for no interpulation.
     */
    public static void animate(final Activity destActivity, final int duration, final TimeInterpolator interpolator) {

        // 在UI线程的消息队列上发布这个消息。我们需要对这些项目进行测量
        new Handler().post(new Runnable() {

            @Override
            public void run() {
                mSetAnim = new AnimatorSet();
                mTopImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                mBottomImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                mSetAnim.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        clean(destActivity);
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {
                        clean(destActivity);
                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                });

                // Animating the 2 parts away from each other
                Animator anim1 = ObjectAnimator.ofFloat(mTopImage, "translationY", mTopImage.getHeight() * -1);
                Animator anim2 = ObjectAnimator.ofFloat(mBottomImage, "translationY", mBottomImage.getHeight());

                if (interpolator != null) {
                    anim1.setInterpolator(interpolator);
                    anim2.setInterpolator(interpolator);
                }

                mSetAnim.setDuration(duration);
                mSetAnim.playTogether(anim1, anim2);
                mSetAnim.start();
            }
        });
    }

    /**
     * 启动显示目标Activity的动画
     * Should be called on the destination activity on Activity#onCreate() AFTER setContentView()
     *
     * @param destActivity the destination Activity
     * @param duration The duration of the animation
     */
    public static void animate(final Activity destActivity, final int duration) {
        animate(destActivity, duration, new DecelerateInterpolator());
    }

    /**
     * Cancel an in progress animation
     */
    public static void cancel() {
        if (mSetAnim != null)
            mSetAnim.cancel();
    }

    /**
     * Clean stuff
     *
     * @param activity The Activity where the animation is occurring
     */
    private static void clean(Activity activity) {
        if (mTopImage != null) {
            mTopImage.setLayerType(View.LAYER_TYPE_NONE, null);
            try {
                // If we use the regular removeView() we'll get a small UI glitch
                activity.getWindowManager().removeViewImmediate(mBottomImage);
            } catch (Exception ignored) {
            }
        }
        if (mBottomImage != null) {
            mBottomImage.setLayerType(View.LAYER_TYPE_NONE, null);
            try {
                activity.getWindowManager().removeViewImmediate(mTopImage);
            } catch (Exception ignored) {
            }
        }

        mBitmap = null;
    }

    /**
     * 为动画制作图形
     *
     * @param currActivity the current Activity from where we start the new one
     * @param splitYCoord  The Y coordinate where we want to split the activity. -1 will split the activity equally
     */
    private static void prepare(Activity currActivity, int splitYCoord) {

        // 获取activity的内容并放入一个位图
        View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content);
        root.setDrawingCacheEnabled(true);
        mBitmap = root.getDrawingCache();

        // If the split Y coordinate is -1 - We'll split the activity equally
        splitYCoord = (splitYCoord != -1 ? splitYCoord : mBitmap.getHeight() / 2);

        if (splitYCoord > mBitmap.getHeight())
            throw new IllegalArgumentException("Split Y coordinate [" + splitYCoord + "] exceeds the activity's height [" + mBitmap.getHeight() + "]");

        // Set the location to put the 2 bitmaps on the destination activity
        mLoc1 = new int[]{0, splitYCoord, root.getTop()};
        mLoc2 = new int[]{splitYCoord, mBitmap.getHeight(), root.getTop()};
    }

    /**
     * 创建一个映像,在目标Activity中包含动画的一个部分
     *
     * @param destActivity The destination activity
     * @param bmp          The Bitmap of the part we want to add to the destination activity
     * @param loc          The location this part should be on the screen
     * @return
     */
    private static ImageView createImageView(Activity destActivity, Bitmap bmp, int loc[]) {
        MyImageView imageView = new MyImageView(destActivity);
        imageView.setImageBitmap(bmp);
        imageView.setImageOffsets(bmp.getWidth(), loc[0], loc[1]);                     

        WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams();
        windowParams.gravity = Gravity.TOP;
        windowParams.x = 0;
        windowParams.y = loc[2] + loc[0];
        windowParams.height = loc[1] - loc[0];
        windowParams.width = bmp.getWidth();
        windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
        windowParams.format = PixelFormat.TRANSLUCENT;
        windowParams.windowAnimations = 0;
        destActivity.getWindowManager().addView(imageView, windowParams);

        return imageView;
    }

    /**
     * MyImageView
     * Extended ImageView that draws just part of an image, base on start/end position  
     */
    private static class MyImageView extends ImageView
    {
        private Rect mSrcRect;
        private Rect mDstRect;
        private Paint mPaint;       

        public MyImageView(Context context) 
        {
            super(context);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        }

        /**
         * 设置位图来控制可见区域
         *
         * @param width        The bitmap image
         * @param bmp          The start Y position
         * @param loc          The end Y position
         * @return
         */
        public void setImageOffsets(int width, int startY, int endY)
        {
            mSrcRect = new Rect(0, startY, width, endY);
            mDstRect = new Rect(0, 0, width, endY - startY);
        }

        @Override
        protected void onDraw(Canvas canvas)
        {
            Bitmap bm = null;
            Drawable drawable = getDrawable();
            if (null != drawable && drawable instanceof BitmapDrawable)
            {
                bm = ((BitmapDrawable)drawable).getBitmap();
            }

            if (null == bm)
            {
                super.onDraw(canvas);
            }
            else
            {
                canvas.drawBitmap(bm, mSrcRect, mDstRect, mPaint);
            }
        }       
    }
}

原文发布于微信公众号 - 项勇(xiangy_life)

原文发表时间:2017-10-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android干货

安卓开发ScrollView嵌套ListView只显示一行

41280
来自专栏向治洪

android上拉下拉加载更多数据

最近项目中用到了ListView的下拉刷新的功能,总结了一下前辈们的代码,单独抽取出来写了一个demo作为示例。 效果图 下拉刷新: ? 加载更多: ? Cu...

38860
来自专栏Android开发指南

10.下拉刷新、加载更多、标记已读、轮播条、缓存

402100
来自专栏向治洪

android仿ios开关按钮

前一段时间在做项目的时候遇到了一个问题,美工在设计的时候设计的是一个iPhone中的开关,但是都知道Android中的Switch开关和IOS中的不同,这样就...

286100
来自专栏向治洪

android scrollview嵌套listview计算高度的问题

 ScrollView中只能放一个控件,一般都放LinearLayout,orientation属性值为vertical。在LinearLayout中放需要呈...

34160
来自专栏Fish

从相机or相册获取图片并显示

这个技术应该算是十分稀松平常了,但是对于小白来说,还是要费一番功夫的。因此在这里贴上我的代码,也是为了以后用到的时候方便找。。。 package com.exa...

31070
来自专栏Android开发指南

Android自定义指示器时间轴

66370
来自专栏Android开发指南

3.PopupWindow 、拍照、裁剪

32990
来自专栏向治洪

toggbutton

2013年8月14日Android记录 很多应用都会有用户设置,用户的一些偏好可以由用户来决定那是应用人性化的体现,在实际开发中很多情况都作成可配置的了,本篇博...

25490
来自专栏古时的风筝

使用ViewPager+Fragment实现选项卡切换效果

实现效果 本实例主要实现用ViewPage和Fragment实现选项卡切换效果,选项卡个数为3个,点击选项卡或滑动屏幕会切换Fragment并实现选项卡下方下边...

75650

扫码关注云+社区

领取腾讯云代金券