转场动画--仿京东分类列表跳转商品转场动画

1.本来想用android5.0之后的系统的转场动画(共享元素)去实现

实现方式:

使用共享元素动画的时候,

我们需要首先给当前的Activity和跳转的Activity中的两个button分别添加android:transitionName=”Button”属性, (随便定义字符串)并且该属性的值要相同,这样系统才知道这两个控件是共享元素。

设置完成之后,接下来就是启动Activity的代码了,如下:

startActivity(new Intent(this, TwoActivity.class), ActivityOptions.makeSceneTransitionAnimation (this, view, "Button") .toBundle());

 

由于我们项目使用模块化,用路由跳转的,

实现方式:


ActivityOptionsCompat compat = ActivityOptionsCompat. makeSceneTransitionAnimation((Activity) mContext, holder.ivGoodsIcon, "goods_imageview_transition"); 
ARouter.getInstance() .build(GuoAnRouter.Goods.path_goods_detail) .withString(Gloables.BUNDLE_IMG_URL, content.getImg()) .withOptionsCompat(compat) .navigation((Activity) mContext); //必须加参数 

 

android 5.0需要直接设置style样式,(自行查询)

这样,就可以实现携带图片并且有动画的的转场动画


2.实现效果后,发现点击跳转的时候会有写卡顿,由于我们详情页图片太多,偶尔会出现oom,所有放弃了这种效果

自己实现的步骤:

1.去掉转场效果

2.获取列表的图片的位置,大小信息,传入详情Activity

3.获取传入的图片的详情,在window上创建一个相同信息的view,开启动画

这里需要注意的是,图片drawable的传递(可能方法不是很好,大家有好的方法欢迎推荐)

实现代码:

列表点击:

holder.llGoods.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(final View v) {
                            GoodsIconInfo goodsIconInfo = UIhelper.getGoodsIconInfo(holder.ivGoodsIcon,  content.getImg());
                            ARouter.getInstance()
                                    .build(GuoAnRouter.Goods.path_goods_detail)
                                    .withString(Gloables.BUNDLE_ID, content.getId())
                                    .withParcelable(Gloables.BUNDLE_IMG_URL, goodsIconInfo)
                                    .withTransition(-1, -1)
                                    .navigation();
                        }
                    });
获取图片信息的工具类
public static GoodsIconInfo getGoodsIconInfo(ImageView goodsIcon, String imgUrl) {
        int[] startLocationImag = new int[2];
        goodsIcon.getLocationInWindow(startLocationImag);
        int itemX = startLocationImag[0];
        int itemY = startLocationImag[1];
        GoodsIconInfo goodsIconInfo = new GoodsIconInfo(goodsIcon.getMeasuredWidth(), goodsIcon.getMeasuredHeight(), itemX, itemY, imgUrl);
        goodsIcon.setDrawingCacheEnabled(true);
        //是用application中变量引用的这样可能有漏洞,但是图片传递效率速度快,后面还有第二种方法
        CoreApplication.drawable = Bitmap.createBitmap(goodsIcon.getDrawingCache());
        goodsIcon.setDrawingCacheEnabled(false);
        return goodsIconInfo;
    }
图片的信息类
class GoodsIconInfo(var width: Int, var height: Int, var x: Int, var y: Int,var url:String) : Parcelable {
    constructor(parcel: Parcel) : this(
            parcel.readInt(),
            parcel.readInt(),
            parcel.readInt(),
            parcel.readInt(),
            parcel.readString()) {
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(width)
        parcel.writeInt(height)
        parcel.writeInt(x)
        parcel.writeInt(y)
        parcel.writeString(url)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<GoodsIconInfo> {
        override fun createFromParcel(parcel: Parcel): GoodsIconInfo {
            return GoodsIconInfo(parcel)
        }

        override fun newArray(size: Int): Array<GoodsIconInfo?> {
            return arrayOfNulls(size)
        }
    }

}

详情Activity中

在oncreate()方法中调用startAnimation()

    //图片的信息
    @Autowired(name = Gloables.BUNDLE_IMG_URL)
    GoodsIconInfo mGoodsIconInfo;

    //跟布局
    private ViewGroup mRoot;

    //copy的view
    private ImageView mAddView;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_goods_all_detail_new);
        ARouter.getInstance().inject(this);
        startAnimation();
    }


private void startAnimation() {
        mAddView = new ImageView(this);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mGoodsIconInfo.getWidth(), mGoodsIconInfo.getHeight());
        params.leftMargin = mGoodsIconInfo.getX();
        params.topMargin = mGoodsIconInfo.getY();
        mAddView.setLayoutParams(params);
        mAddView.setImageBitmap(CoreApplication.drawable);
        mRoot = (ViewGroup) this.getWindow().getDecorView();
        mRoot.addView(mAddView);
        ObjectAnimator positionXAnim = ObjectAnimator.ofFloat(mAddView, "translationX", 0f, -mGoodsIconInfo.getX());
        //控件相对于父布局y坐标变换动画
        ObjectAnimator positionYAnim = ObjectAnimator.ofFloat(mAddView, "translationY", 0f, -mGoodsIconInfo.getY() + ResUtil.getStatusHeight(this));
        //控件宽度变换动画
        ValueAnimator sizeAnim = ValueAnimator.ofInt(mGoodsIconInfo.getWidth(), CoreApplication.sScreenWidth);
        sizeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ViewGroup.LayoutParams layoutParams1 = mAddView.getLayoutParams();
                layoutParams1.width = (int) animation.getAnimatedValue();
                layoutParams1.height = (int) animation.getAnimatedValue();
                mAddView.setLayoutParams(layoutParams1);
            }
        });

        //多个动画同时播放
        AnimatorSet animset = new AnimatorSet();
        animset.playTogether(positionXAnim, positionYAnim, sizeAnim);
        animset.setDuration(300);
        animset.setInterpolator(new AccelerateInterpolator());
        animset.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
               
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                 getDetail(false, true);//获取详情接口
            }
        });
        animset.start();
    }

在不要的时候,吧copyview销毁掉

if (mRoot != null) {
                        mRoot.removeView(mAddView);
                    }

想要实现这种效果,必须取消专场动画,指定Activity的主题

 <activity
            android:name=".activity.GoodsAllDetailActivity2"
            android:configChanges="keyboard|orientation"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/GoodsAllDetailActivity"/>
<style name="GoodsAllDetailActivity" parent="AppTheme">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item><!--防止启动闪烁-->
        <item name="android:windowAnimationStyle">@style/Animation</item>
    </style>
    <style name="Animation">
        <item name="android:activityOpenEnterAnimation">@null</item>
        <item name="android:activityOpenExitAnimation">@null</item>
        <item name="android:activityCloseEnterAnimation">@null</item>
        <item name="android:activityCloseExitAnimation">@null</item>
        <item name="android:taskOpenEnterAnimation">@null</item>
        <item name="android:taskOpenExitAnimation">@null</item>
        <item name="android:taskCloseEnterAnimation">@null</item>
        <item name="android:taskCloseExitAnimation">@null</item>
        <item name="android:taskToFrontEnterAnimation">@null</item>
        <item name="android:taskToFrontExitAnimation">@null</item>
        <item name="android:taskToBackEnterAnimation">@null</item>
        <item name="android:taskToBackExitAnimation">@null</item>
    </style>

ok到此基本上好了

上面说到第二种传递图片的方式,因为我们项目用的是glide去加载图片的,glide已经为我们缓存好图片,我们可以通过获取图片,只要图片的url即可,前提是,glide必须要设置diskCacheStrategy方法的缓存策略为DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,还有downloadOnly()方法需要在线程里进行,直接看代码

private class getImageCacheAsyncTask extends AsyncTask<String, Void, File> {
        private final Context context;

        public getImageCacheAsyncTask(Context context) {
            this.context = context;
        }

        @Override
        protected File doInBackground(String... params) {
            String imgUrl = params[0];
            try {
                return Glide.with(context)
                        .load(imgUrl)
                        .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                        .get();
            } catch (Exception ex) {
                return null;
            }
        }

        @Override
        protected void onPostExecute(File result) {
            if (result == null) {
                mBmp = null;
            } else {
                String path = result.getPath();
                BitmapFactory.Options opt = new BitmapFactory.Options();
                // 这个isjustdecodebounds很重要
                opt.inJustDecodeBounds = true;
                mBmp = BitmapFactory.decodeFile(path, opt);
                // 获取屏的宽度和高度
                WindowManager windowManager = getWindowManager();
                Display display = windowManager.getDefaultDisplay();

                // isSampleSize是表示对图片的缩放程度,比如值为2图片的宽度和高度都变为以前的1/2
                opt.inSampleSize = calculateInSampleSize(opt, mGoodsIconInfo.getWidth(), mGoodsIconInfo.getHeight());

                // 这次再真正地生成一个有像素的,经过缩放了的bitmap
                opt.inJustDecodeBounds = false;
                //获取我们想要的bitmap对象
                mBmp = BitmapFactory.decodeFile(path, opt);
            }
            
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
                                            int reqWidth, int reqHeight) {
        // 源图片的高度和宽度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            // 计算出实际宽高和目标宽高的比率
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

应为是异步的,会有时间差,所有没有使用这种方式,当然还有其他很多方式,大家自行查询

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值