如何使用 Jetpack compose 构建 Instagram 个人资料页面。我尝试过多个库,如 NestedScrollView、CollapsingToolbar 来获得可折叠/可滚动的顶栏,但它们看起来并不平滑。使用 CoordinatorLayout 通过 XML 进行构建很容易。
预期卷轴:- Instagram 个人资料页面
使用 NestedScrollView 库:- 嵌套滚动视图
这个布局很容易用
LazyColumn
和 stickyHeader
实现:
LazyColumn(Modifier.fillMaxWidth()) {
item {
Text("Header")
}
stickyHeader {
TabRow(selectedTabIndex = 0) {
repeat(4) {
Tab(selected = it == 0, onClick = {}) {
Text(
it.toString()
)
}
}
}
}
items(100) {
Text(it.toString())
}
}
我找到了一个库来创建与 Instagram 相同的个人资料布局。 github 链接:- compose-collapsing-toolbar
implementation "me.onebone:toolbar-compose:2.3.5"
使用以下代码折叠工具栏
CollapsingToolbarScaffold(
modifier = Modifier.fillMaxSize(),
state = state,
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
enabled = true,
toolbar = { // create header layout here }
) {
// create main layout here
}
这里我创建了一个带有选项卡布局的示例配置文件布局
package // replace with your package name
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.ShoppingCart
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.totel.testing.ui.theme.TestingTheme
import me.onebone.toolbar.CollapsingToolbarScaffold
import me.onebone.toolbar.ScrollStrategy
import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestingTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
ProfileLayout()
}
}
}
}
}
@Composable
fun ProfileLayout() {
val state = rememberCollapsingToolbarScaffoldState()
Box {
CollapsingToolbarScaffold(
modifier = Modifier.fillMaxSize(),
state = state,
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
enabled = true,
toolbar = {
Column(
modifier = Modifier
.parallax(0.5f)
.height(300.dp)
) {
Text(text = "Hello")
Text(text = "Hello")
Text(text = "Hello")
Text(text = "Hello")
Text(text = "Hello")
}
}
) {
TabContent()
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TabContent(modifier: Modifier = Modifier) {
val pagerState = rememberPagerState(pageCount = {
3
})
Column(
modifier = modifier.fillMaxWidth(),
) {
Tabs(pagerState = pagerState)
TabsContent(pagerState = pagerState)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Tabs(pagerState: PagerState) {
val list = listOf(
"Home" to Icons.Default.Home,
"Shopping" to Icons.Default.ShoppingCart,
"Settings" to Icons.Default.Settings
)
TabRow(
selectedTabIndex = pagerState.currentPage,
contentColor = Color.Black,
) {
list.forEachIndexed { index, _ ->
// on below line we are creating a tab.
Tab(
icon = {
Icon(
imageVector = list[index].second, contentDescription = null,
tint = if (pagerState.currentPage == index) Color.Blue else Color.Black
)
},
text = {
Text(
list[index].first,
color = if (pagerState.currentPage == index) Color.Blue else Color.Black
)
},
selected = pagerState.currentPage == index,
onClick = {
}
)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TabsContent(pagerState: PagerState) {
HorizontalPager(state = pagerState) { page ->
when (page) {
0 -> TabContentScreen(data = "Welcome to Home Screen")
1 -> TabContentScreen(data = "Welcome to Shopping Screen")
2 -> TabContentScreen(data = "Welcome to Settings Screen")
}
}
}
@Composable
fun TabContentScreen(data: String) {
val itemsList = (0..500).toList()
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
items(items = itemsList) { item ->
Text(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
text = "$data $item",
style = MaterialTheme.typography.labelLarge,
color = Color.Black,
fontWeight = FontWeight.Medium,
)
}
}
}