如何在纵向和横向的 Android 背景上创建纯色圆弧

How to create Arc with solid colour on Android background in Portrait and landscape

我当前的 Android 应用程序 UI 需要一个双色调背景和一个弯曲的圆弧作为边框,如下图所示

我可以在肖像中实现这种效果(虽然我不喜欢使用负边距值)如下...

    <ImageView
        android:id="@+id/backgroud_arc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="-150dp"
        android:layout_marginEnd="-150dp"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:src="@drawable/background_circle" />

背景圆是这个可绘制的形状

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/background" />
    <size
        android:width="120dp"
        android:height="60dp" />
    <corners
        android:bottomLeftRadius="60dp"
        android:bottomRightRadius="60dp" />
</shape>

有没有更简单的方法可以达到我想要的效果?

在风景中,这个可绘制对象被严重“剪裁”。

与其使用不灵活的可绘制背景,不如在 canvas 上绘制颜色和曲线。

为此,我们创建了一个自定义视图 ArcBackgroundView,如下所示。代码不言自明:

import android.content.Context
import android.content.res.Configuration
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat

class ArcBackgroundView(context: Context, attrs: AttributeSet) : View(context, attrs) {
    private val paint = Paint()
    private val path = Path()

    init {
        paint.isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (canvas == null) {
            return
        }
        // Draw background color
        canvas.drawColor(ContextCompat.getColor(context, R.color.blue))

        // Draw curve portion of background
        // Setup color
        paint.color = ContextCompat.getColor(context, R.color.white)

        val curveStartAndEndY = 0.6f * measuredHeight // <------ You can change this value based on your requirement
        // Set curve's control point's Y position (downwards bulge of curve) based on orientation
        var curveControlPointY = measuredHeight / 1.4f // <------ You can change this value based on your requirement
        if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            // Since in landscape mode, the curve will have greater arc length,
            // we need to give the curve more downwards bulge as compared to that in portrait mode.
            curveControlPointY = measuredHeight / 1.2f // <------ You can change this value based on your requirement
        }
        // Now we draw the entire path for curve
        path.moveTo(0f, curveStartAndEndY)
        path.quadTo(
            measuredWidth / 2f,
            curveControlPointY,
            measuredWidth.toFloat(),
            curveStartAndEndY
        )
        path.lineTo(measuredWidth.toFloat(), 0f)
        path.lineTo(0f, 0f)
        path.lineTo(0f, curveStartAndEndY)
        canvas.drawPath(path, paint)
    }
}

ArcBackgroundView 现在可以在 xml 中使用,如下所示:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.myapp.ArcBackgroundView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

纵向和横向的结果输出如下所示:

除了如图所示创建自定义视图外,如果需要,您还可以创建一个名为 ArcBackgroundFrameLayout 的自定义视图 FrameLayout。将 onDraw() 的代码复制粘贴到您的 ArcBackgroundFrameLayout's onDraw() 中。现在您可以直接使用自定义容器,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<com.example.myapp.ArcBackgroundFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@color/teal_200"
        android:gravity="center"
        android:text="THIS IS A TEXT VIEW ON TOP OF THE DUAL TONE BACKGROUND"
        android:textSize="28sp"
        android:textStyle="bold" />
</com.example.myapp.ArcBackgroundFrameLayout>

注意 android:background="@color/black" 添加了 ArcBackgroundFrameLayout。必须为容器添加一些背景(不一定是黑色),否则不会调用#onDraw()。您不必担心这种黑色,因为它不会显示。我们正在从覆盖的 onDraw().

内部更改背景颜色

纵向和横向的结果输出如下所示:

如果您有任何其他要求,请告诉我。我会编辑这个答案。

代码在 Kotlin 中。如果您的项目在 Java,请再次告诉我。我可以编辑并提供相同的 Java 版本。

谢谢。