通过 TalkBack 聚焦 SnackBar 中的操作按钮

发布于 2025-01-17 07:45:02 字数 143 浏览 0 评论 0原文

我正在使用 Android Jetpack Compose 创建一个带有操作的 SnackBar。

我的要求是,当启用可访问性 TalkBack 并显示 SnackBar 时,操作按钮应该聚焦,以便用户可以通过单击(双击)任何地方来执行操作(单击操作按钮)。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

高跟鞋的旋律 2025-01-24 07:45:02

我只是提供我的原型。我在一个活动中添加了所有代码,以简化示例。我怀疑你可以针对你的情况进行改进和修改。也许我的例子会对你有所启发)

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
        }
    })
}

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
        }
    })
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文