卡片扇形层叠是一种常见的 Android UI 效果,它通过将多个卡片分散放置在一定角度范围内,形成一个类似于扇形的层叠效果。这种效果常用于展示一组相关的内容,例如图片库、商品列表等。

在 Android 中实现卡片扇形层叠效果可以通过自定义 View 或使用现有的第三方库来实现。下面将通过一个简单的示例来演示如何使用自定义 View 来实现卡片扇形层叠效果。

首先,我们需要创建一个自定义 View,并重写其 onMeasureonDraw 方法。onMeasure 方法用于确定 View 的大小,onDraw 方法用于绘制 View 的内容。

public class FanLayout extends ViewGroup {

    private int mRadius; // 扇形的半径
    private int mAngle; // 扇形的张角
    private int mCenterX; // 扇形的中心点横坐标
    private int mCenterY; // 扇形的中心点纵坐标

    public FanLayout(Context context) {
        super(context);
    }

    public FanLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        // 计算扇形的半径为宽度的一半
        mRadius = width / 2;

        // 扇形的张角为根据子 View 的个数平分的总角度
        mAngle = 360 / getChildCount();

        // 设置 View 的大小为宽度和高度中的较小值
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();

        // 计算扇形的中心点坐标
        mCenterX = getWidth() / 2;
        mCenterY = getHeight() / 2;

        // 计算每个子 View 的位置,并进行布局
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);

            // 计算子 View 的左上右下坐标
            int left = (int) (mCenterX - mRadius * Math.cos(Math.toRadians(i * mAngle)));
            int top = (int) (mCenterY - mRadius * Math.sin(Math.toRadians(i * mAngle)));
            int right = (int) (mCenterX + mRadius * Math.cos(Math.toRadians(i * mAngle)));
            int bottom = (int) (mCenterY + mRadius * Math.sin(Math.toRadians(i * mAngle)));

            // 布局子 View
            child.layout(left, top, right, bottom);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int childCount = getChildCount();

        // 绘制每个子 View 的内容
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            drawChild(canvas, child, getDrawingTime());
        }
    }
}

上述代码中,我们通过 onMeasure 方法确定了扇形的半径和张角,通过 onLayout 方法计算并布局了每个子 View 的位置,通过 onDraw 方法绘制了每个子 View 的内容。

接下来,我们可以在布局文件中使用自定义的 FanLayout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
    xmlns:app="
    xmlns:tools="
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.fanlayout.FanLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_red_light"
            android:gravity="center"
            android:text="1" />

        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_green_light"
            android:gravity="center"
            android:text="2