RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / user-195957

Sirop4ik's questions

Martin Hope
Sirop4ik
Asked: 2025-01-30 02:59:49 +0000 UTC

如何使画布背景模糊?

  • 5

有这样一个图标

在此处输入图片描述

它画得像这样:

    @Composable
    private fun IconWithCircleBackground(
        @DrawableRes res: Int,
        modifier: Modifier = Modifier,
        radius: Dp = 16.dp,
        strokeColor: Color = ColorTokens.grey_10,
        strokeWidth: Dp = 1.dp,
        backgroundColor: Color = Color.Black,
        backgroundAlpha: Float = 0.7f
    ) {
        Box(modifier = modifier.size(radius)) {
            Canvas(modifier = Modifier.size(radius)) {
                drawCircle(
                    color = backgroundColor.copy(alpha = backgroundAlpha),
                    radius = radius.toPx() - strokeWidth.toPx() / 2
                )

                drawCircle(
                    color = strokeColor,
                    radius = radius.toPx(),
                    style = Stroke(width = strokeWidth.toPx())
                )
            }

            Image(
                painter = painterResource(id = res),
                contentDescription = stringResource(id = ...)
            )
        }
    }

即Canvas在其上第一层绘制一个以黑色(+alpha)填充的圆圈作为背景,第二层绘制一条白线作为边框并且图标位于中心。

您需要制作第一层(黑色背景),以使其模糊。问题——这里如何应用模糊?

android
  • 2 个回答
  • 23 Views
Martin Hope
Sirop4ik
Asked: 2024-11-25 02:38:08 +0000 UTC

如何正确使用 StateFlow 更新屏幕的 UIState

  • 5

我看到这篇文章

https://proandroiddev.com/loading-initial-data-in-launchedeffect-vs-viewmodel-f1747c20ce62

其中作者描述了数据初始化方法的优点和缺点,得出的结论是最好通过StateFlow.我决定尝试一下,前提是我使用UiState包装器作为屏幕的一般状态:

sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Error(val code: Int? = null, val message: String? = null) : UiState<Nothing>()
    data class Content<T>(val data: T) : UiState<T>()
}

也就是说,我在更改之前的实现:

class MyRepo {
    fun getMyData(): Flow<List<String>> {
        return flow {
            delay(1000)
            emit(listOf("1", "2"))
        }
    }
}

class MyViewModel1(repo: MyRepo): ViewModel() {
    data class ScreenStateUI(
        val data: List<String> = emptyList(),
        val title: String = "Title"
    )

    private val _screenUiState: MutableStateFlow<UiState<ScreenStateUI>> = MutableStateFlow(UiState.Loading)
    val screenUiState: StateFlow<UiState<ScreenStateUI>> = _screenUiState.asStateFlow()

    init {
        viewModelScope.launch {
            repo.getMyData()
                .map<List<String>, UiState<ScreenStateUI>> { UiState.Content(ScreenStateUI(data = it)) }
                .collectLatest {
                    if (it is UiState.Content) {
                        _screenUiState.emit(
                            UiState.Content(data = it)
                        )
                }
        }
    }

    fun updateTitle(title: String) {
        _screenUiState.update {
            if (it is UiState.Content) {
                it.copy(data = it.data.copy(title = title))
            } else {
                it
            }
        }
    }
}

初始化期间,状态被加载,UI可以通过订阅变化screenUiState,也就是说,如果需要使用它fun updateTitle(title: String),没有问题。

现在,我更改了实现以摆脱init块中的初始化,并在 UI 订阅事件后立即执行所有操作:

    class MyRepo {
        fun getMyData(): Flow<List<String>> {
            return flow {
                delay(1000)
                emit(listOf("1", "2"))
            }
        }
    }

class MyViewModel2(repo: MyRepo): ViewModel() {
    data class ScreenStateUI(
        val data: List<String> = emptyList(),
        val title: String = "Title"
    )

    val screenUiState: StateFlow<UiState<ScreenStateUI>> by lazy {
        repo.getMyData()
            .map<List<String>, UiState<ScreenStateUI>> { UiState.Content(ScreenStateUI(data = it)) }
            .onStart { emit(UiState.Loading) }
            .catch { emit(UiState.Error(message = it.message)) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = UiState.Loading
            )
    }

    fun updateTitle(title: String) {
        ...
    }
}

也就是说,一切似乎都不错,实际上现在 UI 仅在订阅时才会发起请求,但现在状态无法更改,因此该方法fun updateTitle(title: String)无法更新title。

我在这里缺少什么?

android
  • 2 个回答
  • 28 Views
Martin Hope
Sirop4ik
Asked: 2024-10-28 05:05:54 +0000 UTC

当我制作动画时,底部栏导航给出白色背景

  • 5

我正在尝试在底部导航上制作一个简单的动画

这是代码:

@Composable
private fun BottomNavImpl() {
    Scaffold(
        bottomBar = {
            var isBottomBarVisible: Boolean by remember { mutableStateOf(false) }

            LaunchedEffect(Unit) {
                delay(2000)
                isBottomBarVisible = true
            }

            AnimatedVisibility(
                visible = isBottomBarVisible,
                enter = slideInVertically(
                    initialOffsetY = { it },
                    animationSpec = tween(
                        durationMillis = 500,
                        easing = FastOutSlowInEasing
                    )
                ),
                exit = slideOutVertically(
                    targetOffsetY = { it },
                    animationSpec = tween(
                        durationMillis = 300,
                        easing = FastOutSlowInEasing
                    )
                )
            ) {
                NavigationBar(
                    containerColor = Color.Red,
                ) {
                    repeat(3) {
                        NavigationBarItem(
                            icon = {
                                Icon(
                                    modifier = Modifier,
                                    painter = painterResource(android.R.drawable.ic_menu_add),
                                    contentDescription = null,
                                )
                            },
                            selected = false,
                            onClick = { }
                        )
                    }
                }
            }
        },
        content = { paddingValues ->
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(paddingValues)
                    .background(Color.Green)
            ) {

            }
        }
    )
}

