安卓软件开发:使用Jetpack Compose实现 NimWebViewApp

2024-10-09 11:14:32 浏览数 (4)

2024年已经过半了,我作为聋人独立开发者,我经常会时不时反思:自己这半年到底进步了多少?在这篇文章里,我分享一个用 Jetpack Compose、Material3和 Kotlin 语言实现使用Jetpack Compose和Kotlin开发NimWebViewApp的加载和操作的案例。无论你有没有开发经验,相信这篇文章对你会非常有所帮助。

一、项目背景

本文展示如何使用 Jetpack Compose 中的 AndroidView 加载 WebView,处理页面的加载状态和返回导航操作。

二、讲解WebView 核心代码

2.1 加载 WebView

Jetpack Compose 本身没有自带 WebView,通过 AndroidView,可以把传统的 WebView 嵌入到 Compose UI中。以下是如何加载 WebView 的代码:

代码语言:java复制
AndroidView(
    factory = { webView },
    modifier = Modifier.matchParentSize()
)

这段代码用 AndroidView 创建了一个 WebView 并让它填满父布局。

2.2 处理页面加载状态

为了让用户知道页面是否还在加载,监听 WebView 的 onPageStartedonPageFinished,当页面开始加载时,可以展示一个加载中的提示,等页面加载完成后,再隐藏提示。

代码语言:java复制
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
    isLoading.value = true
}

override fun onPageFinished(view: WebView?, url: String?) {
    isLoading.value = false
}

2.3 处理返回按钮

在浏览器类的App中,用户希望通过返回键返回上一页。如果 WebView 有可返回的页面,就调用 goBack(),否则退出当前界面。Compose 提供的 BackHandler 轻松实现返回的功能

代码语言:java复制
BackHandler(enabled = canGoBack.value) {
    if (webView.canGoBack()) {
        webView.goBack()
    } else {
        navController.popBackStack()
    }
}

三、 项目开发

3.1 编码 UI

Demo由一个简单的 HomeScreen 实现NimWebViewDemo。

HomeScreen 包含了一个 URL 输入框、一个加载按钮以及一个 WebView 来展示网页内容。用户输入 URL 后,点击按钮可以加载网页,同时支持下拉刷新和返回上一个网页的功能。

代码语言:java复制
@SuppressLint("SetJavaScriptEnabled")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(navController: NavController) {
    var url by remember { mutableStateOf(TextFieldValue("https://www.baidu.com")) }
    val context = LocalContext.current
    var webView: WebView? = remember { null }
    val isLoading = remember { mutableStateOf(true) }
    val canGoBack = remember { mutableStateOf(false) }
    val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = isLoading.value)

    Scaffold(
        topBar = {
            CenterAlignedTopAppBar(
                title = { Text("NimWebViewDemo", color = MaterialTheme.colorScheme.onPrimary) },
                colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary,
                    titleContentColor = Color.White
                )
            )
        }
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .padding(paddingValues)
                .fillMaxSize()
        ) {
            // 编码UI 输入框和搜索按钮
            OutlinedTextField(
                value = url,
                onValueChange = { url = it },
                label = { Text("Enter URL") },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp),
                singleLine = true,
                trailingIcon = {
                    IconButton(onClick = {
                        webView?.loadUrl(url.text)
                    }) {
                        Icon(Icons.Default.Search, contentDescription = "Search")
                    }
                }
            )

            SwipeRefresh(
                state = swipeRefreshState,
                onRefresh = {
                    webView?.reload()  // 编码UI 下拉时重新加载当前URL
                }
            ) {
                AndroidView(
                    factory = {
                        WebView(context).apply {
                            webView = this
                            settings.javaScriptEnabled = true
                            webViewClient = object : WebViewClient() {
                                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                                    isLoading.value = true
                                    canGoBack.value = view?.canGoBack() ?: false
                                }

                                override fun onPageFinished(view: WebView?, url: String?) {
                                    isLoading.value = false
                                    canGoBack.value = view?.canGoBack() ?: false
                                }
                            }
                            loadUrl(url.text)
                        }
                    },
                    update = {
                        it.loadUrl(url.text)
                    },
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(8.dp)
                )
            }
        }
    }

    // 返回按钮逻辑
    BackHandler(enabled = canGoBack.value) {
        if (webView?.canGoBack() == true) {
            webView?.goBack()
        } else {
            navController.popBackStack()
        }
    }
}

3.1.1 解释代码

URL 输入框:用 OutlinedTextField 作为 URL 输入框,用户可以在输入想要访问的网页地址。

(1)搜索按钮:点击右侧的搜索按钮,WebView 会加载用户输入的 URL。

(2)下拉刷新:使用 SwipeRefresh 实现下拉刷新功能,可以在页面上拉时重新加载当前的网页。

(3)WebView:通过 AndroidView WebView 集成到 Jetpack Compose 中,启用了 JS 功能,大多数现代网站可以正常加载。

(4)返回功能:通过 BackHandler 处理设备上的返回键操作,可以在网页中通过返回按钮回到上一个网页,或者退出当前页面。

3.2 申请权限

如果不设置它,否则不能访问网络。

代码语言:javascript复制
<uses-permission android:name="android.permission.INTERNET" />

3.3 测试 UI

3.4 视频演示

视频内容

四、技术难点

4.1 Jetpack Compose 和 WebView 的结合

用 Jetpack Compose 的 AndroidView 可以轻松实现了传统的 Android 视图控件(如 WebView)嵌入到 Compose 中,且通过 update 方法确保 WebView 随着状态的变化而更新。

4.2 返回操作的管理

WebView 自带页面导航功能,可以在多个页面之间跳转,通过 BackHandler 检测是否可以返回到上一页面,结合 Compose 的导航功能,确保用户能够正常使用返回键。

4.3 SwipeRefresh 的使用

通过引入 SwipeRefresh,让用户在查看网页时,通过下拉动作刷新当前页面。

五、学习笔记

使用 BackHandler 处理返回事件

通过 BackHandler可以在用户按返回键时控制页面的导航行为,特别是处理 WebView 的返回操作。这个功能对像浏览器这样的场景非常有用。

六、总结

本文展示了如何在 Jetpack Compose 中集成 WebView,处理加载状态和返回导航。通过 AndroidView,可以把原生控件带入 Compose 中,利用 Compose 编写UI采用了声明式编程方式处理页面逻辑。希望这篇文章能帮助大家理解在 Compose 中加载 WebView 的基本开发。

有任何问题欢迎提问,感谢大家阅读 )

0 人点赞