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

How to change shape by controlling it from points and line

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

    @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);

    }

画出来的形状是这样的

我想将 (0,height) 点移到顶部,直到梯形变成矩形。之后我想把底线向上移动直到形状变成一条线。

有没有什么方法可以访问创建的路径线和它的意义并操纵它们来实现我想要的?如果不是我怎么能做到这一点?

我必须根据用户的反应为这个形状制作动画。谢谢。

使用 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>