preface
I was on Github and I saw a beautiful login screen. It’s made from Transition. I’ll just paste the address:
MaterialLogin
Of course, if you just take it and use it, it doesn’t make any sense. It’s all about how to do it. I’m going to write down how to do this step by step.
I also wrote a Demo that follows the same principle. The final result looks like this (I copied the layout directly from Github) :
basis
First, let’s look at what Transition is. Transition, not Translate. Let’s go straight to translation:
While Translate usually refers to animation operations that Translate.
The Transition:
So we know we’re doing it in a transitional way, so what is a transition?
The Android 4.4:
Android has more and more animation API support for developers. Drawable Animation and View Animation have existed since API 1, and Property Animation has been added since API 11(Android 3.0). The Transition animation was added to API 19(Android 4.4.2).
I will skip the basics and go straight to the other articles portal:
Android Transition animation parsing basics
Therefore, we can understand it as follows:
Scenes and Transitions. Scenes define the current UI state, while Transitions define the progression of animations from scene to scene.
When a scene changes, transition is responsible for:
(1) Capture the state of each View at the beginning and end of the scene.
(2) Create an Animator based on the difference between the two scenes (start and end).
The Android 5.0
In Android 5.0, Transition can be used to animate activities or fragments in extremely complex ways.
Although in previous versions, Is ready to use the Activity of the overridePendingTransition () and FragmentTransaction setCustomAnimation () to realize the switching Activity or fragments of animation, But they are limited to animating the entire view together. The new Lollipop API goes a step further by allowing individual views to animate when entering or exiting their layout container, and even to share a view among different activities/fragments.
It’s the same as above, but with two Activity screens:
When we jump to the second Activity, we will have a cutscene. Moves the button for the first Activity to the button for the second Activity. The effect is as follows:
So if we look at the following effect, we can see how to achieve it, using the transition animation of the Activity.
You can also check out the links below:
Introduce Activity and Fragment Transition
Understand Content Transition in depth
Learn more about Shared Element Transition
The body of the
Let’s start with the first Activity, which looks like this:
Step 1: Fab button movement:
Let’s move the “+” button to the top:
To start the second Activity, let’s make the interface for the second Activity look like this:
We set the theme of the second Activity to:
<style name="Translucent" parent="Theme.AppCompat.Light.NoActionBar"> // The status bar color of the first activity is#0288D1
<item name="colorPrimaryDark">#0288D1</item>// The background of the second activity is transparent, so you can see the interface of the first activity <item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>
Copy the code
That’s right, we put an “X” button on the second screen, so that we start the second Activity on top of the first, and the Fab button has an animated effect:
The code is simple: make the android:transitionName of the first Activity button the same as the Android :transitionName of the second Activity button. We call this a shared element.
FloatingActionButton btn = findViewById(R.id.fab);;
ActivityOptionsCompat optionsCompat
= ActivityOptionsCompat.makeSceneTransitionAnimation(LoginMainActivity.this,btn,btn.getTransitionName());
startActivity(new Intent(LoginMainActivity.this,RegisterMainActivity.class),optionsCompat.toBundle());
Copy the code
Then use ActivityOptionsCompat to record the state of the fab button for the current Activity. The content is then brought into the second Activity via optionscompat.tobundle () during startActivity. The second Activity will start with the fab button with the same trasitionName as the first Activity’s passed button, and then animate it to its final location. (So the animation is done in the second Activity, except that the button starts with the same state information as the button passed from the first Activity, and then goes to the position set by the end user.)
As we can see, the shared element transformation does not actually implement the sharing of elements between two activities or fragments. In fact, almost all transformations we see (whether B enters or B returns A), the shared element is drawn in B. Instead of really trying to pass an element from A to B, the Framework takes A different approach to achieving the same visual effect. What A passes to B is the state information of the shared element. B uses this information to initialize the shared View elements so that their position, size, and appearance are exactly the same as they were in A. When the transformation begins, all elements in B are invisible except for the shared elements. As the animation progresses, the framework gradually displays B’s activity window, and when the animation is complete, B’s window is fully visible.
And the animation is actually drawn on top of the ViewOverlay. Check out this article: ViewOverlay and Animation
The second step is to make the FAB button change through the curve path:
We’re not going to do anything about it, and by default the fab button’s position changes in a straight line. We would prefer:
We can set the entry animation for shared elements:
<? xml version="1.0" encoding="utf-8"? > <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/linear_out_slow_in"
android:duration="3000">
<changeBounds>
<arcMotion
android:maximumAngle="0"
android:minimumHorizontalAngle="60"
android:minimumVerticalAngle="90" />
</changeBounds>
</transitionSet>
Copy the code
/ / for Transition animation Transition the Transition = TransitionInflater. The from (this). InflateTransition (R.t ransition. Fabtransition); Set the Shared element into the animation getWindow () setSharedElementEnterTransition (transition);Copy the code
I’m using arcMotion here to do the curve path.
ArcMotion document
PathMotion creates a curved path along an arc on an imaginary circle consisting of two points. If the horizontal distance between the points is less than the vertical distance, the center of the circle will be aligned horizontally with the end point. If the vertical distance is less than the horizontal distance, the center of the circle will be aligned vertically with the end point. When two points approach horizontal or vertical, the curve of motion will become smaller because the center of the circle is far from either point. To force the curvature of the path, you can use setMinimumHorizontalAngle (float) and setMinimumVerticalAngle (float) to set the minimum Angle of arc between two points.
Other references:
Curved motion minus one
Curved motion minus 2
Step 3: The registration interface will appear after the fab button animation ends:
We set up the transition animation for the Fab button last step. We can set the end of this transition animation to listen, and then the rest of our registration screen appears:
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.fabtransition);
getWindow().setSharedElementEnterTransition(transition);
transition.addListener(new Transition.TransitionListener() {... . @Override public void onTransitionEnd(Transition transition) { transition.removeListener(this); /* We can write code here to make the registration screen appear */..... after the animation is over . }});Copy the code
Here is the layout of our second Activity changed to this:
By default, the sign-up screen is not visible until our Fab button animation is complete.
In this case, we can directly make the registration screen appear at the end of the fab button animation (because the registration screen is written in CardView, so we use CardView to refer to the instance), and we can directly set it in the end listener above:
@Override public void onTransitionEnd(Transition transition) { transition.removeListener(this); SetVisibility (view.visible); }Copy the code
The effect is as follows:
We found that the direct appearance, although the function is implemented, but we still want to look better, like the beginning of the article, the registration screen is slowly expanded. So we don’t just set view.visible to cardView after the Fab button transition animation is over. We use the reveal animation to achieve:
Animator mAnimator = ViewAnimationUtils. CreateCircularReveal (cardView, cardView getWidth () / 2, 0, 0, cardView. GetHeight ()); mAnimator.setDuration(500); mAnimator.setInterpolator(new AccelerateInterpolator()); mAnimator.addListener(newAnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); cardView.setVisibility(View.VISIBLE); }}); mAnimator.start();Copy the code
Expose animation Reference article:
Add a revealing animation to your application using Circular Reveal
So when we use it this way, it looks like:
Step 4 Return to the login interface:
Here are two ways:
- Press the back button on your phone
- Press the Fab button to return
Our Fab button moves up from the left, and if you press the Back button, you’ll notice that the automatic Fab button will perform the corresponding auto-back animation before closing the activity. For example, if you set the click event directly to the Fab key:
btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); }});Copy the code
If you call finish() directly, you’ll see that instead of the fab key returning the animation, the second activity closes and the first activity is displayed. It’s not very friendly.
We know that the default return key is called:
@Override
public void onBackPressed() {
super.onBackPressed();
}
Copy the code
OnBackPressed calls finish() after the animation is finished;
Reference article:
The difference between onBackPressed() and Finish () for the most common activities.
So we know that clicking the Fab key doesn’t return us with finish, but the last step is to call super.onBackPressed(); .
So we end up making the registration screen fade away and then calling super.onBackPressed(); .
// Overwrite the return key operation, // perform the registration screen disappear animation, // then execute super.onbackpressed (); @Override public voidonBackPressed() { animateRevealClose(); } // Fab click events are the same as above btn.setonClickListener (new View).OnClickListener() { @Override public void onClick(View view) { animateRevealClose(); }}); // The registration screen fades away, then a call to super.onBackPressed() is called, then the Fab key animates back to the original position, and the second Activity closes. // Then display the first Activity public voidanimateRevealClose(){
Animator mAnimator = ViewAnimationUtils.createCircularReveal(cardView,cardView.getWidth()/2
,0,cardView.getHeight(),0);
mAnimator.setDuration(500);
mAnimator.setInterpolator(new AccelerateInterpolator());
mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); cardView.setVisibility(View.GONE); btn.setImageResource(R.drawable.plus); RegisterMainActivity.super.onBackPressed(); }}); mAnimator.start(); }Copy the code
The final implementation looks like this:
conclusion
Thank you for your support. O ( ̄)  ̄) O
Thank you very much if you can help me answer the following two questions:
-
When I use arcMotion, mi 5 (6.0) and Huawei (7.0) present a very different curve effect. (The GIF is from Mi, so the fab key moves more like a straight line, but Huawei obviously has a curve.) I don’t know the reason, please tell me if you know.