单一自定义视图多种形状的动画

时间:2018-12-11 16:09:07

标签: android

如果自定义视图具有多种形状,是否可以仅对其中一种进行动画处理? 例如:对于我的一个应用程序,在自定义视图上绘制了2个圆,一个内圆和另一个外圆。当我尝试使用比例动画制作动画时,我看到两个圆圈都被动画化了,因为我只需要其中一个就可以。 我想到的解决方案之一是拥有多个自定义视图。 但是不确定这是否是正确的方法。 有其他更好的解决方案吗?

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.test.customanimation.CustomView
    android:id="@+id/circular_progress"
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:layout_gravity="center"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

<Button
    android:id="@+id/scale_up"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Scale Up"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    />

<Button
    android:id="@+id/scale_down"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:text="Scale Down"/>

</android.support.constraint.ConstraintLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

private CustomView mCustomView;
private Button mScaleUpBtn;
private Button mScaleDownBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mCustomView = findViewById(R.id.circular_progress);

    mScaleUpBtn = findViewById(R.id.scale_up);
    mScaleUpBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mCustomView.scaleUpAnimation(5000);
        }
    });

    mScaleDownBtn = findViewById(R.id.scale_down);
    mScaleDownBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mCustomView.scaleDownAnimation(5000);
        }
    });

   }
}

CustomView.java

public class CustomView extends View {
private Paint OuterCirclePaint,InnerCirclePaint;

float mCircleX,mCircleY,mInnerCircleRadius,mOuterCircleRadius;

public CustomView(Context context) {
    super(context);
    init();
}

public CustomView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
}

public CustomView(Context context, @Nullable AttributeSet attrs, int 
defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

public CustomView(Context context, @Nullable AttributeSet attrs, int 
defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init();
}

private void init(){
    OuterCirclePaint = new Paint();
    OuterCirclePaint.setColor(Color.GREEN);
    OuterCirclePaint.setStrokeWidth(20);
    OuterCirclePaint.setStyle(Paint.Style.STROKE);

    InnerCirclePaint = new Paint();
    InnerCirclePaint.setColor(Color.BLACK);
    InnerCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}

@Override
protected void onDraw(Canvas canvas) {
    mCircleX = getWidth()/2;
    mCircleY = getHeight()/2;

    if(mCircleX < mCircleY) {
        mInnerCircleRadius = (getWidth() / 2) - 100;
        mOuterCircleRadius = (getWidth() / 2) - 40;
    }
    else {
        mInnerCircleRadius = (getHeight() / 2) - 100;
        mOuterCircleRadius= (getHeight() / 2) - 40;
    }


canvas.drawCircle(mCircleX,mCircleY,mOuterCircleRadius,OuterCirclePaint);
canvas.drawCircle(mCircleX,mCircleY,mInnerCircleRadius,InnerCirclePaint);
}

public void scaleDownAnimation(int duration){
    ScaleAnimation fade_in = new ScaleAnimation(1.0f,0.5f,1.0f,0.5f,
         Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
    fade_in.setDuration(duration);
    fade_in.setFillAfter(true);
    this.startAnimation(fade_in);
}

public void scaleUpAnimation(int duration){
   ScaleAnimation fade_out = new ScaleAnimation(0.5f,1.0f,0.5f,1.0f,
       Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
   fade_out.setDuration(duration);
   fade_out.setFillAfter(true);
   this.startAnimation(fade_out);
}
}

1 个答案:

答案 0 :(得分:1)

您已经覆盖onDraw(),并提供了自己的方法来处理动画。 IMO这种方法最适合性能,因此我会保持这种方式,只切换到另一个动画框架,即Property Animations

为了在动画过程中仅重绘内圆,我建议对动画使用ValueAnimatorValueAnimator.AnimatorUpdateListener

让我们为CustomView

引入一些新字段
private float scaleFactor = 1f;
private ValueAnimator scaleUpAnimator;
private ValueAnimator scaleDownAnimator;
private ValueAnimator.AnimatorUpdateListener updateListener;

按如下所示初始化它们

private void initAnimations() {
    scaleUpAnimator = ValueAnimator.ofFloat(0.5f, 1.0f);
    scaleDownAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
    updateListener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            scaleFactor = (float)animation.getAnimatedValue();
            CustomView.this.invalidate();
        }
    };
    scaleUpAnimator.addUpdateListener(updateListener);
    scaleDownAnimator.addUpdateListener(updateListener);
}

更改onDraw()内圈的线

canvas.drawCircle(mCircleX, mCircleY, mInnerCircleRadius * scaleFactor, innerCirclePaint);

...并开始这样的动画

public void scaleDownAnimation(int duration){
    scaleDownAnimator.setDuration(duration);
    scaleDownAnimator.start();
}

public void scaleUpAnimation(int duration){
    scaleUpAnimator.setDuration(duration);
    scaleUpAnimator.start();
}