这是结果

在此输入图像描述

问题是在动画过程中,后面出现白色背景

android
  • 1 个回答
  • 17 Views
Martin Hope
Sirop4ik
Asked: 2024-10-28 04:37:23 +0000 UTC

如何使 LazyGrid 上某个项目的动画仅在第一次发生?

  • 5

这应该不会太困难,但由于某种原因,重组经历了两次,这使得添加仅第一次执行动画的条件变得困难。

一般来说,我想像这个例子那样做,但我改变了一点,但本质是一样的 - https://yasincamaz.medium.com/simple-item-animation-with-jetpack-composes-lazygrid -78316992af22

网格元素出现气泡效果是必要的

这是代码

private val dataSet: List<String> = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
private val data: List<String> = List(5) { dataSet }.flatten()

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Test_delete_itTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Gallery(
                        paddingValues = innerPadding,
                        uiConfig = { data }
                    )
                }
            }
        }
    }
}

@Composable
private fun Gallery(
    paddingValues: PaddingValues,
    uiConfig: () -> List<String>
) {
    val config: List<String> = uiConfig()
    val columns = 2

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(paddingValues)
    ) {
        LazyVerticalGrid(
            columns = GridCells.Fixed(columns),
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.spacedBy(8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            content = {
                items(config.size) { idx ->
                    val item: String = config[idx]
                    val (scale, alpha) = scaleAndAlpha(idx, columns)

                    MyItem(
                        modifier = Modifier.graphicsLayer(alpha = alpha, scaleX = scale, scaleY = scale),
                        text = item
                    )
                }
            }
        )
    }
}

@Composable
private fun MyItem(
    modifier: Modifier = Modifier,
    text: String
) {
    Card(
        modifier = modifier.height(150.dp),
        shape = RoundedCornerShape(16.dp),
        elevation = CardDefaults.cardElevation(8.dp),
        colors = CardDefaults.cardColors(
            containerColor = Color.Blue,
        )
    ) {
        Box(
            modifier = Modifier
                .weight(1f)
                .height(150.dp)
                .clip(RoundedCornerShape(16.dp))
        ) {
            Text(
                text = text,
                color = Color.White
            )
        }
    }
}

@Immutable
private enum class State { PLACING, PLACED }

@Immutable
data class ScaleAndAlphaArgs(
    val fromScale: Float,
    val toScale: Float,
    val fromAlpha: Float,
    val toAlpha: Float
)

@OptIn(ExperimentalTransitionApi::class)
@Composable
fun scaleAndAlpha(
    args: ScaleAndAlphaArgs,
    animation: FiniteAnimationSpec<Float>
): Pair<Float, Float> {
    val transitionState = remember { MutableTransitionState(State.PLACING).apply { targetState = State.PLACED } }
    val transition = rememberTransition(transitionState, label = "")
    val alpha by transition.animateFloat(transitionSpec = { animation }, label = "") {
        if (it == State.PLACING) args.fromAlpha else args.toAlpha
    }
    val scale by transition.animateFloat(transitionSpec = { animation }, label = "") {
        if (it == State.PLACING) args.fromScale else args.toScale
    }
    return alpha to scale
}

val scaleAndAlpha: @Composable (idx: Int, columns: Int) -> Pair<Float, Float> = { idx, columns ->
    scaleAndAlpha(
        args = ScaleAndAlphaArgs(2f, 1f, 0f, 1f),
        animation = tween(300, delayMillis = (idx / columns) * 100)
    )
}

您可以尝试将Gallery其更改为此以跟踪该元素是否已向用户显示

@Composable
private fun Gallery(
    paddingValues: PaddingValues,
    uiConfig: () -> List<String>
) {
    val config: List<String> = uiConfig()
    val columns = 2

    // Remember a set of already animated indices
    val animatedIndices = remember { mutableSetOf<Int>() }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(paddingValues)
    ) {
        LazyVerticalGrid(
            columns = GridCells.Fixed(columns),
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.spacedBy(8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            content = {
                items(config.size) { idx ->
                    val item: String = config[idx]

                    // Determine if the item should animate
                    val shouldAnimate = !animatedIndices.contains(idx)

                    // If it should animate, mark it as animated
                    if (shouldAnimate) {
                        animatedIndices.add(idx)
                    }

                    val (scale, alpha) = if (shouldAnimate) {
                        scaleAndAlpha(idx, columns)
                    } else {
                        1f to 1f // No animation
                    }

                    MyItem(
                        modifier = Modifier.graphicsLayer(alpha = alpha, scaleX = scale, scaleY = scale),
                        text = item
                    )
                }
            }
        )
    }
}

但问题是,这里每个元素都会调用两次重组 -items(config.size) { idx ->因此,该元素出现在屏幕上就好像没有动画一样

我在这里缺少什么?

android
  • 1 个回答
  • 23 Views
Martin Hope
Sirop4ik
Asked: 2024-08-09 01:28:47 +0000 UTC

NavHost 在切换屏幕时连续进行多次重组

  • 6

有这段代码作为重现的最小示例

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.krokosha.focusrequester2.ui.theme.Test_delete_itTheme

private const val FIRST_SCREEN_ROUTE = "first_screen"
private const val SECOND_SCREEN_ROUTE = "second_screen"

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Test_delete_itTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    shape = RectangleShape
                ) {
                    Greeting()
                }
            }
        }
    }
}

