Introduction to Kotlin and Android Development

Nav Bar Buttons & State

Maximiliano Firtman

Maximiliano Firtman

Independent Consultant
Introduction to Kotlin and Android Development

Check out a free preview of the full Introduction to Kotlin and Android Development course

The "Nav Bar Buttons & State" Lesson is part of the full, Introduction to Kotlin and Android Development course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano demonstrates rendering each navbar item, implementing state, and updating the navigation icon colors when selected. Styling the bottom nav bar with proper padding, background color, and font is also covered in this segment.


Transcript from the "Nav Bar Buttons & State" Lesson

>> Okay, so this is one item, now we need for the NavBar all the items, okay? So, let's do that. So, I'm going to create a preview, composable, I'm going to call that NavBar. And for that, well, I'm going to use a row, y row. Because, I want them horizontally, okay?

So, it's a row. Inside the row, I'm going to use a for. Can I do a for? Yeah, okay. For each page in Routes.pages, and what is that? The array, the list I created before. So, I'm going to loop through all these pages that each has something that I have just created.

And I'm going to render one nav item per page. Does it makes sense? So, here I'm going to render one NavBar item. Which page? The current page, okay? I will need the argument name, if it's the same, maybe it's up to you, if you want to keep it, it's fine.

It's not a problem and then if it's selected or not. So, I can just say, well let's not add the selected for now, we can add that later. So, we have NavBar right down, and I think for now should be good enough to render bar. Look at that at the bottom, it seems fine, right?

So, I'm just looping through and rendering these items. But I need to behavior as well. So, I need to click on each item and somehow change content. We don't have any automatic behavior on checkbox on both. So, we need to do this manually, but it's not so complicated.

So, one simple way is that maybe we can receive here, what is the selected route, but it's just a string. And we can save that by default, we start with a menu page. Okay? So, with that in mind, I can say selected, anyway selected is a Boolean number we're seeing here is equals to, if the route is equals to the current route that I'm actually rendering.

So, let me do things like like this. So, I'm rendering each item and I'm verifying if the current one is the selected one, and we're going to receive that from the outside, okay? Make sense? Now the preview is broken again. Why? Because I need to pass arguments. Okay.

So, it may have problems later. But remember that we can create our own composable shots for preview, okay? So, now that I'm here, what's next? I need to click on items. So how does that work? We can apply a modifier, this is the first time we are doing a click, okay?

So, it's through modifiers and the modifier is known as clickable. Is not on click is not using the on prefix, clickable. And here we do something What do I need to do? If you click here.
>> As a function?
>> Yeah, so first I need to change the section that's kind of the deal.

But if we are receiving the route from the outside selected route, it feels like the source of truth for the carbon route is not here, it's not in a number. It's somewhere top in the composition, maybe in the app, the app knows where you are. So, in that case, as you mentioned, we might wanna receive a callback function, okay?

So, how would you create a callback if just lambda expression. On change, changeable q1. And what's the type? It's a function that receives what? A route, maybe. [INAUDIBLE] That's the name of our and returns nothing. Does anyone remember the boys type in Kotlin for Android? Unit.
>> Unit yeah.

>> Unit, so meaning that if it's clickable I'm going to call on change passing as an argument that the current route somehow, okay? For example, I can only pass a string maybe it's faster instead of passing the whole page, shorter route. I think that will be faster. So, now the preview is broken, which is expectable, okay?

At this point. Why? Because it needs unknown change. It seems complicated, okay? Which is okay. You can delete the preview if you want. If you're happy with that, you can just delete the preview of the NavBar and just keep the preview that you want a preview. You don't need to preview everything.

You're not forced mentally to preview anything, okay? Or all the things that you have, pick your home previews. Okay. So, any question? You might have right now? No? The next part is to actually go to the app and apply that to the bottom bar. So to the bottom bar, I don't want text.

I want to apply the navbar that I have just created and I need to pass something in the unchanged event. And that's the closure, a lambda expression. Makes sense? So, when the NavBar changes we're going to receive here in it. What's it? The route that the user is clicking on it, okay?

So, now here comes the part when we need to set the state of the app. So, the current selected items, selected tab, selected page, call it however you want. It's actually in a state of the app because it's changing and I need to re-render the content every time the user is changing the current selection.

Does it make sense? So that means that I need a variable of type of state. So, it's the current you can call it however you want, the current index, current element, current page, current route, selected route, something like that. And we need to call, remember it's always the same, we're going to remember a mutable state of a string.

And we are going to start with, for example, the menu. Now it was routes.menuPage.route. So we start with that one. That's the initial state. And when it's changing, it's actually changing. So, like the route, the new value is it. If you don't like it remember we can change that like the new route.

