英文原文 https://github.com/lgvalle/Material-Animations
这是GitHub上的一个开源项目( 点击传送门 ), 演示View的平移、缩放动画,activity进入和退出动画,界面间元素共享。
了解 Transition Framework
可以在activity之间跳转的时候添加动画
动画共享元素之间的转换活动
activity中布局元素的过渡动画。
| Explode | Slide | Fade |
|---|---|---|
|
|
|
实现这些效果可以通过xml方式或者在直接在类中实现,下面是Fade的实现方式。
### 说明:Fade
res/transition/slide_from_right
<?xml version = 1.0 encoding = "utf-8"?>
<transitionSet xmls:android = "http://schemas.android.com/apk/res/android">
<slide duration = "500"
slideEage = "left"/>
</transitionSet>
2.如果直接用代码实现,可以如下实现
MainActivity
Slide slideTracition = newSlide(); slideTracition.setSlideEdge(Gravity.LEFT); slideTracition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
MianActivity.onCreat();
设置MainActivty的进出动画代码如下
private void setupWindowAnimations() {
Transition slideTracition = TransitionInflater.from(this).inflateTransition(R.transition.slide_from_left);
getWindow().setEnterTransition(slideTracition);
getWindow().setExitTransition(slideTracition);
//getWindow().setReenterTransition(buildExitTransition());
}
返回和重新输入转换分别是Enter和Exit的反向动画。
如果未定义返回或重新输入,Android将按照你之前设定的默认的版本。但是如果你定义它们,你可以有不同的转换进入和退出活动。(如下图)
Visiable slide = new Slide(); slide.setDuraing(500); getWindow.setReturnTransition(slide); //别直接调用finish(); finshAfterTransition();
| Without Return Transition | With Return Transition |
|---|---|
|
|
需要在/res/style.xml添加
<item name="android:windowContentTransitions">true</item>
res/layout/activity
<ImageView
android:id="@+id/square_blue"
style="@style/MaterialAnimations.Icon.Big"
android:src="@drawable/circle_24dp"
android:transitionName="@string/square_blue_name" />
<TextView
android:id="@+id/title"
style="@style/MaterialAnimations.TextAppearance.Title.Invers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:text="@{sharedSample.name}"
android:transitionName="@string/sample_blue_title" />
Intent intent = new Intent(activity,target); ActivityOptionCompat option = ActiviyoptionCampat.makeSceneTransitionAnimation(activity, new Pair<View, String>(viewHolder.binding.sampleIcon, activity.getString(R.string.square_blue_name)), new Pair<View, String>(viewHolder.binding.sampleName, activity.getString(R.string.sample_blue_title))); startActivity(intent,option.toBundle());
需要在/res/style.xml添加
<item name="android:windowContentTransitions">true</item>
之前的俩个步骤和Activity之间共享元素的没有太大差别。
private void addNextFragment(Sample sample, ImageView blue, boolean b) {
SharedElementFragment2 elementFragment2 = SharedElementFragment2.newInstance(sample);
Slide slide = new Slide();
slide.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
slide.setSlideEdge(Gravity.RIGHT);
ChangeBounds changeBounds = new ChangeBounds();
changeBounds.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
elementFragment2.setEnterTransition(slide);
elementFragment2.setAllowEnterTransitionOverlap(b);
elementFragment2.setAllowReturnTransitionOverlap(b);
elementFragment2.setSharedElementEnterTransition(changeBounds);
getFragmentManager().beginTransaction().replace(R.id.sample2_content, elementFragment2).addToBackStack(null).addSharedElement(blue, getString(R.string.square_blue_name)).commit();
}
上面俩种方式都是运用于过度动画,那Transition FrameWork也可以被用做于改变布局中的某个特定的View,比如修改View的位置或者大小。我们需要确定想改变的结果即可。
TransitionManager.beginDelayedTransition(viewRoot);
ViewGroup.LayoutParams params = view.getLayoutParams(); params.witdh = 200; view.setlayoutParams(params);
ViewGroup.LayoutParams params = view.getLayoutParams(); params.gravity = Gravity.Left; view.setlayoutParams(params);
| Size | Position |
|---|---|
|
|
循环显示只是一个动画显示或隐藏一组UI元素。它可以自API21或以上使用。
那我们应该如何监听共享元素的动画结束的时刻。
private void setupEnterAnimations() {
Transition transtion = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
getWindow().setSharedElementEnterTransition(transtion);
transtion.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
hideTarget();
animateRevealShow(toolbar);
animateButtonIn();
}
});
}
res/transition/changebounds_with_arcmotion.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/anim_duration_long"
android:interpolator="@android:interpolator/decelerate_cubic"
>
<changeBounds>
<arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="90"
android:minimumVerticalAngle="0"/>
</changeBounds>
</transitionSet>
ToolBar Animation
private void animateRevealShow(View viewRoot) {
int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2;
int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight());
Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);
viewRoot.setVisibility(View.VISIBLE);
anim.setDuration(1000);
anim.setInterpolator(new AccelerateInterpolator());
anim.start();
}
四个小球的浮现的动画
private void animateButtonIn() {
for (int i = 0; i < bgViewGroup.getChildCount(); i++) {
View child = bgViewGroup.getChildAt(i);
child.animate()
.setStartDelay(100 + i * DELAY)
.setInterpolator(new AccelerateInterpolator())
.alpha(1)
.scaleX(1)
.scaleY(1);
}
}
红色小球的效果
res/transition/changebounds_with_arcmotion.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/anim_duration_long"
android:interpolator="@android:interpolator/decelerate_cubic"
>
<changeBounds>
<arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="90"
android:minimumVerticalAngle="0"/>
</changeBounds>
</transitionSet>
点击红色小球时 执行 revealRed()
private void revealRed() {
final ViewGroup.LayoutParams params = btnRed.getLayoutParams();
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
transition.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
animateRevealColor(bgViewGroup, R.color.sample_red);
body.setText(R.string.reveal_body3);
body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background));
btnRed.setLayoutParams(params);
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
TransitionManager.beginDelayedTransition(bgViewGroup, transition);
final RelativeLayout.LayoutParams relativeRarams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
relativeRarams.addRule(RelativeLayout.CENTER_IN_PARENT);
btnRed.setLayoutParams(relativeRarams);
}
private void animateRevealColor(ViewGroup viewRoot, @ColorRes int color) {
int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2;
animateRevealColorFromCoordinates(viewRoot, color, cx, cy);
}
private Animator animateRevealColorFromCoordinates(ViewGroup root, @ColorRes int color, int cx, int cy) {
int finalRadius = Math.max(root.getWidth(), root.getHeight());
final Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, 0, finalRadius);
root.setBackgroundColor(ContextCompat.getColor(this, color));
animator.setDuration(getResources().getInteger(R.integer.anim_duration_long));
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
return animator;
}