Property animation shortcomings and improvements
1, the disadvantages
Property animation is really fun to use, and many animation effects can be achieved using property animation. Here are a few typical usage scenarios:
1.1. Code is difficult to reuse
view.animate()
.traslationX(10.20)
.alpha(0.1)
.start();
Animator animator = ObjectAnimator.ofFloat(view,"TranslationX".10.20.30);
animator.start();
Copy the code
The code is simple and intuitive to write. But it’s hard to reuse, and if I need the same animation somewhere else, I have to write the same code all over again.
1.2. Size information cannot be obtained
Most of the time we need to animate based on some size information:
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private LinearLayout mLinearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.txt);
mLinearLayout = (LinearLayout)findViewById(R.id.txt);
//mLinearLayout is the parent of mTextView,
// Move mTextView 10px to the right of mLinearLayout
int distance = mLinearLayout.getWidth() - 10- mTextView.getRight(); mTextView.animate() .TranslationX(distance) .start(); }}Copy the code
The above code does not work as expected because the view is drawn on a different thread than the Activity is created on, and the view dimensions are not available in onCreate(). But a lot of times, we need some size information to animate. The API provided by the system is in px, not dp.
1.3. Complex animation implementation is not simple enough
Animatorsets can execute multiple animators together or sequentially, but to execute multiple animatorsets sequentially, we have to write:
mAnimatorSet1.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
mAnimatorSet2.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
mAnimatorSet3.start()
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimatorSet2.start();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimatorSet1.start();
Copy the code
As you can see, the code is a little bit cumbersome.
2,The solution
This is a property animation encapsulating library that solves the problem mentioned above, using the following method:
- Add the dependent
The root directory build
allprojects {
repositories {
jcenter()
maven {
url 'https://dl.bintray.com/zouzhihao/maven'}}}Copy the code
Project build
compile 'com. Runningzou. Leptanimator: library: 0.0.1'
Copy the code
- Define a LeptAnimator subclass
public class SimpleAnimator extends LeptAnimator {
// This constructor must be overridden. View represents the control that needs to animate and the control that needs to measure dimension information
public SimpleAnimator(View... view) {
super(view);
}
// Target is the view passed in the constructor
// These views can be used to animate or measure dimensions
@Override
public AnimatorBuilder prepare(View... target) {
AnimatorBuilder provides many useful methods
return AnimatorBuilder
.animate(target[0]) 1 / / animationTranslationX (100) Dp / / unit
.ParentTop(10) // 10dp from the top
.duration(1000)
.with(target[1]) // Animation 2, animation 2 is executed synchronously with animation 1
.leftof(target[3].10); // Target [1] is moved to the right of target[3] at a distance of 10dp
.alpha(0.1)
.after(target[2]) // Animation 3, animation 1, animation 1, animation 3TranslationX (100); }}Copy the code
- use
LeptAnimator animator = new SimpleAnimator(view1,view2,view3,view4);
animator.start();
animator.setStartListener(new ViewAnimatorListener.startListener() {
@Override
public void onAnimatorStart(a) {
Log.d("tag"."Animation starts"); }}); animator.setEndListener(new ViewAnimatorListener.endListener() {
@Override
public void onAnimatorEnd(a) {
Log.d("tag"."End of animation"); }});Copy the code
3. Has the problem been solved?
3.1 code reuse
In this wrapper library, animations are encapsulated into classes, such as the SimpleAnimator example, which can be used by simply passing in a new object and the view to operate on. I’m going to say, I’m going to write my animation in XML, and I’m going to load it in code. I have always found it unelegant to write animations in XML. Code can be done very easily (get an Animator instance in a few lines of code). In addition to increasing the number of files and lines of code, writing in XML leads to increased IO operations and decreased efficiency (read files, parse files).
3.2 Size information cannot be obtained
The prepare method for LeptAnimator runs something like this
view.post(new Runnable(){
public void run(a) { prepare(); }})Copy the code
So during the process of preparing the animation (i.e. in the prepare method), you can get the size information of the view.
For example: Place the view view close to the right boundary of the parent layout with margin DP
public class SimpleAnimator extends LeptAnimator {
@Override
public AnimatorBuilder prepare(View... targets) {
View view = targets[0];
View ParentView = (View) view.getParent();
int distance = ParentView.getWidth() - view.getLeft() - view.getWidth() - DistanceUtil.dp2px(10);
return newAnimatorBuilder() .translationX(distance); }}Copy the code
It is now possible to calculate the size of a view, but it is still a bit of a hassle to calculate it every time, so the library’s AnimatorBuilder class provides several methods to simplify your sizing
Margin dp public AnimatorBuilder parentTop(int margin) // Place View close to the bottom of parent layout, ParentBottom (int margin) public AnimatorBuilder parentBottom(int margin) ParentLeft (int margin) public AnimatorBuilder parentLeft(int margin) Public AnimatorBuilder parentRight(int margin) // Move View to the left of target, RigntMargin public AnimatorBuilder leftof(View target, Public AnimatorBuilder rightof(View Target, int margin) public AnimatorBuilder topof(View target, int margin) public AnimatorBuilder bottomof(View target, int margin)Copy the code
All distances in the library are in dp. With these methods, the code above can be changed
public class SimpleAnimator extends LeptAnimator {
@Override
public AnimatorBuilder prepare(View... targets) {
return new AnimatorBuilder()
.parentRignt(10); }}Copy the code
With a combination of these methods, it’s much easier to achieve some cool effects.
3.3. Complex animation implementation is not simple enough
Look at the sample code
public class SimpleAnimator extends LeptAnimator {
// This constructor must be overridden. View represents the control that needs to animate and the control that needs to measure dimension information
public SimpleAnimator(View... view) {
super(view);
}
// Target is the view passed in the constructor
// These views can be used to animate or measure dimensions
@Override
public AnimatorBuilder prepare(View... target) {
AnimatorBuilder provides many useful methods
return AnimatorBuilder
.animate(target[0]) 1 / / animationTranslationX (100) Dp / / unit
.ParentTop(10) // 10dp from the top
.duration(1000)
.with(target[1]) // Animation 2, animation 2 is executed synchronously with animation 1
.leftof(target[3].10); // Target [1] is moved to the right of target[3] at a distance of 10dp
.alpha(0.1)
.after(target[2]) // Animation 3, animation 1, animation 1, animation 3TranslationX (100); }}Copy the code
- With allows you to define synchronously executed animations
- After allows you to define sequentially executed animations
4, eggs
The library provides an interesting feature
// Sets the percentage of animation execution, 0.5 means half animation execution. LeptAnimator. Setpercent (0.2);Copy the code
This feature can be used to achieve some interesting effects, such as ScrollActivity in the demo (see the GIF in the next section)
5 or more
See demo for more usage, below is the demo renderings.
6, thank you
The implementation process of the library is based on the following open source projects:
- ViewAnimator
- AndroidViewAnimations