如何在视图底部绘制圆弧段[Android]?

10

我的活动应该看起来像这样:

我不确定展示顶部和底部视图之间圆弧的最佳方式是什么。

我想避免将该段保存为图像。

是否有一种使用drawable xml来显示它的方法(我尝试使用oval实现这一点,但我不知道如何使其变得“平坦”)?

也许可以在canvas上进行绘制?


尝试使用自定义的Shape类传递给ShapeDrawable构造函数来创建ShapeDrawable(很可能需要使用Path#quadTo方法进行绘制)。 - pskink
谢谢您的建议,我会尝试的。 - Vasily Kabunov
仅为了清晰起见,我正在询问您是否需要像您在问题中提供的图像输出一样的输出? - Jitesh Mohite
为什么不在可绘区域(drawable)中只设置背景颜色和一个大圆形呢?如果圆形的80%超出屏幕范围也没关系。或者您可以使用两个矩形(上方和下方)以及一个弧形,使它们都是相同颜色来制作弯曲部分。 - Christian Stengel
@jiteshmohite,没错。我已经删除了不必要的小部件以简化操作,但是活动的背景应该看起来像我附加的图片。 - Vasily Kabunov
1
为什么不只是有一个背景颜色和一个大圆形的 drawable - 不确定如何正确地将圆形移出屏幕区域 - 以便在不同的屏幕尺寸下具有相同的段角度。@ChristianStengel - Vasily Kabunov
1个回答

26
我认为选项3是最好的,你可以精确控制你所绘制的内容,但不会失去面向对象编程的信誉。 选项1 你可以为顶层视图创建自定义 View ,并像这样实现绘制,我在这里子类化了 RelativeLayout ,但你可以子类化任何你想要的 View
public class CurveBgRelativeLayout extends RelativeLayout {

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

    private Path path;
    private Paint paint;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0xffff0000);
        path = new Path();

        float horizontalOffset = w * .8f;
        float top = -h * .8f;
        float bottom = h;

        RectF ovalRect = new RectF(-horizontalOffset, top, w + horizontalOffset, bottom);
        path.lineTo(ovalRect.left, top);
        path.arcTo(ovalRect, 0, 180, false);
        path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (path != null)
            canvas.drawPath(path, paint);

        super.onDraw(canvas);
    }
}

然后在你的xml布局中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.CurveBgRelativeLayout
        android:layout_width="match_parent"
        android:background="#ffffffff"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#ffff0000"
        />
</LinearLayout>



选项2

您可以创建一个XML可绘制对象作为顶部View的背景,唯一的问题在于圆形的水平拉伸是以DP大小给出的,因此它与View的大小无关。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:height="40dp"
        android:gravity="bottom">
        <shape android:shape="rectangle">
            <solid android:color="#ffff0000" />
        </shape>
    </item>
    <item
        android:width="500dp"
        android:height="60dp"
        android:gravity="bottom|center_horizontal"
        android:top="-40dp">
        <shape android:shape="oval">
            <solid android:color="#ffffffff" />    
        </shape>
    </item>
    <item
        android:height="30dp"
        android:bottom="30dp"
        android:gravity="bottom">
        <shape android:shape="rectangle">
            <solid android:color="#ffffffff" />
        </shape>
    </item>
</layer-list>


选项3

public class CurveBottomDrawable extends Drawable {

    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Path path = new Path();

    public CurveBottomDrawable(int color) {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(color);
    }

    @Override
    public void draw(@NonNull Canvas canvas) {

        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0xffff0000);

        path.reset();
        Rect bounds = getBounds();

        float horizontalOffset = bounds.width() * .8f;
        float top = -bounds.height() * .8f;
        float bottom = bounds.height();

        RectF ovalRect = new RectF(-horizontalOffset, top, bounds.width() + horizontalOffset, bottom);
        path.lineTo(ovalRect.left, top);
        path.arcTo(ovalRect, 0, 180, false);
        path.setFillType(Path.FillType.INVERSE_EVEN_ODD);

        canvas.drawPath(path, paint);
    }

    @Override
    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        paint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {
        paint.setColorFilter(colorFilter);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSPARENT;
    }

}

然后以编程方式进行设置

myView.setBackground(new CurveBottomDrawable(0xffff0000));

@akshaybhange,你在看哪个选项? - lelloman
你需要调整水平偏移和顶部的系数(在两种情况下都为0.8f)。 - lelloman
这并没有太大的区别。如果我将系数设置为0.5f,左上角就会变成曲线。 - akshay bhange
这可能意味着画布和边界框的宽度不相同。 - lelloman
API级别23中提供了选项二属性高度。 - aslamhossin
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,