Android 带有边框自定义视图或矢量可绘制对象的按钮叠加层

Android button overlay with border custom view or vector drawable

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

我最终为它制作了自定义视图。但这太麻烦了。

这里是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 但它是设计在底部的

是的,使用矢量可绘制对象作为背景会是一个更好的策略。 Android 支持 svg。只需将 svg 导入您的 res/drawable 文件夹并将其用作按钮的背景。该按钮将自动符合您的需要。 希望这有帮助

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

可绘制背景是最简单的方法,但我发现过去我无法使它像我希望的那样一致地工作。您可能需要同一张图片的多种变体来覆盖多种屏幕尺寸。

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

Indepth Intro To XML Shape Building

Whosebug - Stacking multiple shapes on top of each other in XML

Building A Custom Floating Action Button - XML (2017)

Whosebug - Example of more complex XML Shape using Vector Drawable

还有一个选项在性能方面比您当前的实施要好得多。如果您可以在 link..

中重新实施解决方案,这可能效果最好

Advanced Android Shape Canvas

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

@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);
}