谷歌官方文档 给了一个 通过共享元素启动Activity的Demo Demo很流畅,图片过渡很自然,但是由于两个页面的TextView大小不同(颜色不同会更加突兀),在动画开始和结束的时候TextView变化很突兀。 这篇博客在共享元素的基础上进一步自定义TextView的动画,使之过度更加自然
谷歌Demo效果展示 改进后效果展示
官方调用
这里不分析源码是怎么实现的,因为我还没彻底搞懂…… 所以只简单贴一下调用方法 从ActivityA启动ActivityB时设置共享元素imageview_item和textview_name ActivityA.java
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra(DetailActivity.EXTRA_PARAM_ID, item.getId());
ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
MainActivity.this,
new Pair<>(view.findViewById(R.id.imageview_item),
DetailActivity.VIEW_NAME_HEADER_IMAGE),
new Pair<>(view.findViewById(R.id.textview_name),
DetailActivity.VIEW_NAME_HEADER_TITLE)
);
ActivityCompat.startActivity(MainActivity.this, intent, activityOptions.toBundle());
同样在ActivityB中也设置这两个共享元素
private ImageView mHeaderImageView;
private TextView mHeaderTitle;
@Override
protected void onCreated(Bundle saveInstanceState){
...
HeaderImageView = findViewById(R.id.imageview_header);
mHeaderTitle = findViewById(R.id.textview_title);
ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);
...
}
就这么简单。具体代码去看谷歌Demo
但是因为Demo中的textview这个共享元素在两个页面的字体不一样,所以过度很突兀
页面跳转共享元素动画实际上是先加载好ActivityB的textview,然后开始动画,所以看到在进入动画的时候,textview的字体样式突然变成了ActivityB的样式
自定义Transition
ActivityA的代码不变 ActivityB的代码略作修改
private ImageView mHeaderImageView;
private TextView mHeaderTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mHeaderImageView = findViewById(R.id.imageview_header);
mHeaderTitle = findViewById(R.id.textview_title);
ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);
configEnterExitAnimation(true);
postponeEnterTransition();
...
startPostponedEnterTransition();
}
配置enter和exit的动画属性
private void configEnterExitAnimation(boolean isEnter) {
TextviewTransition textviewTransition = new TextviewTransition(isEnter);
textviewTransition.addTarget(R.id.textview_title);
ChangeBounds textviewChangeBounds = new ChangeBounds();
textviewChangeBounds.addTarget(R.id.textview_title);
ChangeBounds imageChangeBounds = new ChangeBounds();
imageChangeBounds.addTarget(VIEW_NAME_HEADER_IMAGE);
TransitionSet set = new TransitionSet()
.addTransition(textviewTransition)
.addTransition(textviewChangeBounds)
.addTransition(imageChangeBounds)
.setDuration(1500);
this.getWindow().setSharedElementEnterTransition(set);
}
自定义的TextView的Transition类,用来管理文字颜色和大小的动画过度
class TextviewTransition extends Transition {
private boolean mIsEnter = true;
public TextviewTransition(boolean isEnter) {
mIsEnter = isEnter;
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
return createEnterAnimator(startValues, endValues);
}
private Animator createEnterAnimator(TransitionValues startValues, TransitionValues endValues) {
ObjectAnimator textSizeAnimator = ObjectAnimator.ofFloat((TextView) startValues.view,
new Property<TextView, Float>(Float.class, "textSize") {
@Override
public void set(TextView object, Float value) {
object.setTextSize(TypedValue.COMPLEX_UNIT_PX, value);
}
@Override
public Float get(TextView object) {
return object.getTextSize();
}
},
mIsEnter ? getResources().getDimensionPixelOffset(R.dimen.text_size_start) :
getResources().getDimensionPixelOffset(R.dimen.text_size_end),
mIsEnter ? getResources().getDimensionPixelOffset(R.dimen.text_size_end) :
getResources().getDimensionPixelOffset(R.dimen.text_size_start)
);
ObjectAnimator textColorAnimator = ObjectAnimator.ofArgb((TextView) startValues.view,
new Property<TextView, Integer>(Integer.class, "textColor") {
@Override
public void set(TextView object, Integer value) {
object.setTextColor(value);
}
@Override
public Integer get(TextView object) {
return object.getCurrentTextColor();
}
},
mIsEnter ? getResources().getColor(R.color.start_color, null) :
getResources().getColor(R.color.end_color, null),
mIsEnter ? getResources().getColor(R.color.end_color, null) :
getResources().getColor(R.color.start_color, null)
);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(textSizeAnimator, textColorAnimator);
return animatorSet;
}
}
简单分析下就是TextviewTransition类中包含了两个动画,一个是TextView的大小,另一个是TextView的颜色 然后整体的页面过度动画TransitionSet又包含三个:TextView大小颜色动画(TextviewTransition)、TextView大小和位置动画,ImageView大小和位置动画。这样就能在谷歌Demo的基础上让文字过度更加自然。(这里没有处理字重过度的问题 ,感兴趣可以去拓展)
ChangeBounds: View的大小与位置动画 ChangeTransform: View的缩放与旋转动画 ChangeClipBounds: View的裁剪区域(View.getClipBounds())动画 ChangeScroll: 处理View的scrollX与scrollY属性 ChangeImageTransform: 处理ImageView的ScaleType属性 参考简书
效果不是很完美(包括字重过度、动画启动结束时TextView内容换行问题),但已经实现了TextView大小和动画的过度。
项目代码已传GitHub
|