Compose Unstyled

Progress Indicator

A progress indicator component for determinate and indeterminate loading states.

View Markdown
ProgressIndicatorDemo.kt
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.composeunstyled.Indicator
import com.composeunstyled.UnstyledProgress
import com.composeunstyled.demo.borderToken
import com.composeunstyled.demo.colors
import com.composeunstyled.demo.contentToken
import com.composeunstyled.demo.surfaceToken
import com.composeunstyled.theme.Theme
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.milliseconds

@Preview
@Composable
fun ProgressIndicatorDemo() {
  var hasProgressed by remember { mutableStateOf(false) }
  val pillShape = RoundedCornerShape(100)

  val progress by animateFloatAsState(
    targetValue = if (hasProgressed) 0.85f else 0.2f,
    animationSpec = tween(durationMillis = 450),
  )
  LaunchedEffect(Unit) {
    delay(500.milliseconds)
    hasProgressed = true
  }

  Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center,
  ) {
    UnstyledProgress(
      progress = progress,
      modifier = Modifier
        .width(400.dp)
        .height(12.dp)
        .clip(pillShape)
        .background(Theme[colors][surfaceToken], pillShape)
        .border(1.dp, Theme[colors][borderToken], pillShape),
    ) {
      Indicator(Modifier.background(Theme[colors][contentToken], pillShape))
    }
  }
}

Installation

implementation("com.composables:composeunstyled-progress:2.9.2")

Anatomy

UnstyledProgress(progress = progress) {
  Indicator()
}

Concepts

  • UnstyledProgress() represents the visible bounds of the progress including the track.
  • Indicator fills the available width by the current progress value.

Accessibility

UnstyledProgress applies the appropriate accessibility semantics based on whether the progress parameter is provided.

Code Examples

Creating a determinate progress indicator

Use the progress parameter when the current progress value is known:

UnstyledProgress(progress = 0.4f) {
  Indicator()
}

Creating an indeterminate progress indicator

Use the overload without the progress parameter when the current progress value is unknown:

UnstyledProgress {
  BasicText("Loading")
}

Drawing a custom indicator

Use the ProgressScope.progress property when the indicator needs custom measurement:

UnstyledProgress(progress = progress) {
  Box(Modifier.fillMaxWidth(progress))
}

API Reference

UnstyledProgress

Parameter Type Description
progress Float
modifier Modifier Modifier to be applied to the progress container.
content ProgressScope.() -> Unit A composable function that defines the content of the progress indicator.
content () -> Unit

ProgressScope

Parameter Type Description
progress Float

ProgressScope.Indicator

Parameter Type Description
modifier Modifier Modifier to apply to the filled progress content.