@Composable
fun Greeting() {
    val navigator: NavHostController = rememberNavController()

    NavHost(
        navController = navigator,
        startDestination = FIRST_SCREEN_ROUTE
    ) {
        composable(FIRST_SCREEN_ROUTE) {
            Log.e("HERE", "1 SCREEN")
            FirstScreen(onClick = { navigator.navigate(SECOND_SCREEN_ROUTE) }) }
        composable(SECOND_SCREEN_ROUTE) {
            Log.e("HERE", "2 SCREEN")
            SecondScreen() }
    }
}

@Composable
fun SecondScreen() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Red.copy(alpha = 0.1f)),
        contentAlignment = Alignment.Center
    ) {
        Text(text = "SECOND SCREEN")
    }
}

@Composable
fun FirstScreen(onClick: () -> Unit) {
    Row(modifier = Modifier
        .fillMaxSize()
    ) {
        LeftPanel()
        RightPanel(onClick = onClick)
    }
}

@Composable
fun RowScope.LeftPanel() {
    val buttons: List<String> by rememberSaveable { mutableStateOf(List(5) { "Button ${it + 1}" }) }

    LazyColumn(
        modifier = Modifier
            .background(Color.Blue.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        itemsIndexed(
            items = buttons,
            key = { idx, _ -> idx }
        ) { idx, _ ->
            Button(
                modifier = Modifier,
                onClick = { /* nothing */ }
            ) {
                Text(text = "Left Panel: $idx")
            }
        }
    }
}

@Composable
fun RowScope.RightPanel(onClick: () -> Unit) {
    val buttons: List<String> by rememberSaveable { mutableStateOf(List(4) { "Button ${it + 1}" }) }

    Column(
        modifier = Modifier
            .background(Color.Green.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        LazyVerticalGrid(
            modifier = Modifier.padding(16.dp),
            columns = GridCells.Fixed(2),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            itemsIndexed(
                items = buttons,
                key = { idx, _ -> idx }
            ) { idx, _ ->
                Button(
                    modifier = Modifier
                        .padding(8.dp),
                    onClick = {
                        onClick()
                    }
                ) {
                    Text(text = "Right Panel: $idx")
                }
            }
        }
    }
}

在此输入图像描述

我离开了登录状态composable(FIRST_SCREEN_ROUTE),composable(SECOND_SCREEN_ROUTE)当我单击右侧面板(屏幕上)中的按钮时,我在日志中看到以下内容(以及 中的相同内容LayoutInspector)

13:26:43.572  E  1 SCREEN
13:26:46.570  E  1 SCREEN
13:26:46.580  E  2 SCREEN
13:26:46.661  E  1 SCREEN
13:26:46.668  E  2 SCREEN
13:26:47.369  E  2 SCREEN
13:26:47.438  E  2 SCREEN

问题是——最空的例子加上最空的导航,切换屏幕时怎么会发生多次重组呢?

android
  • 1 个回答
  • 24 Views
Martin Hope
Sirop4ik
Asked: 2024-07-05 03:26:45 +0000 UTC

返回屏幕时如何将焦点分配到同一位置?

  • 6

我正在开发一个关于 AndroidTV 的项目,该平台的独特之处在于用户使用遥控器将焦点移动到屏幕上。

这是屏幕:

在此输入图像描述

当您专注工作时,有两个主要任务:

  1. 当您从左向右移动时,反之亦然,焦点不应混淆位置。例如,用户单击鼠标右键Left Panel 0 -> Right Panel 0,在右侧面板中我们移动到Right Panel 2左侧单击,焦点移动到,Left Panel 0因为用户将焦点移动到右侧面板。此功能已使用focusRestorer并已在运行。

  2. 当右侧面板中的用户单击(例如:) 时RigthPanel 1,它会打开Second Screen,然后用户单击后退并返回到First Screen,此处预计用于打开屏幕的按钮将成为焦点,即Right Panel 1,但对于某些这是因为它在 30% 的情况下有效,并且焦点不是集中在预期的按钮上,而是另一个按钮上。

视频 -> https://drive.google.com/file/d/1NCal4kxx0op74-Yj5v00wOBcnCRSSlUb/view

以下是您可以复制并运行的代码:

private const val FIRST_SCREEN_ROUTE = "first_screen"
private const val SECOND_SCREEN_ROUTE = "second_screen"
private const val DEFAULT_FOCUS_POSITION = -1

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Test_delete_itTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    shape = RectangleShape
                ) {
                    Greeting()
                }
            }
        }
    }
}

@Composable
fun Greeting() {
    val navigator: NavHostController = rememberNavController()

    NavHost(
        navController = navigator,
        startDestination = FIRST_SCREEN_ROUTE
    ) {
        composable(FIRST_SCREEN_ROUTE) {
            DisposableEffect(Unit) {
                Log.e("HERE", "1 CREATED first_screen_route")

                onDispose {
                    Log.e("HERE", "DISPOSED first_screen_route")
                }
            }

            FirstScreen(onClick = {
                Log.e("HERE", "NAVIGATION TO SECOND SCREEN")
                navigator.navigate(SECOND_SCREEN_ROUTE)
            })
        }

        composable(SECOND_SCREEN_ROUTE) {
            DisposableEffect(Unit) {
                Log.e("HERE", "CREATED second_screen_route")

                onDispose {
                    Log.e("HERE", "DISPOSED second_screen_route")
                }
            }

            SecondScreen()
        }
    }
}

