首页 > 解决方案 > 带有边框自定义视图或矢量可绘制的 Android 按钮叠加层

问题描述

我想创建一个带有圆形框架的自定义浮动操作按钮。像下图

在此处输入图像描述

我最终为它制作了一个自定义视图。但它是如此的故障。

这是onDraw功能

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    val cx = (width / 2).toFloat()
    val cy = (height / 2).toFloat()

    val hShift = outerRadius * .4
    val vShift = outerRadius * .05

    circle.set(
        (cx - outerRadius - hShift).toFloat(), (cy - 3 * outerRadius + vShift).toFloat(),
        (cx + outerRadius- hShift).toFloat(), (cy - outerRadius+vShift).toFloat()
    )
    path.arcTo(circle, 0F, 85F)

    path.lineTo(cx,cy-outerRadius)

    circle.set(cx - outerRadius, cy - outerRadius, cx + outerRadius, cy + outerRadius)
    path.arcTo(circle, 90F, 180F)
    path.lineTo(cx,cy-outerRadius)

    path.lineTo(cx, cy+outerRadius)

    circle.set(
        (cx - outerRadius- hShift).toFloat(), (cy + outerRadius - vShift).toFloat(),
        (cx + outerRadius- hShift).toFloat(), (cy + 3 * outerRadius - vShift).toFloat()
    )
    path.arcTo(circle, 275F, 90F)

    canvas.drawPath(path, paint)
}

我的问题:这是正确的方法吗? 我在想一个可绘制的矢量作为背景

PS:我也试过BottomNavigationView,但它在设计的底部

标签: androidxmlandroid-custom-viewvector-graphicsandroid-vectordrawable

解决方案


避免在 onDraw() 方法中进行计算,因为每次都会调用它,这对应用程序的性能不利

可绘制的背景是最简单的方法,但我过去发现我无法让它像我想要的那样一致。您可能需要同一图像的多个变体来覆盖多个屏幕尺寸。

一种选择是使用 XML 形状设计您的定制工厂。虽然这不是我的专业领域,但我有一些资源可以提供帮助。

XML 形状构建的深入介绍

Stackoverflow - 在 XML 中堆叠多个形状

构建自定义浮动操作按钮 - XML (2017)

Stackoverflow - 使用 Vector Drawable 的更复杂 XML 形状的示例

还有另一种选择,它的性能比您当前的实现要好得多。如果您可以在链接中重新实现解决方案,这可能效果最好。

高级 Android 形状画布

该链接是关于使用三次贝塞尔曲线在底栏上构建一个形状,看起来您可以在任何视图类型上使用它,而不仅仅是如图所示的底栏。我将发布此链接用于了解不同之处的相关代码。

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

    //point calculation 

    mPath.reset();
    mPath.moveTo(0, 0);
    mPath.lineTo(mFirstCurveStartPoint.x, mFirstCurveStartPoint.y);

    mPath.cubicTo(mFirstCurveControlPoint1.x, mFirstCurveControlPoint1.y,
            mFirstCurveControlPoint2.x, mFirstCurveControlPoint2.y,
            mFirstCurveEndPoint.x, mFirstCurveEndPoint.y);

    mPath.cubicTo(mSecondCurveControlPoint1.x, mSecondCurveControlPoint1.y,
            mSecondCurveControlPoint2.x, mSecondCurveControlPoint2.y,
            mSecondCurveEndPoint.x, mSecondCurveEndPoint.y);

    mPath.lineTo(mNavigationBarWidth, 0);
    mPath.lineTo(mNavigationBarWidth, mNavigationBarHeight);
    mPath.lineTo(0, mNavigationBarHeight);
    mPath.close();
}

你的 OnDraw 最终会是什么样子 -

  @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPath(mPath, mPaint);
}

推荐阅读