图一是浏览器打开哔哩哔哩的显示情况
图二是webview 显示的情况
这是为什么呢?
我的代码如下
// WebViewComposable程序,用来显示网页
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebViewComposable() {
// 获取当前的上下文环境,用于后续创建WebView等相关操作
val context = LocalContext.current as Activity
// 创建一个可变状态变量来保存WebView实例,初始化为null,后续在创建WebView时赋值
val webViewState = remember { mutableStateOf<WebView?>(null) }
// 创建一个可变状态变量,用于表示网页是否正在加载,初始值为true,表示开始时处于加载状态
var isLoading by remember { mutableStateOf(true) }
// 创建一个AndroidView,用于在Compose UI中嵌入Android原生的View,这里用来嵌入WebView显示网页
var isFullScreen by remember { mutableStateOf(false) } // 全屏状态
AndroidView(
// 设置创建WebView的工厂函数,在这里进行WebView的各种初始化设置
factory = {
WebView(context).apply {
// 启用JavaScript,使网页可以执行JavaScript代码
settings.javaScriptEnabled = true
// 启用DOM存储,方便网页进行本地数据存储等操作
settings.domStorageEnabled = true
// 混合内容模式设置为宽松模式(MIXED_CONTENT_ALWAYS_ALLOW),谨慎使用,需确保网页资源安全性
settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
// 加入长按监听代码,先添加监听,后续再完善具体长按操作逻辑
setOnLongClickListener {
// 获取长按的位置相关信息(例如坐标等),HitTestResult可用于后续判断长按的具体元素类型等
val hitTestResult = hitTestResult
// 获取触发长按操作的WebView实例,后续可基于此实例进行相关处理,比如判断元素类型后针对该WebView执行相应的文字复制、图片下载、视频下载等功能操作
val currentWebView = this
val elementType = hitTestResult.type
// 使用when语句判断元素类型,不同类型对应不同的处理逻辑,这里先只是简单打印日志示意,后续要替换为真正的功能实现代码
when (elementType) {
WebView.HitTestResult.IMAGE_TYPE -> {
// 获取图片的URL(这里假设图片是通过URL加载的,不同情况可能需要不同处理方式)
val imageUrl = hitTestResult.extra
if (imageUrl!= null) {
saveImageFromUrlToLocal(imageUrl, context)
}
}
WebView.HitTestResult.SRC_ANCHOR_TYPE -> {
Log.d("WebViewLongPress", "长按的元素是带有链接的文本等情况,按需添加对应处理")
}
WebView.HitTestResult.PHONE_TYPE -> {
Log.d("WebViewLongPress", "长按的元素是电话号码相关,按需添加对应处理")
}
WebView.HitTestResult.EDIT_TEXT_TYPE -> {
Log.d("WebViewLongPress", "长按的元素是普通文本,后续可添加文字复制逻辑")
}
else -> {
Log.d("WebViewLongPress", "长按的元素是其他类型,可进一步分析处理")
}
}
true
}
// 加载指定的网页URL
loadUrl("https://www.bilibili.com/")
// 设置WebView的客户端,用于监听网页加载的相关事件
webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
if (!isFullScreen) {
isLoading = true
}
}
override fun onPageFinished(view: WebView?, url: String?) {
if (!isFullScreen) {
isLoading = false
}
}
}
// 设置WebView的按键监听,用于处理返回键按下的操作
setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP && canGoBack()) {
// 如果按下的是返回键,并且WebView可以返回上一页,则执行返回操作
goBack()
true
} else {
false
}
}
// 设置WebView使用宽屏视口,使网页能依据屏幕宽度自适应布局,有助于避免出现横向滚动条等布局问题
settings.useWideViewPort = true
// 让网页按概览模式加载,使网页初始显示时整体布局更合理,优化页面初次展示效果
settings.loadWithOverviewMode = true
//支持插件
settings.textZoom = 100
// 获取系统默认的User-Agent字符串,一般它能表明是Android系统下的请求,但可能需要进行修改使其更接近常见浏览器的User-Agent
val defaultUserAgent = WebSettings.getDefaultUserAgent(context)
// 自定义的User-Agent字符串,这里模拟Chrome浏览器的部分关键特征(可根据实际测试情况进一步优化调整)
val customUserAgent = "$defaultUserAgent Chrome/118.0.0.0 Mobile Safari/537.36"
// 设置WebView使用自定义的User-Agent,这样向服务器请求网页时,服务器可能会返回更适配常规浏览器显示效果的内容
settings.userAgentString = customUserAgent
// 设置WebView的页面布局算法为单栏模式,有助于在不同屏幕尺寸下让网页元素更好地自适应排列,避免出现布局错乱的情况
// 尤其对于一些采用流式布局等的网页,能让其更合理地展示内容,类似浏览器中常见的页面布局自适应效果
settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
// 开启对 HTML5 的本地存储功能支持,方便网页使用HTML5的相关API进行本地数据存储等操作,很多网页利用此功能来提升用户体验,比如记住用户设置等
settings.domStorageEnabled = true
// 设置WebView的缓存模式为LOAD_DEFAULT,它会根据网络情况等自动选择合适的缓存策略,
// 例如在有网络时会合理利用已有缓存并更新部分资源,离线时尝试使用缓存内容展示网页,以此来优化网页加载及离线使用等情况
settings.cacheMode = WebSettings.LOAD_DEFAULT
settings.javaScriptCanOpenWindowsAutomatically = true
settings.allowFileAccess = true
settings.allowContentAccess = true
settings.loadsImagesAutomatically = true
settings.mediaPlaybackRequiresUserGesture = false
webViewState.value = this
}
},
// 设置AndroidView的大小充满整个屏幕
modifier = Modifier.fillMaxSize()
)
// 根据isLoading的值来决定是否显示加载中的提示,例如圆形进度条
if (isLoading) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator(modifier = Modifier.size(80.dp))
}
}
}
图一
图二