【Android】设计一个圆角矩形的WebView

设置一个圆角矩形的WebView

自定义RoundWebView

复制代码
package com.example.webviewdialog;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.webkit.WebView;

import androidx.annotation.NonNull;

public class RoundWebView extends WebView {

    private Path mPath = new Path();
    private RectF mRectF = new RectF();

    private float[] mRadiusArray = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f};

    public RoundWebView(Context context) {
        this(context, null);
    }

    public RoundWebView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(@NonNull Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundWebView); // 读取xml styleable,attrs是xml属性的集合
        float defaultDp = context.getResources().getDimensionPixelSize(R.dimen.web_view_corner_radius);
        float radius = a.getDimension(R.styleable.RoundWebView_rwv_radius, defaultDp);
        float topLeftRadius = a.getDimension(R.styleable.RoundWebView_rwv_top_left_radius, 0);
        float topRightRadius = a.getDimension(R.styleable.RoundWebView_rwv_top_right_radius, 0);
        float bottomLeftRadius = a.getDimension(R.styleable.RoundWebView_rwv_bottom_left_radius, 0);
        float bottomRightRadius = a.getDimension(R.styleable.RoundWebView_rwv_bottom_right_radius, 0);
        a.recycle();

        if (radius > 0) {
            topLeftRadius = topRightRadius = bottomLeftRadius = bottomRightRadius = radius;
        }
        setRoundRadius(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius);
    }

    /**
     * 设置四个角的圆角半径
     *
     * @param radius 所有圆角的半径
     */
    public void setRoundRadius(float radius) {
        float result = radius > 0 ? radius : 0;
        setRoundRadius(result, result, result, result);
    }

    /**
     * 设置四个角的圆角半径
     *
     * @param leftTopRadius     左上角半径
     * @param rightTopRadius    右上角半径
     * @param rightBottomRadius 右下角半径
     * @param leftBottomRadius  左下角半径
     */
    public void setRoundRadius(float leftTopRadius, float rightTopRadius,
                               float rightBottomRadius, float leftBottomRadius) {
        mRadiusArray[0] = leftTopRadius > 0 ? leftTopRadius : 0;
        mRadiusArray[1] = leftTopRadius > 0 ? leftTopRadius : 0;
        mRadiusArray[2] = rightTopRadius > 0 ? rightTopRadius : 0;
        mRadiusArray[3] = rightTopRadius > 0 ? rightTopRadius : 0;
        mRadiusArray[4] = rightBottomRadius > 0 ? rightBottomRadius : 0;
        mRadiusArray[5] = rightBottomRadius > 0 ? rightBottomRadius : 0;
        mRadiusArray[6] = leftBottomRadius > 0 ? leftBottomRadius : 0;
        mRadiusArray[7] = leftBottomRadius > 0 ? leftBottomRadius : 0;
        invalidate();
    }

    @Override
    public void onDraw(@NonNull Canvas canvas) {
        int scrollX = this.getScrollX();
        int scrollY = this.getScrollY();
        mPath.reset();
        mRectF.set(0, scrollY, scrollX + getWidth(), scrollY + getHeight());
        // 使用半角的方式,性能比较好
        mPath.addRoundRect(mRectF, mRadiusArray, Path.Direction.CW);
        canvas.clipPath(mPath);
        super.onDraw(canvas);
    }
}

activity_main.xml 布局

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff0000"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="424dp"
        android:background="@drawable/web_view_bg"
        android:clipChildren="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <com.example.webviewdialog.RoundWebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/transparent"
            android:visibility="visible"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

Kotlin 复制代码
package com.example.webviewdialog

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.net.http.SslError
import android.os.Bundle
import android.util.Log
import android.webkit.*
import android.view.View
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MainActivity"
    }

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView: RoundWebView = findViewById<RoundWebView>(R.id.web_view)
        val url = "https://www.baidu.com/"
        
        Log.d(TAG, "Starting to configure WebView")

        // 配置WebView设置
        webView.settings.apply {
            javaScriptEnabled = true
            domStorageEnabled = true
            cacheMode = WebSettings.LOAD_NO_CACHE
            
            // 支持自动适应屏幕
            useWideViewPort = true
            loadWithOverviewMode = true
            
            // 基本设置
            defaultTextEncodingName = "utf-8"
            loadsImagesAutomatically = true
            blockNetworkImage = false
            
            // 支持混合内容
            mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
            
            // 设置UA
            userAgentString = "Mozilla/5.0 (Linux; Android 11; Pixel) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36"
        }

        webView.webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
                Log.e(TAG, "onPageStarted: url = $url")
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                Log.e(TAG, "onPageFinished: url = $url")
            }

            override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
                view.loadUrl(request.url.toString())
                return true
            }

            override fun onReceivedError(
                view: WebView?,
                request: WebResourceRequest?,
                error: WebResourceError?
            ) {
                Log.e(TAG, "onReceivedError: error = ${error?.description}, code = ${error?.errorCode}")
                super.onReceivedError(view, request, error)
            }

            override fun onReceivedSslError(
                view: WebView?,
                handler: SslErrorHandler?,
                error: SslError?
            ) {
                handler?.proceed()
            }
        }

        webView.webChromeClient = WebChromeClient()
        try {
            Log.d(TAG, "Loading URL: $url")
            webView.loadUrl(url)
        } catch (e: Exception) {
            Log.e(TAG, "Error loading URL", e)
        }
    }

    override fun onDestroy() {
        val webView = findViewById<WebView>(R.id.web_view)
        webView.destroy()
        super.onDestroy()
    }
}

最后样式界面如下所示:

相关推荐
行墨1 小时前
Kotlin 主构造函数
android
前行的小黑炭1 小时前
Android从传统的XML转到Compose的变化:mutableStateOf、MutableStateFlow;有的使用by有的使用by remember
android·kotlin
_一条咸鱼_1 小时前
Android Compose 框架尺寸与密度深入剖析(五十五)
android
在狂风暴雨中奔跑2 小时前
使用AI开发Android界面
android·人工智能
行墨2 小时前
Kotlin 定义类与field关键
android
信徒_2 小时前
Mysql 在什么样的情况下会产生死锁?
android·数据库·mysql
大胡子的机器人3 小时前
安卓中app_process运行报错Aborted,怎么查看具体的报错日志
android
goto_w3 小时前
uniapp上使用webview与浏览器交互,支持三端(android、iOS、harmonyos next)
android·vue.js·ios·uni-app·harmonyos
QING6184 小时前
Kotlin Random.Default用法及代码示例
android·kotlin·源码阅读
QING6184 小时前
Kotlin Byte.inc用法及代码示例
android·kotlin·源码阅读