1

I would like to create a custom Floating action button with a round frame. like the following image

enter image description here

I ended up making a custom view for it. But it's so glitchy.

Here is the onDraw function

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

My question: is this the right way to do it? I was thinking of a vector drawable as a background

PS: I also tried BottomNavigationView but it's on the bottom by design

abd3lraouf
  • 1,438
  • 1
  • 18
  • 24

2 Answers2

1

Avoid doing calculations in the onDraw()method because it is called each time and it is not good for the performance of your application

A drawable background is the easiest way to do it, but I have found in the past I could not get this to work as consistent as I would like. You may need multiple variations of the same image to cover multiple screen sizes.

One option is designing your custom fab using XML shapes. While this isn't my area of expertise I have some sources that would help.

Indepth Intro To XML Shape Building

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

Building A Custom Floating Action Button - XML (2017)

Stackoverflow - Example of more complex XML Shape using Vector Drawable

There is another option which performance wise is considerably better than your current implementation. This might work best if you can re-implement the solution in the link..

Advanced Android Shape Canvas

That link is about building a shape on the bottom bar using the Cubic Bézier Curve, and it appears you can use this on any view type, not just the bottom bar as shown. I'll post the relative code this link uses to get an idea of what is different.

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

Where your OnDraw will end up looking like -

  @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPath(mPath, mPaint);
}
C. Skjerdal
  • 2,750
  • 3
  • 25
  • 50
  • 1
    Thanks a lot at first for the detailed answer Actually I did the onDraw fast and didn't optimize it, I just wanted it to work. I think the bezier curve is where I'm heading. I tried vector drawable and I face problems with scaling. – abd3lraouf Jan 12 '20 at 16:37
0

Yess using a vector drawable as the backgorund would be a much better strategy. Android supports svgs. Simply import the svg into your res/drawable folder and use it as the background for the button. The button will automatically conform to what you need. Hope this helps

Haseeb
  • 9
  • 4