简体   繁体   中英

Focus action button in SnackBar with TalkBack

I am creating a SnackBar with action using Android Jetpack Compose.

My requirement is, when accessibility TalkBack is enabled and snackBar is shown, action button should be focused, so that user can perform action (action button click) by clicking (double tap)anywhere.

I just provide my prototype. I added all code in one activity, to simplify example. I suspect you can improve and modify for your case. May be my example will inspire you)

package com.rollo.exampleandtests.composable

import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_DOWN
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.rollo.exampleandtests.composable.ui.ComposeTutorialTheme
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch

class ComposeActivity10 : AppCompatActivity() {

    //must be moved to ViewModel
    private var isShowed = false
    private var action: MutableStateFlow<Boolean?> = MutableStateFlow(null)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                val forceDismiss by action.collectAsState()
                SnackBarDemo(forceDismiss) {
                    isShowed = it
                }
            }
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        return if (ev?.action == ACTION_DOWN && isShowed) {
            action.value = !(action.value ?: false)
            true
        } else {
            super.dispatchTouchEvent(ev)
        }
    }
}

@Composable
fun SnackBarDemo(action: Boolean?, callback: (Boolean) -> Unit) {

    val coroutineScope = rememberCoroutineScope()
    val scaffoldState = rememberScaffoldState()

    Scaffold(
        modifier = Modifier.fillMaxSize(),
        scaffoldState = scaffoldState
    ) {
        Button(
            modifier = Modifier
                .fillMaxWidth()
                .padding(20.dp),
            onClick = {
                coroutineScope.launch {
                    callback(true)
                    val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
                        message = "This is your message",
                        actionLabel = "Do something."
                    )
                    callback(false)
                    when (snackbarResult) {
                        SnackbarResult.Dismissed -> Log.d("SnackbarDemo", "Dismissed")
                        SnackbarResult.ActionPerformed -> Log.d(
                            "SnackbarDemo",
                            "Snackbar's button clicked"
                        )
                    }
                }
            }
        ) {
            Text(text = "A button that shows a Snackbar")
        }
    }

    LaunchedEffect(key1 = action, block = {
        if (action == true) {
            scaffoldState.snackbarHostState.currentSnackbarData?.dismiss()
            //HERE: do something
        }
    })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM