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;
}
应为是异步的,会有时间差,所有没有使用这种方式,当然还有其他很多方式,大家自行查询