Introduction
This Android Kotlin example demonstrates the integration of a WebView with a ProgressIndicator in a Jetpack Compose UI. Jetpack Compose, the modern toolkit for building native Android UIs, allows developers to create responsive and dynamic interfaces with less boilerplate code. Here, we see how to embed a WebView within a Compose layout and manage its loading state with a circular progress indicator, providing users visual feedback during webpage loading.
In this tutorial, we will break down the components and logic used in the code, focusing on the UI elements, state management, and how the WebView client interacts with the rest of the composable elements. By the end, you'll understand how Jetpack Compose can simplify embedding traditional Android views, like WebView, into declarative UI components.
Scaffold Layout
The code begins by defining the main user interface inside a Scaffold
composable, which serves as the base structure of the UI. The Scaffold
provides a consistent layout with built-in support for placing elements such as a TopAppBar and a content section. In this case, the TopAppBar
displays the title "Compose - WebView ProgressIndicator," providing a polished and organized header for the app. The background color of the TopAppBar
is a soft green (Color(0xFFC0E8D5)
), adding a pleasing visual touch to the UI.
The content of the scaffold is handled by another composable, MainContent()
, which is where the core functionality of the WebView and progress indicator is placed. The scaffold's overall background color is a neutral tone (Color(0xFFEDEAE0)
), creating a clean and minimalistic backdrop for the UI components.
State Management
State management in Jetpack Compose is achieved using remember and mutableStateOf functions, which allow the UI to react to changes in data. In this example, two states are declared: url
, which holds the current URL of the WebView, and visibility
, which controls the visibility of the CircularProgressIndicator.
url
: The initial value is set to "https://www.google.com", and this state is updated whenever a user selects a different website (Google or Yahoo) via the buttons.visibility
: A boolean state that tracks whether the progress indicator should be displayed. It is set totrue
when the webpage starts loading and switched tofalse
once the loading completes.
By utilizing Compose’s reactive nature, the UI automatically updates when these state variables change, eliminating the need for manual UI refreshes, which is common in traditional Android development.
User Interaction and Buttons
Inside the MainContent()
composable, a Row
layout is used to arrange two buttons horizontally. These buttons allow users to switch between two preset URLs: Google and Yahoo. When a button is clicked, the url
state is updated with the respective URL, which triggers the WebView to load the new page.
The buttons are placed inside a nested Row
and are styled with padding and rounded corners (RoundedCornerShape(12.dp)
). This adds to the overall polished look of the UI, ensuring that the buttons are both functional and aesthetically pleasing.
WebView Integration with AndroidView
Jetpack Compose provides the AndroidView
composable, which allows developers to integrate traditional Android views within Compose layouts. In this example, a WebView is embedded inside a Box
layout, and its loading state is managed by a custom WebViewClient.
- The
WebView
is created using thefactory
lambda withinAndroidView
, where its settings (such as JavaScript support) and layout parameters are configured. - A WebViewClient is defined to handle the events
onPageStarted
andonPageFinished
. When a webpage starts loading,visibility.value
is set totrue
, causing the CircularProgressIndicator to appear. Once the page finishes loading,visibility.value
is set tofalse
, hiding the progress indicator.
This integration between the WebView's loading state and the composable elements showcases how easily traditional views can be controlled through Jetpack Compose's reactive UI paradigm.
Progress Indicator
The progress indicator is a CircularProgressIndicator, displayed only when the visibility
state is set to true
. It is placed next to the buttons, giving users immediate feedback that a page is loading. The progress indicator’s color is a striking blue (Color(0xFF0018A8)
), ensuring it stands out against the neutral background.
The logic controlling the progress indicator is simple yet effective. Since the WebView's loading process is asynchronous, the use of onPageStarted
and onPageFinished
events ensures that the progress indicator is accurately synchronized with the WebView’s state.
Summary
This Kotlin example demonstrates how Jetpack Compose can be used to seamlessly integrate Android views like WebView into a declarative UI framework. By utilizing the Scaffold
structure, state management, and AndroidView
, this example provides a clean and responsive interface with minimal boilerplate code. The addition of the CircularProgressIndicator enhances user experience by visually signaling webpage loading.
Incorporating traditional views within Compose allows for a smooth transition for developers moving from imperative UI paradigms to the declarative world of Jetpack Compose. This example showcases how both worlds can coexist and complement each other, providing a powerful toolkit for modern Android app development.
package com.cfsuman.jetpackcompose
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.LinearLayout
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedObjectState: Bundle?) {
super.onCreate(savedObjectState)
setContent {
GetScaffold()
}
}
@Composable
fun GetScaffold(){
Scaffold(
topBar = {
TopAppBar(
title = { Text(
text = "Compose - WebView ProgressIndicator"
)},
backgroundColor = Color(0xFFC0E8D5),
)
},
content = {MainContent()},
backgroundColor = Color(0xFFEDEAE0),
)
}
@Composable
fun MainContent(){
val url = remember { mutableStateOf("https://www.google.com")}
val visibility = remember { mutableStateOf(false)}
Box(
modifier = Modifier.fillMaxSize(),
){
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier
.padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Row(
modifier = Modifier
.padding(8.dp)
.clip(RoundedCornerShape(12.dp))
.wrapContentHeight(Alignment.CenterVertically),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Button(onClick = {
url.value = "https://www.google.com"
}) {
Text(text = "Google")
}
Button(onClick = {
url.value = "https://www.yahoo.com"
}) {
Text(text = "Yahoo")
}
}
if (visibility.value){
CircularProgressIndicator(
color = Color(0xFF0018A8)
)
}
}
Box(
modifier = Modifier
.weight(2F)
) {
AndroidView(factory = { context ->
WebView(context).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
settings.javaScriptEnabled = true
webViewClient = object: WebViewClient(){
override fun onPageStarted(
view: WebView, url: String,
favicon: Bitmap?) {
visibility.value = true
}
override fun onPageFinished(
view: WebView, url: String) {
visibility.value = false
}
}
loadUrl("https://www.google.com")
}
},update = {
it.loadUrl(url.value)
})
}
}
}
}
}
- jetpack compose - Row onClick
- jetpack compose - How to use ModalDrawer
- jetpack compose - How to use BadgeBox
- jetpack compose - TopAppBar center title
- jetpack compose - TopAppBar menu
- jetpack compose - Snackbar action
- jetpack compose - Snackbar dismiss listener
- jetpack compose - How to use AndroidView
- jetpack compose - How to update AndroidView
- jetpack compose - How to use navigation controller
- jetpack compose - Navigate with argument
- jetpack compose - Room add remove update
- jetpack compose - How to use WebView
- jetpack compose - WebView progress percentage
- jetpack compose - Backdrop scaffold