Your First Kotlin Android App: Polishing the App

Aug 22 2023 · Kotlin 1.8.20, Android 13, Android Studio Flamingo | 2022.2.1

Part 1: Build Out the App

03. Add Other Game Controls

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 02. Set App Orientation Next episode: 04. Display the Score

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 03. Add Other Game Controls

String resource for this episode:

Transcript: 03. Add Other Game Controls

Info Start Over Score Round


In this episode, you’ll add the remaining UI elements to complete the game screen. This is what the UI should look like at the end of this episode.

Alright let’s get started.

We’re going start off with creating a new component that’ll contain the other game controls. This is going to be contained in a new file just like we did for other components. This is a good point to split our project into packages. Packages helps us group related files together and we can access them using the package name.

For Bullseye, you can see all the files we created are in the root project directory. This structure is not scalable because it will be difficult finding specific files as the project grows. We already have one package inside our project called ui.theme and if you unfold it, it contains style related files for our app. You can see this makes sense because we dont want to mix up theme related code with our composables or activities. So android studio adds them into the ui.theme package.

At this point, we’re going to create two packages; one for the components and the other for the screens.

To create a new package, right click on the reverse domain name of the project, go to new, then select “package.” You can see the project itself is a package and we’re creating a sub package inside it. Go ahead and enter “components” as the package name. Then hit the return key. This creates the new components package.

Next, lets create the screens package. Right click on the reverse domain name of your project once again, go to new, select “package.” Enter screens as the package name. Then hit the return key. And there you have it, two new packages have been added to the project.

Next, we need to add the existing components to this package. Click on one of the components, then hold down the Cmd key, and select the rest. You can see the three(3) components are now highlighted. Finally, drag them into the components package.

Android Studio pops up the “move” dialog which helps us refactor our code by updating the places where these files are called. You can see we’re moving them from the project’s package to a subpackage inside it. Just tap the “OK” button to make the updates.

Next, do the same for the GameScreen. Just drag it into the screens package.

Cool!!! Our project now has a better structure with scalability in mind and we know how to easily find related files.

Now its time to add in the remaining game controls. You’ll put them into a new composable named GameDetail. So right click on the components package, go to new, select Kotlin Class/File, select File from the context menu, enter GameDetail as the name. Then hit return.

Next, create an empty GameDetail composable and pass in a default modifier to it like so:

@Composable
fun GameDetail(modifier: Modifier = Modifier) {

}

We also need a preview composable so that we can see what we’re building. Go ahead and add it in:

@Preview(showBackground = true)
@Composable
fun GameDetailPreview() {
  GameDetail()
}

The GameDetail component is going to have 4 widgets lined up horizontally so for this add in a Row like so:

Row(
  modifier = modifier
) {

}

We passed in the default modifier of the GameDetail composable just in case we want to customize how the Row looks from where it will be called.

After that, add in two Buttons as the children of the Row:

//...
  Button(onClick = {}) {
    Text(stringResource(R.string.start_over))
  }
  // Score Widget
  // Round Widget
  Button(onClick = {}) {
    Text(stringResource(R.string.info))
  }
//...

Do a build & refresh to see what the component looks like.

The first button will be used in the future to restart the game while the second button will be used to navigate to the about screen. You can see their text uses some string resources. Head over to strings.xml file. You can see some extra strings I’ve added to the starter project. You’ll be making use of them in this episode. Okay, let’s head back to the GameDetail file.

You can see I added two comments here. One for the score widget and the other for the game round widget. These two widgets have identical styling so instead of repeating code here, I’ll make a new reusable GameInfo widget for these.

Create this widget right below GameDetail by adding in the following code:

@Composable
fun GameInfo(label: String, value: Int = 0) {
  Column(
    horizontalAlignment = Alignment.CenterHorizontally,
    modifier = Modifier.padding(horizontal = 32.dp)
  ) {
    Text(label)
    Text(
      value.toString(),
    )
  }
}

In here, we created a new composable called GameInfo. We added two parameters, one for the label which is a String and the other for the value which is an Integer value. Then inside it, we have a Column that contains two Text composables as its children. The first Text composable will display the string label while the second one will display the Integer value. We also added some padding around the children of the Column.

Next, call it in for the score and round widgets inside GameDetail by replacing those comments like so:

GameInfo(label = stringResource(id = R.string.score_label), value = 0)
GameInfo(label = stringResource(id = R.string.current_round_label), value = 1)

We passed in the score label string and a value of 0 for the score widget and passed in the round label and 1 for the round widget. Remember, I’ve added these strings in the starter project of this episode and you can also copy them from the author notes of this episode.

The labels are currently aligned to the top. You can fix this by adding the following argument to the Row:

verticalAlignment = Alignment.CenterVertically,

Finally, lets call the GameDetail component inside the GameScreen composable. Head over to GameScreen.kt file. Scroll down to the Hit Me button.

Then call GameDetail below the Hit Me button like so:

GameDetail()

Run your app.

And you can see it in the emulator. We want it to spread across the width of the screen so add in the fillMaxWidth modifier like so:

GameDetail(modifier = Modifier.fillMaxWidth())

Then run your app.

Oops!!! What just happened? The component is now aligned to the left. To fix this, head over to the GameDetail composable. Then add in the following argument to the Row.

horizontalArrangement = Arrangement.SpaceEvenly,

This spaces the children evenly on the horizontal axis.

Run your code once again.

We now have the complete game controls for Bullseye.