4

Basically, I have two composable funcs which create a TopAppBar and add a tab layout contained in the app bar :

@Composable
fun ZCryptAppBar(
    modifier: Modifier = Modifier,
    title: @Composable RowScope.() -> Unit
) {
    Column(Modifier.fillMaxWidth()) {
        TopAppBar(
            title = {
                Column {
                    Row { title() }
                    Row {
                        TabLayout()
                    }
                }
            },
            modifier = modifier,
            backgroundColor = MaterialTheme.colors.primary,
            contentColor = Color.White
        )
    }
}

@Composable
fun TabLayout() {
    var selectedTab by remember {
        mutableStateOf(0)
    }
    TabRow(
        modifier = Modifier.fillMaxWidth(),
        selectedTabIndex = selectedTab,
        backgroundColor = MaterialTheme.colors.primary,
        tabs = {
            Tab(
                selected = selectedTab == 0,
                onClick = { selectedTab = 0 },
                text = { Text(stringResource(R.string.encrypt)) },
                icon = {
                    Image(
                        painterResource(id = R.drawable.ic_padlock_black),
                        stringResource(R.string.descr_icon_padlock)
                    )
                }
            )
            Tab(
                selected = selectedTab == 0,
                onClick = { selectedTab = 0 },
                text = { Text(stringResource(R.string.decrypt)) },
                icon = {
                    Image(
                        painterResource(id = R.drawable.ic_padunlock_black),
                        stringResource(R.string.descr_icon_padunlock)
                    )
                }
            )
        }
    )
}

But I am having two problems here : firstly, when I click on a tab, nothing happens and app stays in the same tab.

Secondly, the TopAppBar seems to not automatically adjust its height since the tab name and icon are all cropped :

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
ScarySneer
  • 199
  • 3
  • 9

2 Answers2

4

The TopAppBar implements the Material design specs and has a fixed height of 56.dp.

You can use:

Column(Modifier.fillMaxWidth()) {
    TopAppBar(
        title = {
            Column() {
                Row { Text("Title") }
            }
        },
        backgroundColor = MaterialTheme.colors.primary,
        contentColor = Color.White
    )
    TabLayout()
}

Then in your TabLayout use:

       Tab(
            selected = selectedTab == 0,
            onClick = { selectedTab = 0 },
            //.....
        )
        Tab(
            selected = selectedTab == 1,
            onClick = { selectedTab = 1 },
            //.....
        )

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • Oh thank you it worked. Where is it said that TopAppBar height is fixed ? I didn't see this in the docs I would turn it into a suggestion for Google – ScarySneer Jun 17 '21 at 20:12
  • @ScarySneer The `TopAppBar` implements the material design [specs](https://material.io/components/app-bars-top#specs). You can also check the code. It uses an `AppBar` with this modifier: `.height(AppBarHeight)` where `AppBarHeight = 56.dp` – Gabriele Mariotti Jun 17 '21 at 20:14
  • 1
    @GabrieleMariotti can we set the height of TopAppBar to dynamic if the title text font size increase this should increase height accordingly. – Sultan Nov 07 '22 at 23:50
  • 2
    Is there any analogue of ```TopAppBar``` without height restriction but with ```scrollBehavior``` parameter? – Michael Abyzov Dec 22 '22 at 00:45
0
@Composable
fun ZCryptAppBar(
    modifier: Modifier = Modifier,
    title: @Composable RowScope.() -> Unit
) {
    Column(Modifier.fillMaxWidth()) {
        TopAppBar(
            content = {
                Column {
                    Row { title() }
                    Row {
                        TabLayout()
                    }
                }
            },
            modifier = modifier,
            backgroundColor = MaterialTheme.colors.primary,
            contentColor = Color.White
        )
    }
}

@Composable
fun TabLayout() {
    var selectedTab by remember {
        mutableStateOf(0)
    }
    TabRow(
        modifier = Modifier.fillMaxWidth(),
        selectedTabIndex = selectedTab,
        backgroundColor = MaterialTheme.colors.primary,
        tabs = {
            Tab(
                selected = selectedTab == 0,
                onClick = { selectedTab = 0 },
                text = { Text(stringResource(R.string.encrypt)) },
                icon = {
                    Image(
                        painterResource(id = R.drawable.ic_padlock_black),
                        stringResource(R.string.descr_icon_padlock)
                    )
                }
            )
            Tab(
                selected = selectedTab == 1,
                onClick = { selectedTab = 1 },
                text = { Text(stringResource(R.string.decrypt)) },
                icon = {
                    Image(
                        painterResource(id = R.drawable.ic_padunlock_black),
                        stringResource(R.string.descr_icon_padunlock)
                    )
                }
            )
        }
    )
}

When copying and pasting, it is common to forget to change values. Funny it happens so often I myself do it many times. Try it out

Oh by the way, here you were using the wrong variant of the ``TopAppBar``` The reason for the clipping was probably the fact that you were stuffing everything in the title of the bar. Using 'content' instead should fix that. If it doesn't, try Modifier.wrapContentSize()

Tabs were not changing since you applied the same logic in both the tabs.

Richard Onslow Roper
  • 5,477
  • 2
  • 11
  • 42
  • Lol I am so sorry it's a dummy copy-paste problem. Thank you, now tabs are switching however icons and text are still cropped even using the content parameter instead of title. BTW why is Google offering like 1 func name but which can point to two different functions which behave completely different. This also happens for the Tab element which has 2 functions which are completely different. Why just not name them or differently and explain in the docs the diffs between the 2 ? – ScarySneer Jun 17 '21 at 19:42
  • Shouldn't be happening really. Have you tried setting an explicit height to see if it works? – Richard Onslow Roper Jun 17 '21 at 19:45
  • Of course that's not a solution, but just to gain info, try it out – Richard Onslow Roper Jun 17 '21 at 19:45
  • About the why Google does that, it is not the only one. This is a common technique in programming called as method-overloading. We can create as many variants as required, with the same name, but different signatures (parameters). This is so that we can use the best one that suits our use case. It's rather an advantage. In the docs, you will see that it is a part of the material components which compose supports out of the box. Hence, for supporting different material styles (like with or without icons), there are multiple methods with the same name – Richard Onslow Roper Jun 17 '21 at 19:55
  • So two things about the appbar. I first tried to remove the tabrow and set a very high fontSize for the first Row { title() } and it turns out the appBar also does not automatically adjusts its height to show the entire the title. The title is just cropped and appbar keeps the same hieght. However if I set a custom Modifier.size() then the appbar changes its height and width according to the parameters I passed. I think this way of coding UI is not very good lol. I am missing something/doing wrong or is this just a bug as jetpack compose is still in beta ? – ScarySneer Jun 17 '21 at 20:01
  • I didn't know what was method overloading thank you for your explanation – ScarySneer Jun 17 '21 at 20:02