Omico/androidx-compose-material3-pullrefresh

Compose Material3 1.2.0 release version is very poor

Closed this issue · 7 comments

fun PullToRefreshSample() {
    var itemCount by remember { mutableStateOf(15) }
    val state = rememberPullToRefreshState()
    if (state.isRefreshing) {
        LaunchedEffect(true) {
            // fetch something
            delay(1500)
            itemCount += 5
            state.endRefresh()
        }
    }
    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
        LazyColumn(Modifier.fillMaxSize()) {
            if (!state.isRefreshing) {
                items(itemCount) {
                    ListItem({ Text(text = "Item ${itemCount - it}") })
                }
            }
        }
        PullToRefreshContainer(
            modifier = Modifier.align(Alignment.TopCenter),
            state = state,
        )
    }
}

The display of the refresh header and the triggering of the refresh operation are very difficult to control.

I still choose to use your library

fun PullToRefreshSample() {
    var itemCount by remember { mutableStateOf(15) }
    val state = rememberPullToRefreshState()
    if (state.isRefreshing) {
        LaunchedEffect(true) {
            // fetch something
            delay(1500)
            itemCount += 5
            state.endRefresh()
        }
    }
    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
        LazyColumn(Modifier.fillMaxSize()) {
            if (!state.isRefreshing) {
                items(itemCount) {
                    ListItem({ Text(text = "Item ${itemCount - it}") })
                }
            }
        }
        PullToRefreshContainer(
            modifier = Modifier.align(Alignment.TopCenter),
            state = state,
        )
    }
}

The display of the refresh header and the triggering of the refresh operation are very difficult to control.

I still choose to use your library

Because pullToRefreshState cannot be directly controlled in viewmodel

You can use state.startRefresh() to trigger it directly.

You don't understand me. The old version of PullToRefresh triggered refresh through the onRefresh callback, but now it uses state.isRefreshing. That is to say, the current version of state.isRefreshing not only indicates whether the current UI displays the refresh key state, but also indicates that the refresh action is to be triggered.

Two versions of the API are used below to implement the same function:

old example:

@Composable
fun Example() {
    val viewModel = remember {
        ViewModel().also {
            val needAutoRefresh = true // If needed
            if (needAutoRefresh) {
                it.refresh()
            }
        }
    }
    val state = rememberPullRefreshState(refreshing = viewModel.isLoading, onRefresh = {
        viewModel.refresh()
    })
    Box {
        Column {
            Text(text = viewModel.text)
            Button(onClick = {
                viewModel.refresh()
            }) {
                Text(text = "refresh")
            }
        }

        PullRefreshIndicator(
            refreshing = viewModel.isLoading,
            state = state,
            modifier = Modifier.align(Alignment.TopCenter),
        )
    }
}

class ViewModel {

    var isLoading by mutableStateOf(false)

    var text by mutableStateOf("")

    fun refresh() {
        isLoading = true
        viewModelScope.launch {
            // fetch something
            delay(1500)
            text = "hello"
            isLoading = false
        }
    }
}

new example:

@Composable
fun Example() {

    val state = rememberPullToRefreshState()

    val viewModel = remember {
        ViewModel().also {
            val needAutoRefresh = true // If needed
            if (needAutoRefresh) {
                state.startRefresh()
            }
        }
    }

    if (state.isRefreshing) {
        LaunchedEffect(true) {
            viewModel.refresh(state)
        }
    }

    Box {
        Column {
            Text(text = viewModel.text)
            Button(onClick = {
                state.startRefresh()
            }) {
                Text(text = "refresh")
            }
        }

        PullToRefreshContainer(
            modifier = Modifier.align(Alignment.TopCenter),
            state = state,
        )
    }
}

class ViewModel {

    var text by mutableStateOf("")

    fun refresh(state: PullToRefreshState) {
        viewModelScope.launch {
            // fetch something
            delay(1500)
            text = "hello"
            state.endRefresh()
        }
    }
}

I think the old version is better than the new version. The API and isLoading status of the new version must only be controlled through PullRefreshState and cannot be uniformly placed in viewModel

See 04e019d

I hope this is what you are struggling with.

By the way, I'm not working for Google.
If there is some issue that you feel uncomfortable with Jetpack Compose Material.
You should send an issue to Google via https://issuetracker.google.com/issues/new?component=742043&template=1590761

See 04e019d

I hope this is what you are struggling with.

By the way, I'm not working for Google. If there is some issue that you feel uncomfortable with Jetpack Compose Material. You should send an issue to Google via https://issuetracker.google.com/issues/new?component=742043&template=1590761

Thank you, you are very enthusiastic

发现你是国人,😄

I support that in the new implementation from Google it is very difficult to control the state of the indicator, because they themselves violate their Jetpack Compose ideologies .
The idea with andRefreshing/ startRefreshing seems to be bad, because it is very difficult to make it compatible with VIewModel. Previous implementation seems to be more intelligently designed