Android - 自定義極座標佈局的那個人肯定沒學過 ConstraintLayout

極座標系相對於笛卡爾座標系,使用角度和半徑來指定點的位置。通過三角函數公式,兩者可以互相轉換,本質上並沒有區別。

那麼使用極座標佈局的意義在哪裏呢?既然是使用角度和半徑的,如果基於角度和半徑可以方便地做出一些效果,那就能提高開發的效率,使代碼更加簡潔。

ConstraintLayout 中對極座標的支持非常直接,ConstraintLayout 的核心思維就是靠關係,在極座標佈局中,就是作爲圓心的 View 與其他 View 之間通過半徑和角度產生的關係。

使用方法

作爲圓心的 View 不用設置任何極座標相關屬性。除非它相對於另一個圓心以極座標佈局。

圍繞這個圓心的其他 View 需要設置 3 個 LayoutParams 屬性:

  • layout_constraintCircle 指定圓心 View 的 id
  • layout_constraintCircleAngle 指定角度,單位是度°。官方文檔中說是 0 - 360 度,實際上可以設置大於 360 度的值。0 度的方向是豎直向上,順時針角度增大,和鐘錶的數字刻度一樣。用 ConstraintLayout 畫個錶盤很方便有木有。
  • layout_constraintCircleRadius 指定半徑,dimension。

代碼示例

<Button
    android:id="@+id/button_center"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    android:text="Center"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<ImageView
    android:id="@+id/imageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#900000"
    app:layout_constraintCircle="@id/button_center"
    app:layout_constraintCircleAngle="0"
    app:layout_constraintCircleRadius="100dp"
    app:srcCompat="@android:drawable/ic_menu_camera" />

做個動畫

屬性動畫,轉個圈圈。

private void animate() {
    // 代碼裏角度可以用負值。
    PropertyValuesHolder holderAngle = PropertyValuesHolder.ofFloat("angle", 0, -90, -180, -270);
    PropertyValuesHolder holderRadius = PropertyValuesHolder.ofInt("radius", 0, 100, 200, 300);
    ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(circleAdapter, holderAngle, holderRadius);
    animator.setDuration(2000);
    animator.start();
}
// 沒有屬性可以直接設置角度和半徑,自定義一個對象來 adapt 這兩個屬性。
private static class CircleAdapter {
    private View view;
    public CircleAdapter(View view) {
        this.view = view;
    }
    public float getAngle() {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (lp instanceof ConstraintLayout.LayoutParams) {
            return ((ConstraintLayout.LayoutParams) lp).circleAngle;
        }
        return 0;
    }
    public void setAngle(float angle) {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (lp instanceof ConstraintLayout.LayoutParams) {
            ((ConstraintLayout.LayoutParams) lp).circleAngle = angle;
            view.requestLayout();
        }
    }
    public int getRadius() {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (lp instanceof ConstraintLayout.LayoutParams) {
            return ((ConstraintLayout.LayoutParams) lp).circleRadius;
        }
        return 0;
    }
    public void setRadius(int radius) {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (lp instanceof ConstraintLayout.LayoutParams) {
            ((ConstraintLayout.LayoutParams) lp).circleRadius = radius;
            view.requestLayout();
        }
    }
}

題圖:Pixabay License

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章