为什么索引不加一个在第一次点击图标按钮



所以我做了一个日历。我现在正在尝试让两个箭头按钮在月份之间跳跃。唯一的问题是,每次我点击图标按钮++不做任何事情的第一次,但做了一些在第二次…这是为什么?有人能帮帮我吗?

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

的按钮
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
    )
}

一个问题是i++在增加之前将当前i的值传递给计算,因此您将相同的旧值传递给onEvent。你可以在这个答案中找到更多的细节——它是关于C的,但是inc/dec运算符在所有存在的语言中都是一样的。您可以使用++i,它将在计算中使用它之前增加值。

但是第二个问题来了。这条线:

var dropDownPickedState = calendarViewModel.dropDownMenuState.value.pickedItem

创建了一个局部变量,这些变量不会在重组之间保存。所以你第一次点击,你增加了本地值,但将旧值传递给onEvent,这不会导致重组。

第二次点击-先前增加的值被传递到视图模型,触发重组,并重置你的dropdownpickstate。

为了防止这样的错误,不要在组合视图中使用var,除非你使用状态委托,例如:

var item by viewModel.stateValue  // is ok
var item = viewModel.stateValue.value // is not ok

相关内容

最新更新