0

I have a BottomSheet non-Modal with a WebView in Compose using an AndroidView.

The WebView shows the Google Map Site and I use parameters to show a Location that I obtain using FusedLocationProviderClient and others.

I wish to disable user interactions with the WebView and I read here there were two suggestions: Add an Overlay or override Touch events. But that is a really old thread and I don't know how to do any of the suggestions with Compose inside an AndroidView.

The following is my code:

BottomSheet:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationScreen(startLocationUpdates: ()->Unit, context: Context, currentLocation: LatLng) {

val permissions = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

val launchMultiplePermissions = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissionMaps ->
    val areGranted = permissionMaps.values.reduce { acc, next -> acc && next }
    if (areGranted) {
        locationRequired = true
        startLocationUpdates()
        Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
    }
}

var readable by remember { mutableStateOf("") }
//val scope = rememberCoroutineScope() 
//I HAVE THIS COMMENTED BECAUSE THE BUTTON THAT IS USUALLY LOCATED IN THE BOTTOMSHEET TO CLOSE IT IS COVER BY THE WEBVIEW AND CAN'T BE USED
val scaffoldState = rememberBottomSheetScaffoldState()

BottomSheetScaffold(
    scaffoldState = scaffoldState,
    sheetPeekHeight = 590.dp, //The Bottom Sheet will show the WebView partially but all that is needed
    sheetSwipeEnabled = false, //For the  moment I don't want the Bottom Sheet to occupy the full screen
    sheetContent = {
        
        Column(
            Modifier
                .fillMaxWidth()
                .padding(6.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble() && readable != "") {
                WebViewScreen(location = currentLocation) //HERE IS THE CALL TO THE ANDROIDVIEW/WEBVIEW
            } else {Text(text = "Please click [Get your location]")}
        }
    }) { innerPadding ->
    Box(Modifier.padding(innerPadding)) {
        Column(
            modifier = Modifier.fillMaxWidth(),
            verticalArrangement = Arrangement.SpaceEvenly,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Your location: ${currentLocation.latitude}/${currentLocation.longitude}")
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble()) {
                Text(
                    text = "Readable location: $currentLocation"
                )
                location = ""
                readable = getReadableLocation(currentLocation.latitude, currentLocation.longitude, context) //HERE I USE A GEOCODER TO GET THE ADDRESS
                glocation = currentLocation
            }
            Button(onClick = {
                if (permissions.all {
                        ContextCompat.checkSelfPermission(
                            context,
                            it
                        ) == PackageManager.PERMISSION_GRANTED
                    }) {
                    //Get Locations
                    startLocationUpdates() //THIS IS WHERE I GET THE LOCATION/COORDINATES
                } else {
                    launchMultiplePermissions.launch(permissions)
                }
                //run = true
            }) {
                Text(text = "Get your location")
            }
        }
    }
}

}

AndroidView with WebView:

@Composable
fun WebViewScreen(location: LatLng){ 

//val urladdress = URLDecoder.decode(address,"utf-8")
val url = "http://maps.google.com/maps?z=16&t=h&q=loc:${location.latitude}+${location.longitude}&hl=${Locale.getDefault().language}"

AndroidView(
    factory = { context ->
        WebView(context).apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            settings.javaScriptEnabled = true
            webViewClient = WebViewClient()

            settings.loadWithOverviewMode = true
            settings.useWideViewPort = true
            settings.setSupportZoom(true)
            loadUrl(url)
        }
    },
    update = { webView ->
        webView.loadUrl(url)
    }
)

}

I am not providing the code for the Location nor the Address as is not needed for the purpose of this question.

1 Answer 1

0

Found an alternative approach to disable user interaction with the WebView.

Instead of adding an Overlay I follow the Touch event approach.

The following is the code:

AndroidView(
    modifier = Modifier
        //.focusProperties { canFocus = false }
        .pointerInteropFilter {
        when (it.action) {
            MotionEvent.ACTION_DOWN -> {}
            MotionEvent.ACTION_MOVE -> {}
            MotionEvent.ACTION_UP -> {}
            else ->  false
        }
        true
    },
    factory = { context ->
        WebView(context).apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            settings.javaScriptEnabled = true
            webViewClient = WebViewClient()

            settings.loadWithOverviewMode = true
            settings.useWideViewPort = true
            settings.setSupportZoom(true)

            loadUrl(url)
        }
    },
    update = { webView ->
        webView.loadUrl(url)
    }
)

The "pointerInteropFilter" capture all movement in the parent AndroidView blocking all interaction in the children WebView. If for instance you want to permit Touch events in a particular are you can detect the coordinates inside AndroidView and permit the ones corresponding to the area that falls over the children you require to responde to events.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.