We can call it new route. Does it make more sense with new route than it? So, we are changing the state. What I'm missing here is that NavBar receives an option I'll select the route. That is the value that I'm just mutating. This is called state hosting. A state hosting is when you have a composable that receives one variable and since also the value change through a lambda expression.

This is called a state hosting. We're saving the state, not here in the number, but one level up. This is state hoisting. In fact, the text field is actually using this technique. When we're setting the text field we also have the same idea. So, let's see what happens.

First, I can try to see what's going on here. Well, if you look at the bottom, we have something there, it's still a little weird, okay? So, you can see there in terms of the background, and all that thing. So, let's run this on a real phone. Look at the bottom.

Yes, kind of, we need to add some more things but it has to do with the UI. what do we need, to do two things. First, change the background color and also maybe stretch that number to the whole width. So where? In the NavBar. Make sense? So, in the NavBar in this row, I'm going to apply some modifiers.

So modifier equals to, for example changing the background color to primary. We can take it from the material theme, the primary is actually the one that defines also the top bar Colors primary. That's one modifier. And the other one it's fillMaxWidth. Because I want the whole row to take the whole width that we're having in the space.

>> The images won't get stretched now.
>> Sorry, what?
>> The images won't get stretched
>> If it's an image, you can change the aspect ratio that you wanna use. If you remember we did that on, offers page. When we were putting an image here, we change the content scale.

So, here you can change, how do you want that image to be stretch. If fill or crop, okay? So, you just change this property with all the enum values that you have available.
>> Okay, do you have padding in between them and just do we have padding to be able to be stretched?.

>> You have padding in everything. [FOREIGN]
>> So any mesh is a composable.
>> So forget about the emesh as the file. It's a composable that renders on the machine side, okay? Makes sense? Cool. Well let's see, if I run this now look at the bottom. We're still missing some parts, right?

So, what do we need, I mean it's better than before, but it's still not what I was expecting, okay? So, I need more paddings and also it's not actually stretching. So, we need to find which one are we missing. Let's see. So, let's go to bottom navigation, like here, let me go to code only.

So, this is a row. Okay, the row is filling the max width, but we might have a problem here. So, it's okay. We are filling the max width, but the row is just putting all the elements one after the other. It's not aligning the elements along the row.

Does it make sense? So we need to change more properties. One of the properties that we can change is horizontal. So there are many properties. Okay, that [INAUDIBLE]. Unfortunately, sometimes the IDE is not showing you all the properties. And when you look at the autocomplete, sometimes it's giving you even more properties that the ones that you can use.

And if you pick one of these, these are not actually from Jetpack compose. So, be careful because not everything that appears here is what you want. You can also get into the row and try to see there there, for example, we have a horizontal arrangement. Remember you enter with ctrl click.

And you get into that function and you see the properties, in case the IV is not helping. So and in this case, arrangement can be, for example, in space around the space even in space between. And if we do this, we're missing the parenthesis? Now, I'm asking the row to actually put the spaces between elements so they can fit on the screen.

And also between we can use a space around that also add spaces at both pages, okay? And also in the middle. So, you can play with this value. And just because I'm here maybe I want the padding as well for the whole row that renders the icons, okay?

And it's like what's going on, how to solve the problem? So what's the problem we have?
>> On the bottom padding. [LAUGH]
>> Well, the padding, should be moved up.
>> The padding should we moved up or the background or down? So, I'm applying the padding and then the background color.

But if I swap the order, background first, padding later. Okay, it looks better. We're still happy with the selection. But it seems like I'm not seeing any different background color, okay? That's what I'm saying. But the rest looks fine. Wanna change the route value, look the route, everything seems perfectly fine.

So, we'll go with a clean RStudio wants to update, I don't wanna update. So, I push the codes on GitHub, you have my latest code. Let's run it to see if my NavBar is actually interactive. So you can see it's working. Maybe I wanna swap the colors. I don't think I like how they colors looks like right now.

So, for that, let's go to bottom navigation Kotlin. And here, when we are saying in the NavBar item, if selected, I'm going to swap this color. Of course, you can play with these colors as much as you like. We have one primary and alternative one. So if I run this again, now it looks better.

So, the next step is to actually change the main contents based on the current tab, the current selected item. For that, we're going to do that something in app. Right now the content in app is actually always offers pages. So, the app now has to select a route.

So, what if we apply here when, do you remember the when? The when is like the switch. So, I'm going to say when, the select the route value is, for example, offers or I can take it from the routes.OffersPage.route. I'm going to render offers page. So we use arrow.

And what do we wanna render, like this.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now