如何通过点和线控制来改变形状

时间:2017-11-10 08:48:05

标签: android android-canvas

我使用下面的代码在自定义视图中创建了一个梯形形状。

    @Override
    protected void onDraw(Canvas canvas) {

        trapezoidPath.moveTo(0,0);
        trapezoidPath.lineTo(getWidth() ,0);
        trapezoidPath.lineTo(getWidth() , altitude);
        trapezoidPath.lineTo(0,getHeight());
        trapezoidPath.lineTo(0,0);
        trapezoidPath.close();

        canvas.drawPath(trapezoidPath,paintTrapezoid);

    }

绘制的形状如下所示。

enter image description here

我想移动(0,高度)指向顶部,直到梯形形状变成矩形。在那之后我想要移动底线直到形状变成一条线。

有没有办法访问创建的路径线,它指向并操纵它们以达到我想要的效果?如果不是我怎么能实现这一目标?

我必须根据用户响应设置此形状的动画。谢谢。

1 个答案:

答案 0 :(得分:0)

使用ObjectAnimator更改onDraw中使用的变量。以下是如何实现此功能的示例。

<强> MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TrapezoidView trapezoidView = findViewById(R.id.trapezoid);
        final Button resetButton = findViewById(R.id.btn_reset);
        resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                trapezoidView.reset();
            }
        });
        final Button animateButton = findViewById(R.id.btn_animate);
        animateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animateButton.setEnabled(false);
                resetButton.setEnabled(false);
                trapezoidView.toNewState();
            }
        });
        trapezoidView.setListener(new TrapezoidView.TrapezoidListener() {
            @Override
            public void onNewState() {
                animateButton.setEnabled(true);
                resetButton.setEnabled(true);
            }
        });

    }
}

<强> TrapezoidView.java

public class TrapezoidView extends View {

    public interface TrapezoidListener {
        void onNewState();
    }

    public static final int TRAPEZOID_STATE = 0;
    public static final int RECTANGLE_STATE = 1;
    public static final int LINE_STATE = 2;

    private int mState = TRAPEZOID_STATE;

    private Paint mTrapezoidPaint;
    private Path mTrapezoidPath = new Path();
    private int mAnimationDuration = 5000; // 5 s in millis

    private float mRectangleHeight = dpTopx(200);
    private float mAltitude = mRectangleHeight;

    private TrapezoidListener mListener;

    public TrapezoidView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mTrapezoidPaint = new Paint();
        mTrapezoidPaint.setColor(Color.BLACK);
        mTrapezoidPaint.setStrokeWidth(5.0f);
        mTrapezoidPaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mTrapezoidPath.reset();
        if (mState == TRAPEZOID_STATE) {
            mAltitude = getHeight();
        }
        mTrapezoidPath.moveTo(0, 0);
        mTrapezoidPath.lineTo(getWidth(), 0);
        if (mState == LINE_STATE) {
            mTrapezoidPath.lineTo(getWidth(), mAltitude);
            mTrapezoidPath.lineTo(0, mAltitude);
        } else {
            mTrapezoidPath.lineTo(getWidth(), mRectangleHeight);
            mTrapezoidPath.lineTo(0, mAltitude);
        }
        mTrapezoidPath.lineTo(0, 0);
        mTrapezoidPath.close();
        canvas.drawPath(mTrapezoidPath, mTrapezoidPaint);
    }

    private float dpTopx(int dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    public float getAltitude() {
        return mAltitude;
    }

    public void setAltitude(float altitude) {
        this.mAltitude = altitude;
        invalidate();
    }

    public void reset() {
        mState = TRAPEZOID_STATE;
        mRectangleHeight = dpTopx(200);
        mAltitude = mRectangleHeight;
        invalidate();
    }

    public void setListener(TrapezoidListener listener) {
        mListener = listener;
    }

    public void toNewState() {
        if (mState == LINE_STATE) {
            mListener.onNewState();
            return;
        }
        float start;
        float target;
        final int targetState = mState == TRAPEZOID_STATE ? RECTANGLE_STATE : LINE_STATE;
        if (targetState == RECTANGLE_STATE) {
            start = getHeight();
            target = mRectangleHeight;
        } else {
            start = mAltitude;
            target = 0.0f;
        }
        ObjectAnimator stateAnimation = ObjectAnimator.ofFloat(TrapezoidView.this, "Altitude", start);
        stateAnimation.setFloatValues(target);
        stateAnimation.setDuration(mAnimationDuration);
        stateAnimation.addListener(
                new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        mState = targetState;
                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mListener.onNewState();
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                }
        );
        stateAnimation.start();
    }
}

<强> activity_main.xml中

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="50dp"
    tools:context="test.example.MainActivity">

    <test.example.TrapezoidView
        android:id="@+id/trapezoid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="0.9" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.1"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_animate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Animate!" />

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Reset" />
    </LinearLayout>

</LinearLayout>