@Composable
fun SecondScreen() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Red.copy(alpha = 0.1f)),
        contentAlignment = Alignment.Center
    ) {
        Text(text = "SECOND SCREEN")
    }
}

@Composable
fun FirstScreen(
    onClick: () -> Unit
) {
    var focusBtnIdx by rememberSaveable { mutableIntStateOf(DEFAULT_FOCUS_POSITION) }

    Row(modifier = Modifier
        .fillMaxSize()
    ) {
        LeftPanel()
        RightPanel(onClick = onClick, focusBtnIdx = focusBtnIdx, setFocusBtnIdx = { focusBtnIdx = it })
    }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun RowScope.LeftPanel() {
    val firstItemFr = remember { FocusRequester() }
    val buttons by rememberSaveable { mutableStateOf(List(5) { "Button ${it + 1}" }) }

    LaunchedEffect(Unit) {
        this.coroutineContext.job.invokeOnCompletion {
            try { firstItemFr.requestFocus() }
            catch (e: Exception) {/* do nothing */ }
        }
    }

    TvLazyColumn(
        modifier = Modifier
            .focusRestorer { firstItemFr }
            .background(Color.Blue.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        itemsIndexed(
            items = buttons,
            key = { idx, _ -> idx }
        ) { idx, _ ->
            Button(
                modifier = Modifier
                    .let { modifier ->
                        if (idx == 0) {
                            modifier.focusRequester(firstItemFr)
                        } else {
                            modifier
                        }
                    },
                onClick = {}
            ) {
                Text(text = "Left Panel: $idx")
            }
        }
    }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun RowScope.RightPanel(
    onClick: () -> Unit,
    focusBtnIdx: Int,
    setFocusBtnIdx: (Int) -> Unit
) {
    val firstItemFr = remember { FocusRequester() }

    LaunchedEffect(Unit) {
        this.coroutineContext.job.invokeOnCompletion {
            try {
                Log.e("HERE", ">>> REQUEST FOCUS")
                if (focusBtnIdx != DEFAULT_FOCUS_POSITION) {
                    firstItemFr.requestFocus()
                    Log.e("HERE", "<<< REQUEST FOCUS")
                }
            }
            catch (e: Exception) {
                /* do nothing */
                Log.e("HERE", "FOCUS ERROR: $e")
            }
        }
    }

    Column(
        modifier = Modifier
            .background(Color.Green.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        val buttons: List<String> by rememberSaveable { mutableStateOf(List(4) { "Button ${it + 1}" }) }

        TvLazyVerticalGrid(
            modifier = Modifier
                .focusRestorer { firstItemFr }
                .padding(16.dp),
            columns = TvGridCells.Fixed(2),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            itemsIndexed(
                items = buttons,
                key = { idx, _ -> idx }
            ) { idx, _ ->
                Button(
                    modifier = Modifier
                        .padding(8.dp)
                        .let {
                            Log.e("HERE", "1 RightPanel: $idx")
                            if (idx == focusBtnIdx || (focusBtnIdx == DEFAULT_FOCUS_POSITION && idx == 0)) {
                                Log.e("HERE", "2 RightPanel: $idx")
                                it.focusRequester(firstItemFr)
                            } else {
                                it
                            }
                        },
                    onClick = {
                        setFocusBtnIdx(idx)
                        onClick()
                    }
                ) {
                    Text(text = "Right Panel: $idx")
                }
            }
        }
    }
}

日志显示焦点已分配并在所需的按钮上调用,但由于某种原因,屏幕上的焦点位于另一个按钮上。

假设实现本身存在错误focusRequester

我缺少什么?

android
  • 1 个回答
  • 20 Views
Martin Hope
Sirop4ik
Asked: 2024-07-02 22:02:28 +0000 UTC

单击左侧的(远程控制)时如何将焦点返回到同一视图?

  • 6

我有一个这样的屏幕(Andorid TV)

在此输入图像描述

我需要这样做:

  1. 当屏幕打开时,焦点位于左侧面板中的第一个视图上(左侧面板:0)
  2. 用户可以(在遥控器上)上下切换左侧面板中的元素
  3. 如果用户按向右,焦点将移至第一个视图中的右侧面板(右侧面板:0)
  4. 用户可以根据需要在右侧面板中的元素之间移动焦点
  5. 如果用户位于左侧堆栈的右侧面板中,按向左键,则焦点应移动到左侧面板到从其转到右侧面板的元素。也就是说,如果用户位于左侧面板中的第三个元素上并向右按下,那么当他从右侧面板返回到左侧时,焦点应移回到他之前所在的第三个元素。

总的来说,除了第 5 点之外,一切都正常

这是代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Test_delete_itTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    shape = RectangleShape
                ) {
                    Greeting()
                }
            }
        }
    }
}

@Composable
fun Greeting() {
    val leftPanelFocusRequester: FocusRequester = remember { FocusRequester() }
    val rightPanelFocusRequester: FocusRequester = remember { FocusRequester() }

    Row(modifier = Modifier
        .fillMaxSize()
    ) {
        LeftPanel(
            focusRequester = leftPanelFocusRequester,
            onRightDirectionClicked = {
                rightPanelFocusRequester.requestFocus()
            }
        )
        RightPanel(focusRequester = rightPanelFocusRequester)
    }
}

