我必须创建动态 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")
}
}
}
}
只需将
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")
只需确保每个屏幕都有自己的视图模型实例。此外,您可能希望将图标分配给选项卡而不是按其索引,因为当添加和删除选项卡时索引会随着时间而变化。您应该使用唯一的标识符,例如选项卡的名称。