Dimezis / BlurView

Dynamic iOS-like blur of underlying Views for Android
Apache License 2.0
3.5k stars 333 forks source link

Rounded Blur on CustomView #208

Closed nauhalf closed 11 months ago

nauhalf commented 11 months ago

Please include: 1) Library version version-2.0.3 2) Device and OS version Nox 7.0.3.1 Android 7 3) Detailed steps to reproduce the issue I create a customview that accept rounded but not all rounded, we can configure the topLeft, topRight, bottomLeft, and bottomRight using canvas. But the blur is not clipped to the rounded I set.

class RoundedBlurView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : BlurView(context, attrs, defStyle) {

    private var cornerRadiusTopLeft: Float = 0f
    private var cornerRadiusTopRight: Float = 0f
    private var cornerRadiusBottomLeft: Float = 0f
    private var cornerRadiusBottomRight: Float = 0f

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundedBlurView)
        cornerRadiusTopLeft = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusTopLeft, 0f)
        cornerRadiusTopRight = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusTopRight, 0f)
        cornerRadiusBottomLeft = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusBottomLeft, 0f)
        cornerRadiusBottomRight = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusBottomRight, 0f)
        typedArray.recycle()
    }

    override fun onDraw(canvas: Canvas) {
        val path = Path()
        val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())

        // Set corner radii individually
        val radii = floatArrayOf(
            cornerRadiusTopLeft, cornerRadiusTopLeft,
            cornerRadiusTopRight, cornerRadiusTopRight,
            cornerRadiusBottomRight, cornerRadiusBottomRight,
            cornerRadiusBottomLeft, cornerRadiusBottomLeft
        )

        path.addRoundRect(rect, radii, Path.Direction.CW)

        canvas.clipPath(path)
        super.onDraw(canvas)
    }
}

4) XML layout and code for BlurView setup

   <com.nauhalf.example.RoundedBlurView
                    android:id="@+id/blur_view"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/_60sdp"
                    app:cornerRadiusBottomLeft="@dimen/_14sdp"
                    app:cornerRadiusBottomRight="@dimen/_14sdp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:blurOverlayColor="@color/transparent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent">
... 
</com.nauhalf.example.RoundedBlurView>

the BlurView Setup

binding?.apply {
      blurView.setupWith(
          root, RenderScriptBlur(requireContext()))
                  .setBlurRadius(radius)
}

5) Stacktrace in case of a crash 6) Result image

Is there any wrong with the customview?

Dimezis commented 11 months ago

As a blind guess, try overriding draw instead of onDraw

nauhalf commented 11 months ago

Ah I see. it works now. thank you

nauhalf commented 11 months ago

I will put the code on this ticket for the other who facing same problem as me

CustomView

class RoundedBlurView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0,
) : BlurView(context, attrs, defStyle) {
    private var cornerRadiusTopLeft: Float = 0f
    private var cornerRadiusTopRight: Float = 0f
    private var cornerRadiusBottomLeft: Float = 0f
    private var cornerRadiusBottomRight: Float = 0f

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundedBlurView)
        cornerRadiusTopLeft = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusTopLeft, 0f)
        cornerRadiusTopRight = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusTopRight, 0f)
        cornerRadiusBottomLeft = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusBottomLeft, 0f)
        cornerRadiusBottomRight = typedArray.getDimension(R.styleable.RoundedBlurView_cornerRadiusBottomRight, 0f)
        typedArray.recycle()
    }
    override fun draw(canvas: Canvas) {
        val path = Path()
        val radii = floatArrayOf(
            cornerRadiusTopLeft, cornerRadiusTopLeft,
            cornerRadiusTopRight, cornerRadiusTopRight,
            cornerRadiusBottomLeft, cornerRadiusBottomLeft,
            cornerRadiusBottomRight, cornerRadiusBottomRight
        )
        path.addRoundRect(
            RectF(0f, 0f, width.toFloat(), height.toFloat()),
            radii,
            Path.Direction.CW
        )
        canvas.clipPath(path)

        super.draw(canvas)
    }
}

attrs

    <declare-styleable name="RoundedBlurView">
        <attr name="cornerRadiusTopLeft" format="dimension" />
        <attr name="cornerRadiusTopRight" format="dimension" />
        <attr name="cornerRadiusBottomLeft" format="dimension" />
        <attr name="cornerRadiusBottomRight" format="dimension" />
    </declare-styleable>
nauhalf commented 11 months ago

Regarding the customview above, when using it with radius, somehow there's a little gap on the edge like this. image image

Do you know the root cause about this @Dimezis ?

Thank you

Dimezis commented 11 months ago

@nauhalf probably you clipped them with your canvas.clipPath(path), but please let's keep Github issues about the library itself. Anything extra you're doing with it is your responsibility.