@Composable
fun RowScope.LeftPanel(
    focusRequester: FocusRequester,
    onRightDirectionClicked: () -> Unit
) {
    LaunchedEffect(Unit) {
        this.coroutineContext.job.invokeOnCompletion {
            focusRequester.requestFocus()
        }
    }

    Column(
        modifier = Modifier
            .background(Color.Blue.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f)
            .onKeyEvent {
                if (it.key == Key.DirectionRight) {
                    onRightDirectionClicked()
                    true
                } else {
                    false
                }
            },
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        repeat(5) {
            Button(
                modifier = Modifier
                    .let { modifier ->
                        if (it == 0) {
                            modifier.focusRequester(focusRequester)
                        } else {
                            modifier
                        }
                    },
                onClick = { }
            ) {
                Text(text = "Left Panel: $it")
            }
        }
    }
}

@Composable
fun RowScope.RightPanel(focusRequester: FocusRequester) {
    Column(
        modifier = Modifier
            .background(Color.Green.copy(alpha = 0.1f))
            .fillMaxHeight()
            .weight(1f),
        verticalArrangement = Arrangement.spacedBy(8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        val buttons by rememberSaveable { mutableStateOf(List(10) { "Button ${it + 1}" }) }

        LazyVerticalGrid(
            columns = GridCells.Fixed(2),
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            itemsIndexed(
                items = buttons,
                key = { idx, _ -> idx }
            ) { idx, _ ->
                Button(
                    modifier = Modifier
                        .padding(8.dp)
                        .let {
                            if (idx == 0) {
                                it.focusRequester(focusRequester)
                            } else {
                                it
                            }
                        }
                    ,
                    onClick = { }
                ) {
                    Text(text = "Right Panel: $idx")
                }
            }
        }
    }
}

据我想象,您需要记住用户转到右侧面板的索引(假设按钮3)并跟踪用户向左的单击,当用户单击向左时,然后请求将焦点放在保存的索引(在我们的示例 3 中)。但这2个问题

  1. 如何区分右侧面板元素之间的右键单击(例如,右侧面板 3 -> 右侧面板 2 单击)和所需的单击(例如,右侧面板:6 -> 左侧面板 3)?
  2. 在我看来,这个解决方案看起来太麻烦了,不知何故,这一切应该更简单。

欢迎任何想法:)

UPD

我还有一个相关的问题,如果有人感兴趣欢迎 - https://ru.stackoverflow.com/a/1586671/195957

android
  • 1 个回答
  • 28 Views
Martin Hope
Sirop4ik
Asked: 2024-06-11 00:58:09 +0000 UTC

为什么会出现CompletionHandlerException?

  • 5

有Column一个按钮列表,您需要要求将焦点放在列表中的第一个按钮上,我是这样做的

...
               var modifier: Modifier = Modifier
                   .height(96.toDpWithOffset)
                   .width(520.toDpWithOffset)


               if (idx == 0) {
                   modifier = modifier.focusRequester(focusRequester)
               }

               Button(modifier = modifier...
...

也就是说,如果这是第一个按钮,则添加focusRequester到modifier

问题是这样的:视觉上它可以像这样缩短

...
                Button(
                    modifier = Modifier
                        .height(96.toDpWithOffset)
                        .width(520.toDpWithOffset)
                        .apply {
                            if (idx == 0) {
                                this.focusRequester(focusRequester)
                            }
                        }
...

但由于某种原因它会引发错误

Process: ca.bellmedia.cravetv.debug, PID: 27984
                 kotlinx.coroutines.CompletionHandlerException: Exception in completion handler InvokeOnCompletion@b5280d2[job@9cd05a3] for StandaloneCoroutine{Completed}@9cd05a3
                    at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:322)
                    at kotlinx.coroutines.JobSupport.tryFinalizeSimpleState(JobSupport.kt:297)
                    at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:860)
                    at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:832)
                    at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
                    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
                    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
                    at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
                    at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
                    at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
                    at android.os.Handler.handleCallback(Handler.java:958)
                    at android.os.Handler.dispatchMessage(Handler.java:99)
                    at android.os.Looper.loopOnce(Looper.java:205)
                    at android.os.Looper.loop(Looper.java:294)
                    at android.app.ActivityThread.main(ActivityThread.java:8177)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@99dc6cc, androidx.compose.runtime.BroadcastFrameClock@887fd15, StandaloneCoroutine{Completed}@9cd05a3, AndroidUiDispatcher@441582a]
                 Caused by: java.lang.IllegalStateException: 
                    FocusRequester is not initialized. Here are some possible fixes:
                 
                    1. Remember the FocusRequester: val focusRequester = remember { FocusRequester() }
                    2. Did you forget to add a Modifier.focusRequester() ?
                    3. Are you attempting to request focus during composition? Focus requests should be made in
                    response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }

我在这里缺少什么?

android
  • 1 个回答
  • 32 Views
Martin Hope
Sirop4ik
Asked: 2024-06-07 22:40:59 +0000 UTC

为什么 dp 在 andorid TV 上不能按预期工作?

  • 5

在 Android TV 上,我使用 Jetpack Compose,其中卡大小在 720p(模拟器)和 1080p(模拟器)电视上看起来不同。

720: 在此输入图像描述

1080: 在此输入图像描述

卡代码:

