Is there a way to remove space in App Bar NestedScrollConnection?

I am trying to collapsing the App Bar with my Custom NestedScrollConnection but it make space in App Bar place when I Scroll. The App Bar goes up when I scroll but the space of App Bar in the Background of App Bar doesn’t go up?

My Custom NestedScrollConnection Class:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class CollapsingAppBarNestedScrollConnection(
val appBarMaxHeight: Int,
) : NestedScrollConnection {
var appBarOffset by mutableIntStateOf(0)
private set
override fun onPreScroll(
available: Offset,
source: NestedScrollSource,
): Offset {
val delta = available.y.roundToInt()
val newsOffset = appBarOffset + delta
val previousOffset = appBarOffset
appBarOffset = newsOffset.coerceIn(
-appBarMaxHeight,
0
)
val consumed = appBarOffset - previousOffset
return Offset(0f, consumed.toFloat())
}
}
</code>
<code>class CollapsingAppBarNestedScrollConnection( val appBarMaxHeight: Int, ) : NestedScrollConnection { var appBarOffset by mutableIntStateOf(0) private set override fun onPreScroll( available: Offset, source: NestedScrollSource, ): Offset { val delta = available.y.roundToInt() val newsOffset = appBarOffset + delta val previousOffset = appBarOffset appBarOffset = newsOffset.coerceIn( -appBarMaxHeight, 0 ) val consumed = appBarOffset - previousOffset return Offset(0f, consumed.toFloat()) } } </code>
class CollapsingAppBarNestedScrollConnection(
    val appBarMaxHeight: Int,
) : NestedScrollConnection {

    var appBarOffset by mutableIntStateOf(0)
        private set

    override fun onPreScroll(
        available: Offset,
        source: NestedScrollSource,
    ): Offset {
        val delta = available.y.roundToInt()
        val newsOffset = appBarOffset + delta
        val previousOffset = appBarOffset
        appBarOffset = newsOffset.coerceIn(
            -appBarMaxHeight,
            0
        )
        val consumed = appBarOffset - previousOffset

        return Offset(0f, consumed.toFloat())
    }
}

MY UI:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>val density = LocalDensity.current
val appBarMaxHeight = with(density) { (70).dp.roundToPx() }
val connection = remember(appBarMaxHeight) {
CollapsingAppBarNestedScrollConnection(appBarMaxHeightPx)
}
Scaffold(
topBar = {
TopAppBar(
title = {
Text("Top App Bar")
},
modifier = Modifier
.offset { IntOffset(0, connection.appBarOffset) }
)
},
modifier = Modifier
.fillMaxSize()
.nestedScroll(connection)
) {
// Content
}
</code>
<code>val density = LocalDensity.current val appBarMaxHeight = with(density) { (70).dp.roundToPx() } val connection = remember(appBarMaxHeight) { CollapsingAppBarNestedScrollConnection(appBarMaxHeightPx) } Scaffold( topBar = { TopAppBar( title = { Text("Top App Bar") }, modifier = Modifier .offset { IntOffset(0, connection.appBarOffset) } ) }, modifier = Modifier .fillMaxSize() .nestedScroll(connection) ) { // Content } </code>
val density = LocalDensity.current

val appBarMaxHeight = with(density) { (70).dp.roundToPx() }

val connection = remember(appBarMaxHeight) {
    CollapsingAppBarNestedScrollConnection(appBarMaxHeightPx)
}

Scaffold(
   topBar = {
      TopAppBar(
         title = {
            Text("Top App Bar")
         },
         modifier = Modifier
             .offset { IntOffset(0, connection.appBarOffset) }
      )
   },
   modifier = Modifier
       .fillMaxSize()
       .nestedScroll(connection)
) {
   // Content
}

Video gif, before

Video gif, After

2

When you use the offset Modifier, the space where the Composable originally was remains reserved. This is because

it avoids recomposition when the offset is changing, and also adds a graphics layer that prevents unnecessary redrawing of the context when the offset is changing.

Thus, the offset is applied on another layer and does not actually impact the Composable hierarchy. This means that you can’t use the space where the TopAppBar originally was for other Composables.

To achieve this, you would usually use a default NestedScrollConnection like TopAppBarDefaults.enterAlwaysScrollBehavior.

If you actually need a custom NestedScrollConnection the TopAppBar to shift out of the screen at scrolling, implement this using the height Modifier together with wrapContent:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyCollapsibleTopAppBarDemo() {
val density = LocalDensity.current
val myNestedScrollConnection = remember {
MyNestedScrollConnection(TopAppBarDefaults.TopAppBarExpandedHeight.dpToPx(density))
}
Scaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(myNestedScrollConnection),
topBar = {
CenterAlignedTopAppBar(
modifier = Modifier
.height(myNestedScrollConnection.currentHeaderHeightPx.toInt().pxToDp(density))
.wrapContentHeight(Alignment.Bottom, true),
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = Color.LightGray
),
title = {
Text("Demonstration")
}
)
}
) { innerPadding ->
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
items(50) { item ->
Text("Item $item", modifier = Modifier.padding(16.dp))
}
}
}
}
fun Dp.dpToPx(density: Density) = with(density) { [email protected]() }
fun Int.pxToDp(density: Density) = with(density) { [email protected]() }
</code>
<code>@OptIn(ExperimentalMaterial3Api::class) @Composable fun MyCollapsibleTopAppBarDemo() { val density = LocalDensity.current val myNestedScrollConnection = remember { MyNestedScrollConnection(TopAppBarDefaults.TopAppBarExpandedHeight.dpToPx(density)) } Scaffold( modifier = Modifier .fillMaxSize() .nestedScroll(myNestedScrollConnection), topBar = { CenterAlignedTopAppBar( modifier = Modifier .height(myNestedScrollConnection.currentHeaderHeightPx.toInt().pxToDp(density)) .wrapContentHeight(Alignment.Bottom, true), colors = TopAppBarDefaults.centerAlignedTopAppBarColors( containerColor = Color.LightGray ), title = { Text("Demonstration") } ) } ) { innerPadding -> LazyColumn( modifier = Modifier .fillMaxSize() .padding(innerPadding) ) { items(50) { item -> Text("Item $item", modifier = Modifier.padding(16.dp)) } } } } fun Dp.dpToPx(density: Density) = with(density) { [email protected]() } fun Int.pxToDp(density: Density) = with(density) { [email protected]() } </code>
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyCollapsibleTopAppBarDemo() {

    val density = LocalDensity.current
    val myNestedScrollConnection = remember {
        MyNestedScrollConnection(TopAppBarDefaults.TopAppBarExpandedHeight.dpToPx(density))
    }

    Scaffold(
        modifier = Modifier
            .fillMaxSize()
            .nestedScroll(myNestedScrollConnection),
        topBar = {
            CenterAlignedTopAppBar(
                modifier = Modifier
                    .height(myNestedScrollConnection.currentHeaderHeightPx.toInt().pxToDp(density))
                    .wrapContentHeight(Alignment.Bottom, true),
                colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                    containerColor = Color.LightGray
                ),
                title = {
                    Text("Demonstration")
                }
            )
        }
    ) { innerPadding ->
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
        ) {
            items(50) { item ->
                Text("Item $item", modifier = Modifier.padding(16.dp))
            }
        }
    }
}

