Search code examples
androidandroid-webviewandroid-custom-view

Android Custom WebView With Rounded Corners


I'm trying to make a custom WebView that is completely identical to a regular WebView except that it has rounded corners. The rounded corners need to be transparent because I'd like to put this WebView in a Dialog.

I tried making my custom class like so:

public class RoundedWebView extends WebView
{
    private Context context;

    private int width;

    private int height;

    public RoundedWebView(Context context)
    {
        super(context);

        initialize(context);
    }

    public RoundedWebView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        initialize(context);
    }

    public RoundedWebView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        initialize(context);
    }

    private void initialize(Context context)
    {
        this.context = context;
    }

    // This method gets called when the view first loads, and also whenever the
    // view changes. Use this opportunity to save the view's width and height.
    @Override protected void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight)
    {
        this.width = newWidth;

        this.height = newHeight;

        super.onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
    }

    @Override protected void onDraw(Canvas canvas)
    {
        int radius = Utilities.dpToPx(context, 5);

        Path clipPath = new Path();

        clipPath.addRoundRect(new RectF(0, 0, width, height), radius, radius, Path.Direction.CW);

        canvas.clipPath(clipPath);

        super.onDraw(canvas);
    }
}

and this implementation works for the most part. However, as soon as a url finishes loading and displays itself on the screen, I lose the rounded corners from the WebView. Any idea what's going on?


Solution

  • Here was the solution I found. In my onDraw() method, I create an inverted, filled, rounded rectangle, and then use the Porter Duff Xfer Mode to "clear" that area from the screen. This leaves me with a WebView that has nicely bevelled edges, including the case where the WebView finishes loading a url.

    public class RoundedWebView extends WebView
    {
        private Context context;
    
        private int width;
    
        private int height;
    
        private int radius;
    
        public RoundedWebView(Context context)
        {
            super(context);
    
            initialize(context);
        }
    
        public RoundedWebView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
    
            initialize(context);
        }
    
        public RoundedWebView(Context context, AttributeSet attrs, int defStyleAttr)
        {
            super(context, attrs, defStyleAttr);
    
            initialize(context);
        }
    
        private void initialize(Context context)
        {
            this.context = context;
        }
    
        // This method gets called when the view first loads, and also whenever the
        // view changes. Use this opportunity to save the view's width and height.
        @Override protected void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight)
        {
            super.onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
    
            width = newWidth;
    
            height = newHeight;
    
            radius = Utilities.dpToPx(context, 5);
        }
    
        @Override protected void onDraw(Canvas canvas)
        {
            super.onDraw(canvas);
    
            Path path = new Path();
    
            path.setFillType(Path.FillType.INVERSE_WINDING);
    
            path.addRoundRect(new RectF(0, getScrollY(), width, getScrollY() + height), radius, radius, Path.Direction.CW);
    
            canvas.drawPath(path, createPorterDuffClearPaint());
        }
    
        private Paint createPorterDuffClearPaint()
        {
            Paint paint = new Paint();
    
            paint.setColor(Color.TRANSPARENT);
    
            paint.setStyle(Style.FILL);
    
            paint.setAntiAlias(true);
    
            paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
    
            return paint;
        }
    }