Getting started with jetpack compose – Basic components

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

To learn more about the jetpack compose internals, Please check the official documents. In this post, I am focusing on creating material components using jetpack compose.

Jetpack compose official page

Jetpack compose tutorial by android developers


If you’re new to Compose, I highly recommend going through the following articles:

Getting started with jetpack compose – Modifiers

Getting started with jetpack compose – Layouts

Getting started with jetpack compose – ConstraintLayout

Getting started with jetpack compose – Scaffold layout

Getting started with jetpack compose – Theming


Also, check out the video from android developers.

jetpack compose

Setup jetpack compose on android studio

Method 1 – Creating new Jetpack compose Project

Create jetpack compose project

Create New Project by selecting “Empty Compose Activity“, It will add all the Gradle dependencies in the Gradle file and MainAcitivity to accept composable. So, straightaway we can start working on the project.

Method 2 – Migrate Existing Android Studio Project

Add jetpack compose version in the project build.gradle file.

buildscript {
    ext {
        compose_version = '1.0.0'
    }
    ...
}

Then, add the build features and compose options in your module-level build.gradle file.

compileOptions {
        sourceCompatibility "1.8"
        targetCompatibility "1.8"
    }
    kotlinOptions {
        jvmTarget = '1.8'
        useIR = true
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
        kotlinCompilerVersion '1.5.10'
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }

The next step is to add the jetpack compose dependencies in the gradle file.

    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.activity:activity-compose:1.3.1'
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"

Finally, change your MainAcitivity.kt to extends ComponentActivity. Also, add the setContent to accept the composable content on oncreate().

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
        }
    }
}

Ok. setup Is completed. The next step is to create compose components.

Before getting started into jetpack components, you should know about the layouts, Modifiers, and mutablestate in kotlin compose. Please check the below links for your references.

Layouts in Compose

State and Jetpack Compose

Compose modifiers

Jetpack compose components

Text

Text is a central piece of any UI, and Jetpack Compose makes it easier to display or write text. 

Displaying text

@Composable
fun SimpleText() {
    Text(text = "Hello World!")
}
text

Reading text from resource

@Composable
fun SimpleText() {
    Text(text = stringResource(R.string.hello_world))
}

Changing the text color

@Composable
fun SimpleText() {
    Text(text = stringResource(R.string.hello_world), color = Color.Blue)
}

Changing the font size / font weight / font Family / font style

       Text(text = stringResource(R.string.hello_world), fontSize = 20.sp)
        Text(text = stringResource(R.string.hello_world), fontSize = 20.sp, fontWeight = FontWeight.Bold)
        Text(text = stringResource(R.string.hello_world), fontSize = 20.sp, fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic)
        Text(text = stringResource(R.string.hello_world), fontSize = 20.sp, fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic , fontFamily = FontFamily.Monospace)
text style

Multiple styles in a text

@Composable
fun DisplayAnnotatedString() {
    val context = LocalContext.current
    Text(buildAnnotatedString {
        withStyle(style = SpanStyle(color = Color.Gray)) {
            append("Text")
        }
        append(" Jetpack")

        withStyle(style = SpanStyle(color = Color.Red, fontFamily = FontFamily.Monospace)) {
            append(" compose")
        }
    })
}
Span text

Text Field

TextField allows users to enter and modify text.

@Composable
fun DisplayTextField() {
    var name by remember {
        mutableStateOf("")
    }
    TextField(value = name, onValueChange = { it ->
        name = it
    }, label = { Text(text = "Username") })
}
textfield

Outlined TextField

@Composable
fun DisplayOutlinedTextField() {
    var name by remember {
        mutableStateOf("")
    }
    OutlinedTextField(value = name, onValueChange = { it ->
        name = it
    }, label = { Text(text = "Username") })
}
outlined textfield

Styling TextField

  • singleLine
  • maxLines
  • textStyle
@Composable
fun DisplayTextField() {
    var name by remember {
        mutableStateOf("")
    }
    TextField(value = name, onValueChange = { it ->
        name = it
    }, label = { Text(text = "Username", style = TextStyle(fontSize = 18.sp)) },
    maxLines = 1, modifier = Modifier.padding(8.dp),
    textStyle = TextStyle(color = Color.Red, fontFamily = FontFamily.Monospace))
}

Keyboard options

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction
fun DisplayTextField() {
    var password by remember {
        mutableStateOf("Hello")
    }

    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("Enter password") },
        visualTransformation = PasswordVisualTransformation(),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
    )
}

Button

A Button has an onClick-Function. You can add a Text-Composable or any other Composables as child elements of the Button.

@Composable
fun DisplayPrimaryButton() {
    val context = LocalContext.current
    Button(onClick = {
        Toast.makeText(context, "Primary Button clicked", Toast.LENGTH_SHORT).show()
    }, Modifier.padding(4.dp)) {
        Text(
            text = "Primary Button")
    }
}
button

Outlined Button

@Composable
fun DisplayOutlinedButton() {
    val context = LocalContext.current
    OutlinedButton(onClick = { Toast.makeText(context, "Outlined Button clicked", 
        Toast.LENGTH_SHORT).show()
    }, Modifier.padding(4.dp)) {
        Text(
            text = "Outlined Button"
        )
    }
}
outlined button

Styling Button