fun Dp.dpToPx(density: Density) = with(density) { [email protected]() }
fun Int.pxToDp(density: Density) = with(density) { [email protected]() }

Update your custom NestedScrollConnection like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class MyNestedScrollConnection(
val appBarMaxHeight: Float,
) : NestedScrollConnection {
var currentHeaderHeightPx by mutableFloatStateOf(appBarMaxHeight)
private set
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
val delta = available.y
// add this if statement when you only want the TopAppBar to appear when scrolled fully to the top
if (delta >= 0) {
return Offset.Zero
}
//
val newHeaderHeightPx = currentHeaderHeightPx + delta
val previousHeaderHeightPx = currentHeaderHeightPx
currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight)
val consumed = currentHeaderHeightPx - previousHeaderHeightPx
return Offset(x = 0f, y = consumed)
}
// additionally add this fun when you only want the TopAppBar to appear when scrolled fully to the top
// this code is very similar to onPreScroll, so you could extract a common method for it
override fun onPostScroll(
consumed: Offset,
available: Offset,
source: NestedScrollSource
): Offset {
val delta = available.y
val newHeaderHeightPx = currentHeaderHeightPx + delta
val previousHeaderHeightPx = currentHeaderHeightPx
currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight)
val consumedLocally = currentHeaderHeightPx - previousHeaderHeightPx
return Offset(x = 0f, y = consumedLocally)
}
}
</code>
<code>class MyNestedScrollConnection( val appBarMaxHeight: Float, ) : NestedScrollConnection { var currentHeaderHeightPx by mutableFloatStateOf(appBarMaxHeight) private set override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val delta = available.y // add this if statement when you only want the TopAppBar to appear when scrolled fully to the top if (delta >= 0) { return Offset.Zero } // val newHeaderHeightPx = currentHeaderHeightPx + delta val previousHeaderHeightPx = currentHeaderHeightPx currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight) val consumed = currentHeaderHeightPx - previousHeaderHeightPx return Offset(x = 0f, y = consumed) } // additionally add this fun when you only want the TopAppBar to appear when scrolled fully to the top // this code is very similar to onPreScroll, so you could extract a common method for it override fun onPostScroll( consumed: Offset, available: Offset, source: NestedScrollSource ): Offset { val delta = available.y val newHeaderHeightPx = currentHeaderHeightPx + delta val previousHeaderHeightPx = currentHeaderHeightPx currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight) val consumedLocally = currentHeaderHeightPx - previousHeaderHeightPx return Offset(x = 0f, y = consumedLocally) } } </code>
class MyNestedScrollConnection(
    val appBarMaxHeight: Float,
) : NestedScrollConnection {

    var currentHeaderHeightPx by mutableFloatStateOf(appBarMaxHeight)
        private set

    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        val delta = available.y
        // add this if statement when you only want the TopAppBar to appear when scrolled fully to the top
        if (delta >= 0) {
            return Offset.Zero
        }
        // 
        val newHeaderHeightPx = currentHeaderHeightPx + delta
        val previousHeaderHeightPx = currentHeaderHeightPx
        currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight)
        val consumed = currentHeaderHeightPx - previousHeaderHeightPx
        return Offset(x = 0f, y = consumed)
    }

    // additionally add this fun when you only want the TopAppBar to appear when scrolled fully to the top
    // this code is very similar to onPreScroll, so you could extract a common method for it
    override fun onPostScroll(
        consumed: Offset,
        available: Offset,
        source: NestedScrollSource
    ): Offset {
        val delta = available.y
        val newHeaderHeightPx = currentHeaderHeightPx + delta
        val previousHeaderHeightPx = currentHeaderHeightPx
        currentHeaderHeightPx = newHeaderHeightPx.coerceIn(0f, appBarMaxHeight)
        val consumedLocally = currentHeaderHeightPx - previousHeaderHeightPx
        return Offset(x = 0f, y = consumedLocally)
    }
}

