如何在Jetpack compose中制作动态ScrollableTabRow

问题描述 投票:0回答:1

我必须创建动态 ScrollableTabRow,其中我最初将有 3 个选项卡,但我可以在运行时添加多个选项卡,而且所有新添加的选项卡将具有关闭图标以删除选项卡。并且每个新屏幕将有单独的 BottomNavigation(每个屏幕将有 6 到 7 个可滚动的底部 Navitems)。 我怎样才能有效地做到这一点

我面临一个问题,即在添加选项卡时打开同一个实例。

@Composable
fun HomeScreenWithScrollableTabRow(
    modifier: Modifier= Modifier,
    tabsViewModel: TabLayoutVM = viewModel()){


    val scope = rememberCoroutineScope()

    Column(
        modifier = modifier.fillMaxSize()) {
        ScrollableTabRow(
            edgePadding = 4.dp,
            modifier = Modifier
                .fillMaxWidth()
                .background(MaterialTheme.colorScheme.onSurface),
            selectedTabIndex = tabsViewModel.selectedTabIndex.intValue) {
            tabsViewModel.tabs.forEachIndexed{index, title ->
                Tab(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(50.dp)
                        .padding(horizontal = 10.dp),
                    selected = tabsViewModel.selectedTabIndex.intValue == index,
                    onClick = {
                        tabsViewModel.selectTab(index)
                    },
                    text = {
                        Row(
                            verticalAlignment = Alignment.CenterVertically
                        ){
                            Text(
                                title,
                                fontWeight = FontWeight.Bold
                            )
                            if (index >= 3) {
                                Spacer(modifier = Modifier.width(1.dp))
                                IconButton(
                                    onClick = {
                                        tabsViewModel.removeTab(index)
                                    }){
                                    Icon(Icons.Default.Close, contentDescription = "Close Icon")
                                }
                            }
                        }
                    }
                )
            }
        }
        TabContent(
            tabs = tabsViewModel.tabs,
            selectedIndex = tabsViewModel.selectedTabIndex.intValue,
            onAddTab = { newTabName ->
                tabsViewModel.addTab(newTabName)
                scope.launch {
                    delay(100)
                    tabsViewModel.selectTab(tabsViewModel.tabs.size.minus(1))
                }
            },
            onPress = {
                tabsViewModel.currentSelectedDeviceForGraph(it)
            },
            currentSelectedDevice = tabsViewModel.currentSelectedDevice.value,
            tabsViewModel = tabsViewModel
        )
    }
}


@Composable
fun TabContent(
    selectedIndex:Int,
    tabs: List<String>,
    onPress:(String)->Unit,
    onAddTab: (String) -> Unit,
    currentSelectedDevice:String?,
    tabsViewModel: TabLayoutVM){

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        contentAlignment = Alignment.TopStart){

        when (selectedIndex) {
            0 -> ScannerScreen(currentSelectedDevice,onPress,onAddTab)
            1 -> BondedScreen()
            2 -> AdvertiserScreen()
            else -> {
                TabScreen()
            }
        }
    }
}
class TabLayoutVM: ViewModel() {

    private val _tabs = mutableStateListOf("Scanner", "Bonded", "Advertiser")
    val tabs: List<String> = _tabs

    private var _selectedTabIndex = mutableIntStateOf(0)
    val selectedTabIndex: MutableIntState = _selectedTabIndex


    var currentSelectedDevice = mutableStateOf<String?>(null)
        private set




    fun addTab(deviceName:String) {
        _tabs.add(deviceName)
    }

    fun removeTab(index: Int) {
        if (_tabs.size > 3) {
            _tabs.removeAt(index)
            if (selectedTabIndex.intValue >= _tabs.size) {
                selectedTabIndex.intValue = _tabs.size - 1
            }
        }
    }

    fun selectTab(index: Int) {
        selectedTabIndex.intValue = index
    }

    fun currentSelectedDeviceForGraph(device: String?){
        currentSelectedDevice.value = device
    }

@Composable
fun TabScreen(deviceName:String, genericVM: GenericVM= viewModel()) {

    val bottomNavIndex = genericVM.bottomNavIndex.value

    val tabs = listOf("GPS", "GSM", "CAN", "ACC", "DEVICE")

    Scaffold(
        topBar = {
            //Add Top App Bar inside Tab Layout if have
        },
        bottomBar = {
            ScrollableTabRow(
                selectedTabIndex = bottomNavIndex,
                modifier = Modifier.fillMaxWidth(),
                edgePadding = 4.dp
            ) {
                tabs.forEachIndexed { index, title ->
                    Tab(
                        text = { Text(title) },
                        selected = bottomNavIndex == index,
                        onClick = { genericVM.setBottomNavIndex(index)},
                        icon = {
                            when (index) {
                                0 -> Icon(imageVector = Icons.Default.GpsFixed, contentDescription = null)
                                1 -> Icon(imageVector = Icons.Default.SettingsInputAntenna, contentDescription = null)
                                2 -> Icon(imageVector = Icons.Default.Settings, contentDescription = null)
                                3 -> Icon(imageVector = Icons.Default.Lock, contentDescription = null)
                                4 -> Icon(imageVector = Icons.Default.Devices, contentDescription = null)
                            }
                        }
                    )
                }
            }
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .padding(paddingValues)
                .fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            when (bottomNavIndex) {
                0 -> Text("${tabs[0]} Content")
                1 -> Text("${tabs[1]} Content")
                2 -> Text("${tabs[2]} Content")
                3 -> Text("${tabs[3]} Content")
                4 -> Text("${tabs[4]} Content")
            }
        }
    }
}

android kotlin mobile mobile-development
1个回答
0
投票

只需将

tabs
移至视图模型即可:

private val _tabs: MutableStateFlow<List<String>> =
    MutableStateFlow(listOf("GPS", "GSM", "CAN", "ACC", "DEVICE"))
val tabs = _tabs.asStateFlow()

fun addTab(tab: String) {
    _tabs.update { it + tab }
}

fun removeTab(tab: String) {
    _tabs.update { it - tab }
}

TabScreen
中,您可以替换

val tabs = listOf("GPS", "GSM", "CAN", "ACC", "DEVICE")

val tabs by genericVM.tabs.collectAsStateWithLifecycle()

就是这样。
如果您想调整选项卡的数量,请相应地调用视图模型函数:

genericVM.addTab("new Tab")
genericVM.removeTab("GPS")

只需确保每个屏幕都有自己的视图模型实例。此外,您可能希望将图标分配给选项卡而不是按其索引,因为当添加和删除选项卡时索引会随着时间而变化。您应该使用唯一的标识符,例如选项卡的名称。

© www.soinside.com 2019 - 2024. All rights reserved.