...
Card(
            modifier = Modifier
                .width(412.dp)
                .height(200.dp),
            border = CardDefaults.border(border = Border.None),
            colors = CardDefaults.colors(
                containerColor = ColorTokens.grey_40,
                contentColor = ColorTokens.white,
                focusedContainerColor = Color.White,
                focusedContentColor = Color.Black,
                pressedContainerColor = Color.Gray,
                pressedContentColor = Color.LightGray
            ),
            shape = CardDefaults.shape (shape = RoundedCornerShape(CornerRadiusTokens.radius_300.withDPIOffset(LocalContext.current))),
            onClick = { /*TODO*/ },
        )
...

我希望这些卡片在两个屏幕上看起来都是一样的dp。我缺少什么?

android
  • 1 个回答
  • 30 Views
Martin Hope
Sirop4ik
Asked: 2024-03-22 22:22:34 +0000 UTC

如何在辅助功能模式下关闭撰写对话框?

  • 5

我有一个正在撰写的对话

...
    Dialog(
        properties = DialogProperties(usePlatformDefaultWidth = false),
        onDismissRequest = { eventReceiver.contentEventReceiver.onCellClick?.invoke(null) }
    ) {
        (LocalView.current.parent as DialogWindowProvider).window.apply {
            setDimAmount(0.8f)
            setGravity(Gravity.CENTER_VERTICAL)
        }

        rotator.ContentCellHorizontalRotator(
            selectedContent = selectedItem
        )
    }
...

问题是该对话框没有X用户可以单击并关闭它的按钮,这意味着用户在对话框外部单击并将其关闭。

但是,问题出在辅助功能模式下(对于有视力问题的人来说是可以接受的),那么在这种情况下,回溯将读取屏幕上的所有内容,包括可用选项,但没有关闭对话框的选项。换句话说,打开对话的人无法关闭它。

例如,在 iOS 中,要关闭对话框,有一个开箱即用的手势 - 用两根手指在屏幕上拖动 Z 形状,但我还没有发现 Android 中存在这种情况。

有人对此有什么想法吗?

android
  • 1 个回答
  • 23 Views
Martin Hope
Sirop4ik
Asked: 2024-03-22 01:30:17 +0000 UTC

如何正确使用testImplementation?

  • 4

我需要写一些测试,像这样

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("ent.test", appContext.packageName)
    }
}

为了使它工作,我添加了这个依赖项:

testImplementation "androidx.test.ext:junit-ktx:${project.test.JUnit}"

但一切都以红色突出显示,依赖关系未被识别,我更改为

implementation "androidx.test.ext:junit-ktx:${project.test.JUnit}"

一切正常

据我了解,对于测试依赖项,您需要使用testImplementation,以免将它们与将要进入构建的依赖项混合,但问题是,为什么当我使用testImplementation它时,依赖项不被识别?

java
  • 1 个回答
  • 26 Views
Martin Hope
Sirop4ik
Asked: 2024-02-21 04:25:27 +0000 UTC

如何从片段调用 onBackPressedDispatcher?.onBackPressed() ?

  • 5

onBackPressedDispatcher?.onBackPressed()我对片段中的实现有点困惑。

我有一个活动和一个片段。

我在片段中有一系列操作 - >当用户按下“后退”按钮时,我需要显示一个对话框,询问:“您确定吗?” 当用户点击“Yes”后,你需要执行onBackPressed。

为此,我在我的片段中做了 ->

...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                showAlertDialog(
                    message = getString(R.string.myText),
                    dialogCallback = object : AlertDialogInterface {
                        override fun onAlertDialogButtonClicked(alertDialog: AlertDialog?) {}

                        override fun onPositiveButtonClicked(alertDialog: AlertDialog?) {
                            isEnabled = false
                            alertDialog?.dismiss()
                            activity?.onBackPressedDispatcher?.onBackPressed()
                        }

                        override fun onNegativeButtonClicked(alertDialog: AlertDialog?) {
                            alertDialog?.dismiss()
                        }
                    }
                    )
            }
        }

        activity?.onBackPressedDispatcher?.addCallback(
            this,
            callback
        )
    }
...

我猜测当用户在对话框上单击“是”时,它会触发一个事件onPositiveButtonClicked,并执行onBackPressed我调用此行 ->activity?.onBackPressedDispatcher?.onBackPressed()但这会导致循环而不是返回。

我在这里错过了什么?

android
  • 1 个回答
  • 20 Views
Martin Hope
Sirop4ik
Asked: 2024-01-26 02:34:56 +0000 UTC

如何在带有参数的 Compose 函数中使用 @Preview?

  • 6

我有这个代码:

...

    @Composable
    private fun PhoneVerificationCodeScreen(vm: MyViewModel) {
        Column(...) {
...
            OTPBlock(numberOfCells = NUMBER_OF_OTP_CELLS, isVerifyBtnEnabledState = vm.isVerifyBtnEnabledState)
...
        }
    }

...

这是预览功能:

    class MyViewModelProvider : PreviewParameterProvider<MyViewModel> {
        override val values: Sequence<MyViewModel> = sequenceOf(MyViewModel(
            SavedStateHandle()
        ))
    }

    @Preview(
        name = "Phone-portrait",
        device = Devices.PHONE,
        showBackground = true,
        backgroundColor = 0x111,
        showSystemUi = true
    )
    @Composable
    private fun PhonePreviewVerificationCodeScreen(
        @PreviewParameter(MyViewModelProvider::class) vm: MyViewModel
    ) = PhoneVerificationCodeScreen(vm = vm)

剧透:在我将 ViewModel 放入参数之前,一切正常。

我检查了几个答案,我尝试的最后一个答案是使用PreviewParameterProvider,但这也不起作用。

问题是如何“预览” compose 中带有参数的函数?

错误:

java.lang.ClassNotFoundException:my_package.VerificationCodeViewModelProvider在java.lang.ClassLoader.loadClass在java.lang.ClassLoader.loadClass在java.lang.Class.forName0在java.lang.Class.forName在androidx.compose.ui.tooling。 ComposableInvoker.invokeComposable 

android
  • 1 个回答
  • 26 Views
Martin Hope
Sirop4ik
Asked: 2023-08-28 03:20:38 +0000 UTC

如何正确制作通用函数“getCallFrom”?

  • 6
class MyClass {
    
    // Функция для получения запроса ApolloQueryCall из Query
    fun getCallFrom(query: Query<*, *, *>): ApolloQueryCall<out Any?> = apolloClient.query(query)

    // Функция для тестирования
    fun test() {
        // Первый запрос с ожиданием ответа типа com.apollographql.apollo.api.Response<MyTestQuery.Data>
        val response1: com.apollographql.apollo.api.Response<MyTestQuery.Data> = apolloClient.query(
            MyTestQuery("test")
        ).await()
        
        // Второй запрос, использующий вашу общую функцию
        // Проблема в том, что вам нужно получить тот же тип результата, что и response1
        val response2: com.apollographql.apollo.api.Response<out Any?> = getCallFrom(
            MyTestQuery("test")
        ).await()
    }
}

该函数有test()两个响应(response1和response2),但返回类型有所不同。对于第一个我使用的appoloClient.query,对于第二个我使用我的一般功能getCallFrom。

我需要从通用函数中获得与response1(com.apollographql.apollo.api.Response<MyTestQuery.Data>) 中相同类型的结果。

我尝试了不同的传递类型的方法(而不是 *),但它不起作用。

我究竟做错了什么?

kotlin
  • 1 个回答
  • 27 Views
Martin Hope
Sirop4ik
Asked: 2023-08-02 21:59:27 +0000 UTC

未生成 AAR 文件

  • 7

我有一个项目和一个 lib 模块(该项目基本上是 lib 模块的包装器,用于创建 .aar)。预计它会像这样工作:在构建项目之后,应该构建 lib 模块,并.aar在文件夹中生成build-> output,该文件夹已经可以在需要时使用。但问题是它没有被创建。

必须说的是,项目中有2个lib模块,每次都成功生成第二个lib-module.aar文件,也就是说,很明显第一个lib模块没有创建的地方有问题.aar。

我尝试过清理、重建、无效和所有这些事情,但它不起作用。

猜猜可能是什么问题?

是否可以(也许通过日志)检查工作室试图在哪里创建.aar?或者如何更改文件的保存位置?或者只是看一些关于它的创作的信息?

UPD

未生成该模块的gradle文件

import org.jetbrains.kotlin.gradle.plugin.myproject.KotlinNativeTarget

plugins {
    kotlin("multiplatform")
    id("com.android.library")
    id("maven-publish")
    id("kotlin-android-extensions")
}

var frameworkName = "myframeworkname"
group = "here.my.library"
version = "0.0.2"

kotlin {
    android()

    ios {
        compilations.forEach {
            it.kotlinOptions.freeCompilerArgs += arrayOf("-linker-options", "-application_extension")
        }
        binaries {
            framework {
                baseName = "mybasename"
                embedBitcode("disable")
            }
        }
    }

    tvos {
        compilations.forEach {
            it.kotlinOptions.freeCompilerArgs += arrayOf("-linker-options", "-application_extension")
        }
        binaries {
            framework {
                baseName = "mybasename"
                embedBitcode("bitcode")
            }
        }
    }

    sourceSets {
        val commonMain by getting

        val androidMain by getting {
            dependencies {
                implementation("com.google.android.material:material:1.2.1")
            }
        }

        val iosMain by getting

        val tvosMain by getting {
            dependsOn(iosMain)
        }

        val iosTest by getting

        val tvosTest by getting

        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
    }
    
    android {
        publishLibraryVariants("release", "debug")
    }

    configure(listOf(targets["metadata"], android())) {
        mavenPublication {
            val targetPublication = this@mavenPublication
            tasks.withType<AbstractPublishToMaven>()
                .matching { it.publication == targetPublication }
        }
    }
}

android {
    compileSdk = 30
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 24
        targetSdk = 30
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
}

publishing {
    println("Project dir : ${projectDir.name}")
    publications {
        create<MavenPublication>("lib") {
            groupId = "entpay.shared.library"
            artifactId = project.name
            version = project.version as String?
            artifact("$buildDir/outputs/aar/${projectDir.name}-release.aar")
        }
    }

    repositories {
        mavenLocal()
    }
}

val packForXcode by tasks.creating(Sync::class) {
    val xcodeMode = if (System.getenv("CONFIGURATION").equals("release", true)) "RELEASE" else "DEBUG"
    val frameworksDirectory = File(buildDir, "xcode-frameworks")
    val target = System.getProperty("TARGET_PLATFORM") ?: "iosX64"
    println("target = ${target}")
    println("configuration = ${xcodeMode}")
    group = "build"
    inputs.property("mode", xcodeMode)
    val framework = kotlin.targets.getByName<KotlinNativeTarget>(target).binaries.getFramework(xcodeMode)
    dependsOn(framework.linkTask)
    from({ framework.outputDirectory })
    val path = File(frameworksDirectory,target)
    into(path)
}

tasks.getByName("build").dependsOn(packForXcode)
java
  • 1 个回答
  • 32 Views
Martin Hope
Sirop4ik
Asked: 2022-12-11 00:17:22 +0000 UTC

为什么在实现中没有指出这些方法已被弃用(尽管在文档中是这样)?

  • 6

为了使用,EncryptedSharedPreferences我添加了这个依赖

implementation "androidx.security:security-crypto:1.0.0"

我这样使用它

...
        val sharedPref = EncryptedSharedPreferences.create(
            PREF_NAME,
            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
            context,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
...

然后我遇到了 off doc - https://developer.android.com/reference/androidx/security/crypto/MasterKeys其中说这个类deprecated,这里​​有一些关于如何正确执行它的建议 - https://stackoverflow。 com/a/62504831/5098477

但是,为什么当我在代码中打开一个类或方法的实现时,没有提到它是什么deprecated?

/**
 * Convenient methods to create and obtain master keys in Android Keystore.
 *
 * <p>The master keys are used to encrypt data encryption keys for encrypting files and preferences.
 */
public final class MasterKeys {
    private MasterKeys() {
    }

或者在这里

    /**
     * Creates or gets the master key provided
     *
     * The encryption scheme is required fields to ensure that the type of
     * encryption used is clear to developers.
     *
     * @param keyGenParameterSpec The key encryption scheme
     * @return The key alias for the master key
     */
    @NonNull
    public static String getOrCreate(
            @NonNull KeyGenParameterSpec keyGenParameterSpec)
            throws GeneralSecurityException, IOException {
        validate(keyGenParameterSpec);
        if (!MasterKeys.keyExists(keyGenParameterSpec.getKeystoreAlias())) {
            generateKey(keyGenParameterSpec);
        }
        return keyGenParameterSpec.getKeystoreAlias();
    }

我不明白为什么不显示这些方法deprecated?

java
  • 1 个回答
  • 25 Views
Martin Hope
Sirop4ik
Asked: 2022-12-03 00:56:28 +0000 UTC

如何在请求所在的同一线程上获得回调(Retrofit)?

  • 8

问题是无论在哪个线程上发出请求,回调都会在主线程上返回。您可以让回调飞到后台,但为此您需要按照此答案中的描述更改配置:https ://stackoverflow.com/a/41370867/5709159

...
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(/* your url */)
        .callbackExecutor(Executors.newSingleThreadExecutor())  <--- THIS LINE
        // other builder options...
        .build();
...

但是所有回调都会在后台到达,我需要能够控制哪些回调在后台到达,哪些在 main 中,为此,在请求所在的同一线程上接收回调会非常方便被制作了,但我有这样的选择,我看不到。

问题是如何在请求之前确定在哪个线程上接收回调?我不想有两种 Retrofit 配置(如上所述),一种是背景指示,另一种是默认配置。

java
  • 1 个回答
  • 35 Views
Martin Hope
Sirop4ik
Asked: 2022-09-05 09:18:58 +0000 UTC

为什么子模块在更新后会切换到 HEAD?

  • 0

我的 git repo 正在使用submodule,当我在我的主 repo 中提取更改时,我也在终端中执行此命令

git submodule update --recursive

当我打开我的时submodule,我看到它不是在一个dev分支上,而是由于某种原因它切换到HEAD几周前有一个指针,也就是说,没有更新,我可以说是把它切换回它用我的双手dev(和 HEAD 同时消失)

一般来说,我不是很明白,我期望调用命令时,update --recursive所有子模块都应该从它们所在的分支中拉取最新的更改,也就是说,如果子模块现在有一个活动分支,dev那么它应该拉所有开发人员的最新更改,而不是创建仍然未更新的 HEAD...

我究竟做错了什么?

git
  • 0 个回答
  • 0 Views
Martin Hope
Sirop4ik
Asked: 2022-08-25 04:18:47 +0000 UTC

错误:(JetPack Compose)类型 'TypeVariable(T)' 没有方法 'getValue(Nothing?, KProperty<*>)

  • 0

我发现一篇文章解释了如何在其中对图像进行视差处理lazyColumn,因此那里有这样的方法

@Composable
    fun ImageParallaxScroll() {
        val lazyListState = rememberLazyListState()
        val list = (0..1_000).map{ "Item $it" }.toList()

        val firstItemTranslationY: LazyListState by remember {
            derivedStateOf {
                when {
                    lazyListState.layoutInfo.visibleItemsInfo.isNotEmpty() && lazyListState.firstVisibleItemIndex == 0 -> lazyListState.firstVisibleItemScrollOffset * .6f
                    else -> 0f
                }
            }
        }

            ...
    }

问题是整个块remember都用红色下划线写了下面的错误

Type 'TypeVariable(T)' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate

怎么了?无法弄清楚如何修复

android
  • 1 个回答
  • 32 Views
Martin Hope
Sirop4ik
Asked: 2022-08-24 10:39:40 +0000 UTC

从资源中获取颜色(Jetpack Compose)的正确方法是什么?

  • 0

我正在使用资源,因为我需要支持多个BuildVariants. 我在Color.kt哪里定义了所有颜色并color.xml像这样从中获取它们

val MyWhiteColor: Color = Color(R.color.my_white_color)

我这样申请

    Text(
        text = ...,
        style = TextStyle(
            color = MyWhiteColor
        )
    )

问题是我得到的是蓝色而不是白色,但是如果我改变颜色不是从color.xml,即像这样

val MyWhiteColor: Color = Color(android.graphics.Color.parseColor("#FFFFFF"))

然后一切正常,我得到白色。

我错过了什么?为什么当我转向color.xml那个我得到蓝色而不是白色?

UPD

<color name="my_white_color">#FFFFFF</color>
android
  • 1 个回答
  • 43 Views

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5