Output:

Note:

This does not animate the CenterAlignedTopAppBar color when the content is scrolled.

8

I found the Problem I just Add Height Modifier in My App Bar.

so whenever I scroll so it also moves the space that remains in the App Bar

I have to gave the exact height to the Composable that I don’t want. how Can I gave the Wrap Height or without Height

and How You add Video, How can I Add Video?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>
// Top Bar Scroll Connection
val topBarMaxHeight: Int = with(density) { (30).dp.roundToPx() }
val topBarScrollConnection: CollapsingAppBarNestedScrollConnection =
remember(topBarMaxHeight) {
CollapsingAppBarNestedScrollConnection(topBarMaxHeight)
}
CenterAlignedTopAppBar(
title = {
Text(
text = if(tabPagerState.currentPage == 0) "News" else "Events",
)
},
navigationIcon = {
IconButton(onClick = {
scope.launch {
drawerState.open()
}
}) {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Icon for Navigation Drawer",
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent
),
modifier = Modifier
.statusBarsPadding()
.then(
with(density) {
Modifier
.height( // I Add this Height
(topBarMaxHeight + topBarScrollConnection.appBarOffset).toDp()
)
}
)
.offset { IntOffset(0, topBarScrollConnection.appBarOffset) }
)
</code>
<code> // Top Bar Scroll Connection val topBarMaxHeight: Int = with(density) { (30).dp.roundToPx() } val topBarScrollConnection: CollapsingAppBarNestedScrollConnection = remember(topBarMaxHeight) { CollapsingAppBarNestedScrollConnection(topBarMaxHeight) } CenterAlignedTopAppBar( title = { Text( text = if(tabPagerState.currentPage == 0) "News" else "Events", ) }, navigationIcon = { IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon( imageVector = Icons.Default.Menu, contentDescription = "Icon for Navigation Drawer", ) } }, colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Transparent, scrolledContainerColor = Color.Transparent ), modifier = Modifier .statusBarsPadding() .then( with(density) { Modifier .height( // I Add this Height (topBarMaxHeight + topBarScrollConnection.appBarOffset).toDp() ) } ) .offset { IntOffset(0, topBarScrollConnection.appBarOffset) } ) </code>

  // Top Bar Scroll Connection
    val topBarMaxHeight: Int = with(density) { (30).dp.roundToPx() }
    val topBarScrollConnection: CollapsingAppBarNestedScrollConnection =
        remember(topBarMaxHeight) {
            CollapsingAppBarNestedScrollConnection(topBarMaxHeight)
        }


                        CenterAlignedTopAppBar(
                            title = {
                                Text(
                                    text = if(tabPagerState.currentPage == 0) "News" else "Events",
                                )
                            },
                            navigationIcon = {
                                IconButton(onClick = {
                                    scope.launch {
                                        drawerState.open()
                                    }
                                }) {
                                    Icon(
                                        imageVector = Icons.Default.Menu,
                                        contentDescription = "Icon for Navigation Drawer",
                                    )
                                }
                            },
                            colors = TopAppBarDefaults.topAppBarColors(
                                containerColor = Color.Transparent,
                                scrolledContainerColor = Color.Transparent
                            ),
                            modifier = Modifier
                                .statusBarsPadding()
                                .then(
                                    with(density) {
                                        Modifier
                                            .height( // I Add this Height
                                                (topBarMaxHeight + topBarScrollConnection.appBarOffset).toDp()
                                            )
                                    }
                                )
                                .offset { IntOffset(0, topBarScrollConnection.appBarOffset) }
                        )

I Add Height so when ever I scroll so the it moves the height of TopAppBar Also that before it remains.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật