为什么第一次点击Iconbutton的索引加上一个
所以我做了一个日历。我现在正在尝试使两个箭头按钮在整个几个月中跳跃。 The only problem is that everytime i click the Iconbutton the ++ doesnt do anything the first time but does something on the second... why is this can someone please help
package com.jens.svensson.jenson_calendar
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.*
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.hilt.navigation.compose.hiltViewModel
import com.jens.svensson.jenson_calendar.data.model.CalendarColors
import com.jens.svensson.jenson_calendar.ui.CalendarViewModel
import com.jens.svensson.jenson_calendar.ui.events.CalendarEvent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Composable
fun Calendar(
calendarViewModel: CalendarViewModel = hiltViewModel(),
isRoundedCorners: Boolean = false,
startMonth: Int,
calendarColor: CalendarColors,
textStyle: TextStyle,
onDissmissDialog: () -> Unit,
size: Configuration
){
val calendarYears = calendarViewModel.calendarYears
val showMenuState = calendarViewModel.dropDownMenuState.value.showDropDown
var dropDownPickedState = calendarViewModel.dropDownMenuState.value.pickedItem
val sizeHeight = size.screenHeightDp
val sizeWidth = size.screenWidthDp
val width = sizeWidth * 0.95
val height = sizeHeight * 0.95
val coroutineScope = rememberCoroutineScope()
Dialog(onDismissRequest = onDissmissDialog, properties = DialogProperties(dismissOnClickOutside = true)) {
Column(modifier = Modifier
.size(width = width.dp, height = height.dp)
.padding(15.dp)
.background(
calendarColor.calendarColor,
shape = if (isRoundedCorners) RoundedCornerShape(10) else RectangleShape
)) {
Header(isRoundedCorners = isRoundedCorners, color = calendarColor.headerColor)
Row(
modifier = Modifier
.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(start = 22.dp)
) {
Row(Modifier.clickable { calendarViewModel.onEvent(CalendarEvent.ShowDropDown(!showMenuState)) }) {
Text(
text = calendarViewModel.standardMonths[calendarViewModel.dropDownMenuState.value.pickedItem],
style = MaterialTheme.typography.h6,
color = calendarColor.mainCalendarTextColor
)
Icon(
imageVector = Icons.Default.ArrowDropDown,
contentDescription = "Month dropdown arrow",
tint = calendarColor.mainCalendarTextColor
)
}
DropdownMenu(
expanded = showMenuState,
onDismissRequest = { calendarViewModel.onEvent(CalendarEvent.ShowDropDown(!showMenuState)) }) {
calendarViewModel.standardMonths.forEachIndexed { index, month ->
DropdownMenuItem(onClick = { calendarViewModel.onEvent(CalendarEvent.ClickedMenuItem(index))
}) {
Row() {
Text(text = month, style = MaterialTheme.typography.h6)
}
}
}
}
}
IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = {}) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Go back one month arrow",
tint = calendarColor.mainCalendarTextColor
)
}
IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = {
calendarViewModel.onEvent(CalendarEvent.ClickedMenuItem(dropDownPickedState++))
}) {
Icon(
imageVector = Icons.Default.ArrowForward,
contentDescription = "Go forward one month arrow",
tint = calendarColor.mainCalendarTextColor
)
}
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
calendarViewModel.datesList.forEach {
Text(text = it, color = calendarColor.mainCalendarTextColor)
}
}
LazyRow(state = calendarViewModel.listState, modifier = Modifier.fillMaxWidth()) {
calendarYears.forEach {
items(it.months.count()) { index ->
CalendarRowItem(
modifier = Modifier.fillParentMaxWidth(),
calendarSize = it.months[index].amountOfDays,
initWeekday = it.months[index].startDayOfMonth.ordinal,
textColor = MaterialTheme.colors.secondaryVariant,
clickedColor = MaterialTheme.colors.primary,
textStyle = MaterialTheme.typography.body1
)
}
}
}
DisposableEffect(Unit) {
coroutineScope.launch {
calendarViewModel.listState.scrollToItem(calendarViewModel.currentMonth)
}
onDispose { }
}
CalendarButtonSection()
}
}
}
calendarViewModel
package com.jens.svensson.jenson_calendar.ui
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.jens.svensson.jenson_calendar.data.model.CalendarMonth
import com.jens.svensson.jenson_calendar.data.model.CalendarYear
import com.jens.svensson.jenson_calendar.data.model.YearMonths
import com.jens.svensson.jenson_calendar.domain.repository.CalendarInterface
import com.jens.svensson.jenson_calendar.ui.events.CalendarEvent
import com.jens.svensson.jenson_calendar.ui.state.DropDownMenuState
import dagger.hilt.android.lifecycle.HiltViewModel
import java.time.Month
import java.util.*
import javax.inject.Inject
@HiltViewModel
class CalendarViewModel @Inject constructor(private val repository: CalendarInterface): ViewModel() {
val datesList: List<String> = repository.getShortenedWeekDays()
val calendarYears: List<CalendarYear> = repository.createAndReturnYears()
val standardMonths: List<String> = repository.getStandardMonths()
val listState = LazyListState()
val currentMonth: Int = Calendar.getInstance().get(Calendar.MONTH)
private val _dropdownMenuState = mutableStateOf(DropDownMenuState())
val dropDownMenuState: State<DropDownMenuState> = _dropdownMenuState
init {
_dropdownMenuState.value = dropDownMenuState.value.copy(pickedItem = currentMonth)
}
fun onEvent(event: CalendarEvent){
when(event){
is CalendarEvent.ShowDropDown -> _dropdownMenuState.value = dropDownMenuState.value.copy(showDropDown = event.value)
is CalendarEvent.ClickedMenuItem -> {
_dropdownMenuState.value = _dropdownMenuState.value.copy(pickedItem = event.value)
}
}
}
fun getCalendarMonths(yearIndex: Int): List<CalendarMonth>{
return calendarYears[yearIndex].months
}
}
New viewmodel
package com.jens.svensson.jenson_calendar.ui
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.jens.svensson.jenson_calendar.data.model.CalendarMonth
import com.jens.svensson.jenson_calendar.data.model.CalendarYear
import com.jens.svensson.jenson_calendar.data.model.YearMonths
import com.jens.svensson.jenson_calendar.domain.repository.CalendarInterface
import com.jens.svensson.jenson_calendar.ui.events.CalendarEvent
import com.jens.svensson.jenson_calendar.ui.state.DropDownMenuState
import dagger.hilt.android.lifecycle.HiltViewModel
import java.time.Month
import java.util.*
import javax.inject.Inject
@HiltViewModel
class CalendarViewModel @Inject constructor(private val repository: CalendarInterface): ViewModel() {
val datesList: List<String> = repository.getShortenedWeekDays()
val calendarYears: List<CalendarYear> = repository.createAndReturnYears()
val standardMonths: List<String> = repository.getStandardMonths()
val listState = LazyListState()
val currentMonth: Int = Calendar.getInstance().get(Calendar.MONTH)
private var datePickedState: Int = 0
private val _dropdownMenuState = mutableStateOf(DropDownMenuState())
val dropDownMenuState: State<DropDownMenuState> = _dropdownMenuState
init {
_dropdownMenuState.value = dropDownMenuState.value.copy(pickedItem = currentMonth)
}
fun onEvent(event: CalendarEvent){
when(event){
is CalendarEvent.ShowDropDown -> _dropdownMenuState.value = dropDownMenuState.value.copy(showDropDown = event.value)
is CalendarEvent.ClickedMenuItem -> {
_dropdownMenuState.value = _dropdownMenuState.value.copy(pickedItem = event.value)
}
is CalendarEvent.NextMonth -> nextMonth()
is CalendarEvent.PreviousMonth -> previousMonth()
}
}
fun nextMonth(){
datePickedState = _dropdownMenuState.value.pickedItem
if(datePickedState == 11){
datePickedState = 0
}else{
_dropdownMenuState.value = _dropdownMenuState.value.copy(pickedItem = ++datePickedState)
}
}
fun previousMonth(){
datePickedState = _dropdownMenuState.value.pickedItem
if(datePickedState == 0){
datePickedState == 11
}else{
_dropdownMenuState.value = dropDownMenuState.value.copy(pickedItem = --datePickedState)
}
}
fun getCalendarMonths(yearIndex: Int): List<CalendarMonth>{
return calendarYears[yearIndex].months
}
}
The buttons
IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = {calendarViewModel.onEvent(CalendarEvent.PreviousMonth)}) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Go back one month arrow",
tint = calendarColor.mainCalendarTextColor
)
}
IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = {
calendarViewModel.onEvent(CalendarEvent.NextMonth)
}) {
Icon(
imageVector = Icons.Default.ArrowForward,
contentDescription = "Go forward one month arrow",
tint = calendarColor.mainCalendarTextColor
)
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一个问题是
i ++
在增加之前将当前的i
值传递给计算,因此您将相同的旧值传递给OneVent
。您可以在 ++ i ,它将在计算中使用该值之前增加该值。但是这是第二个问题。这一行:
创建一个局部变量,而这些变量并未在重组之间保存。因此,您第一次单击时,您会增加本地值,但将旧值传递给
OneVent
,这不会导致重新分配。第二次单击 - 先前增加的值将传递给您的视图模型,该模型会触发重新分配,并重置您的下拉列表。
为了防止此类错误,请勿在撰写视图中使用
var
,除非您将其与状态委托使用,例如:One problem is that
i++
passes the currenti
value to the calculation before increasing, so you pass the same old value toonEvent
. You can find more details in this answer - it's about C, but inc/dec operators work the same in all languages they exists. You could've used++i
, which will increase the value before using it in the calculations.But here comes the second problem. This line:
creates a local variable, and those are not saved between recompositions. So the first time you click, you're increasing the local value, but pass the old value to
onEvent
, which doesn't cause recomposition.The second time you click - previously increased value gets passed to your view model, which triggers recomposition, and resets your dropDownPickedState.
To prevent such errors don't use
var
in Compose views, unless you're using it with state delegation, e.g.: