preface
We all know that Android comes with Roate Scale Translate Alpha, a variety of frame animations that we can use to achieve rich animation effects, but these wide animations have a fatal flaw, they just change the size of the View display, Without changing the response area of the View. This is where attribute animations like ObjectAnimator and ValueAnimator come in.
Effect of simple
The working principle of
Property animation word as its name, is to change the View of the property value to change the shape of the control, to put it plainly is through reflection technology to obtain some properties of the control such as width, height, get and set methods, so as to achieve the so-called animation effect. Therefore, this requires our View (as in a custom View) to have set and get methods, otherwise it will cause the program to Clash. Specific steps
- First, the system obtains the property value through the GET method
- Under the action of the time interpolator, the system changes the attribute values
- The system calls the set method to re-assign the property value to the control
It can also be seen that the property animation directly changes the properties of the control, so the control is permanently changed after the animation is over.
Implement four animations using ObjectAnimator
Here I intend to implement four animation frameworks using ObjectAnimator:
- alpha
- scaleX/scaleY
- translateX/translateY
- rotation
Let me show you how ObjectAnimator works
private void iniAnimation(a){
// Transparency animation
ObjectAnimator.ofFloat(mAlphaImage, "alpha".1.0.1)
.setDuration(4000)
.start();
/ / zoom
final AnimatorSet animatorSet = new AnimatorSet();
mScaleImage.setPivotX(mScaleImage.getWidth()+250);
mScaleImage.setPivotY(mScaleImage.getHeight()+250);
animatorSet.playTogether(
ObjectAnimator.ofFloat(mScaleImage, "scaleX".1.0)
.setDuration(2000),
ObjectAnimator.ofFloat(mScaleImage, "scaleY".1.0)
.setDuration(2000)); animatorSet.start();/ / translation translation
final AnimatorSet translationAnimatorSet = new AnimatorSet();
translationAnimatorSet.playTogether(
ObjectAnimator.ofFloat(mTranslationImage, "translationX".20.100)
.setDuration(2000),
ObjectAnimator.ofFloat(mTranslationImage, "translationY".20.100)
.setDuration(2000)); translationAnimatorSet.start();// Use ObjectAnimator to animate the rotation
final AnimatorSet rotateAnimationSet = new AnimatorSet();
rotateAnimationSet.playTogether(
ObjectAnimator.ofFloat(mRotationImage, "rotation".0.360)
.setDuration(2000)); rotateAnimationSet.start(); }Copy the code
The above code is implemented through ObjectAnimator. The four effects can be summarized as follows
- Create an AnimatorSet object
- Set the axis where changes occur (part required)
- Set the animation that needs to change (usually in the playTogether() method)
- Open animation
As shown in the opening animation, we can add multiple animations to a playTogether method to achieve the effect of multiple animation combinations. I won’t repeat it here, but you can try it yourself (the animation in the lower right corner of my GIF is rotation + transparency).
Use ValueAnimator to animate properties
ValueAnimator is a parent of ObjectAnimator. The difference between ObjectAnimator and ValueAnimator is that ObjectAnimator uses reflection technology to animate objects on top of ValueAnimator. ObjectAnimator is given two values (from, to), and after determining the animation type (” scale, translate “) it automatically generates the animation. ValueAnimator does not automatically execute anything. Instead, the ValueAnimator uses the listener method addUpdateListener. Returns a sequence of values that we can then use to set the control.
The instance
FloatingActionButton = FloatingActionButton = FloatingActionButton = FloatingActionButton
Implementation method
This effect can be achieved either through the animation frame or through the property animation. Here I will show you how to achieve this effect. We use ValueAnimator, so it has more ValueAnimator characteristics. After we set the time interpolator to it, it will regularly return a series of numbers. So we just need to set the properties of the control with this series of numbers.
private FloatingActionButton fab;
private ImageView imageView;
private int buttonSize = 0, imageSize = 0;
private float startY = 0;
private float endY = 0;
private ValueAnimator createValueAnimate(final View view, int start, int end){
ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
params.width = (int) animation.getAnimatedValue(); view.setLayoutParams(params); }});return valueAnimator;
}
Copy the code
You can see that we pass in three parameters. Here I’m doing a zoom animation, so I give the control, the current size of the control, and the target size of the control. Then set it based on the value returned by the listener. In terms of invocation, I have implemented pull-up hiding and pull-down display, so we need to determine the sliding direction of the Y-axis:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_UP:
startY = event.getY();
if ((startY - endY) < 0) {/ / to narrow
animationDown(fab, buttonSize);
animationDown(imageView, imageSize);
}else if ((startY - endY) > 0) {Enlarge / /
animationUp(fab, buttonSize);
animationUp(imageView, imageSize);
}
break;
case MotionEvent.ACTION_DOWN:
endY = event.getY();
break;
}
return super.onTouchEvent(event);
}
private void animationDown(final View view, int originalSize){
ValueAnimator animator = createValueAnimate(view, originalSize, 0);
animator.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); view.setVisibility(View.GONE); }}); animator.setInterpolator(new BounceInterpolator());
animator.setDuration(500).start();
}
private void animationUp(final View view, int originalSize){
view.setVisibility(View.VISIBLE);
ValueAnimator animator = createValueAnimate(view, 0, originalSize);
animator.setInterpolator(new BounceInterpolator());
animator.setDuration(500).start();
}
Copy the code
Here we can see that since it is a property animation, the change is directly the size of the control, which causes a problem if the control size is retrieved in real time. So we will not be able to get the original size of the control after we perform the small animation, that is, animationDown. So here we get the control size in the onResume method:
@Override
protected void onResume(a) {
super.onResume();
fab.post(new Runnable() {
@Override
public void run(a) { buttonSize = fab.getHeight(); }}); imageView.post(new Runnable() {
@Override
public void run(a) { imageSize = imageView.getHeight(); }}); }Copy the code
We practice
Property animation can be used as a ViewGroup to increase and reduce the animation and interface transformation is not so abrupt. In fact, careful students may find that Android has its own switching effect, but the form is relatively simple, so HERE I use a custom ObjectAnimator method.
The final result
- First instantiate a LayoutTransition object
- Then through ObjectAnimator. OfPropertyValuesHolder () instantiate one for loading animation
- ObjectAnimator object
- Then the ObjectAnimator. OfPropertyValuesHolder () set in a series of animation effects
- SetAnimation sets the ObjectAnimator to the Transition animation
- Set the Duration execution time for ObjectAnimator
- Set animation delay setStartDelay
Set the Remove animation in the same way
LayoutTransition transition = new LayoutTransition();
ObjectAnimator appendAnimator = ObjectAnimator.ofPropertyValuesHolder(
(ImageView) null,
PropertyValuesHolder.ofFloat("scaleX".0.0 f.1.0 f),
PropertyValuesHolder.ofFloat("scaleY".0.0 f.1.0 f),
PropertyValuesHolder.ofFloat("alpha" , 0.0 f.1.0 f)); appendAnimator.setInterpolator(new BounceInterpolator());
transition.setAnimator(LayoutTransition.APPEARING, appendAnimator);
transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING));
transition.setStartDelay(LayoutTransition.APPEARING, transition.getStartDelay(LayoutTransition.APPEARING));
ObjectAnimator removeAnimator = ObjectAnimator.ofPropertyValuesHolder(
(ImageView) null,
PropertyValuesHolder.ofFloat("scaleX".1.0 f.0.0 f),
PropertyValuesHolder.ofFloat("scaleY".1.0 f.0.0 f),
PropertyValuesHolder.ofFloat("alpha".1.0 f.0.0 f)); removeAnimator.setInterpolator(new BounceInterpolator());
transition.setAnimator(LayoutTransition.DISAPPEARING, removeAnimator);
transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
transition.setStartDelay(LayoutTransition.DISAPPEARING, transition.getStartDelay(LayoutTransition.DISAPPEARING));
Copy the code
And then you just give that LayoutTransition object to your ViewGroup by setLayoutTransition
layout = findViewById(R.id.layout);
layout.setLayoutTransition(transition);
Copy the code
The test link
The test is divided into add control and remove control, function in the activity dynamic execution: add method:
- So I’m going to create a control, and I’m going to use ImageView.
- The size, content and other properties are set
- Call the addView method of the LinearLayout to add controls to the specified position in the layout
Remove method
- First determine whether there are controls in the offline layout
- In some cases, the control is removed
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_add_image:
ImageView imageView = new ImageView(ExtendActivity.this);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setImageResource(R.drawable.heart);
ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(200.200);
imageView.setLayoutParams(params);
layout.addView(imageView,0);
break;
case R.id.btn_remove_image:
int count = layout.getChildCount();
if (count > 0){
layout.removeViewAt(0);
}
break; }}Copy the code
Click https://github.com/FishInWater-1999/android_view_user_defined_first for the Demo project
So far, the use of all attribute animations is basically introduced
Since this is a summary of personal learning, if you have any questions or omissions, please leave a message in the comments section
Happy programming, less code bugs, hahaha