@Composable
fun DisplayPrimaryButton() {
    val context = LocalContext.current
    Button(onClick = {
        Toast.makeText(context, "Primary Button clicked", Toast.LENGTH_SHORT).show()
    }, Modifier.padding(4.dp)) {
        Text(
            text = "Primary Button",
            style = TextStyle(fontSize = 22.sp,fontFamily = FontFamily.Monospace, fontWeight = FontWeight.Bold)
        )
    }
}
Button style

Checkbox

@Composable
fun DisplayCheckBox() {
    var checkStatus by remember {
        mutableStateOf(false)
    }
    Row {
        Checkbox(checked = checkStatus, onCheckedChange = {
            checkStatus = it
        })

        Text(text = "Checkbox", Modifier.clickable { checkStatus = !checkStatus })
    }
}
Checkbox

Radio Button

@Composable
fun DisplayRadioButton() {
    val cities = listOf("Chennai", "Mumbai", "Pune")
    val (selected, onOptionSelected) = remember {
        mutableStateOf(cities[0])
    }
    Column(Modifier.padding(4.dp)) {
        cities.forEach { text ->
            Row(modifier = Modifier.padding(4.dp)) {
                RadioButton(selected = selected == text, onClick = {
                    onOptionSelected(text)
                })
                Text(text = text, Modifier.clickable { onOptionSelected(text) })
            }
        }
    }
}
Radio button

Switch

@Composable
fun DisplaySwitch() {
    val context = LocalContext.current
    var switchStatus by remember {
        mutableStateOf(false)
    }
    Row(Modifier.padding(8.dp)) {
        Text(text = "Light on/off")
        Switch(checked = switchStatus, onCheckedChange = {
            switchStatus = it
            Toast.makeText(context, "Light ${if (it) "on" else "off"}", Toast.LENGTH_SHORT).show() })
    }
}
Switch

Surface

The surface is like a view in android. So can add background color, shape, elevation, and border, etc.

@ExperimentalMaterialApi
@Composable
fun DisplaySurface() {
    val context = LocalContext.current
    Surface(shape = RoundedCornerShape(8.dp), elevation = 8.dp, onClick = {
        Toast.makeText(
            context,
            "Surface clicked",
            Toast.LENGTH_SHORT
        ).show()},border = BorderStroke(2.dp, Color.Blue), modifier = Modifier.padding(8.dp).width(100.dp)) {
        Text(text = "Surface",Modifier.padding(8.dp), textAlign = TextAlign.Center)
    }
}
Surface

Circular Progress Indicator

A CircularProgressIndicator can be used to display progress in a circular shape.

Indeterminate

When you use the CircularProgressIndicator without the progress parameter, it will run forever.

@Composable
fun DisplayCircularProgressBar() {
        CircularProgressIndicator(strokeWidth = 8.dp, color = Color.Gray, modifier = Modifier.padding(4.dp))
}

Determinate

When you set a value to the progress parameter, the indicator will be shown with that progress.

@Composable
fun DisplayCircularProgressBar() {
        CircularProgressIndicator(progress = 0.5f, strokeWidth = 8.dp, color = Color.Gray, modifier = Modifier.padding(4.dp))
}
Circular progressbar

Linear Progress Indicator

A LinearProgressIndicator can be used to display progress in a linear line, also known as a progress bar.

Indeterminate

When you use the LinearProgressIndicator without the progress parameter.

@Composable
fun DisplayLinearProgressBar() {
    LinearProgressIndicator(backgroundColor = Color.Blue, color = Color.Black, modifier = Modifier.padding(4.dp))
}

Determinate

When you set a value to the progress parameter, the indicator will be shown with that progress.

@Composable
fun DisplayLinearProgressBar() {
    LinearProgressIndicator(progress = 0.5f, backgroundColor = Color.Blue, color = Color.Black, modifier = Modifier.padding(4.dp))
}
Linear progressbar

Slider

Sliders allow users to make selections from a range of values.

@Composable
fun DisplaySlider() {
    Spacer(modifier = Modifier.padding(4.dp))
    var sliderValue by remember {
        mutableStateOf(10.0f)
    }
    Text(text = sliderValue.toInt().toString(), modifier = Modifier.fillMaxWidth(),textAlign = TextAlign.Center)
    Slider(value = sliderValue, onValueChange = {sliderValue = it}, valueRange = 0f..100f)
}
Slider

Slider with steps

@Composable
fun DisplaySliderWithStepper() {
    var sliderValue by remember {
        mutableStateOf(25.0f)
    }
    Text(text = sliderValue.toInt().toString(), modifier = Modifier.fillMaxWidth(),textAlign = TextAlign.Center)
    Slider(value = sliderValue, onValueChange = {sliderValue = it}, steps = 3, valueRange = 0f..100f)
}
Slider with steps

Spacer

The spacer component is used to display an empty space. Width and (or) height can be set for Spacer using Modifier object.

@Composable
fun DisplaySpacer() {
    Spacer(modifier = Modifier
        .padding(8.dp)
        .height(40.dp)
        .fillMaxWidth()
        .background(Color.Gray))
}
Spacer

Thanks for reading. Also, you can download this example from GITHUB.

If you like this post, you can follow me on

Facebook

Twitter

Medium

Leave a Reply

Your email address will not be published. Required fields are marked *