컴포즈가 아닌 xml로 구현할때는 세상 귀찮았던 리스트뷰 !!!!
컴포즈로 구현해봅시다
컴포즈의 가장 큰 장점은 변화에 자유롭다는 것.
데이터의 변화에 바로바로 반응할 수 있다는 점이 가장 큰 장점이지 않을까 싶다.
임시적으로 보여주기 위해 일단은 뷰모델에 더미데이터를 만들어뒀지만 일반적으로는 데이터 베이스에서 데이터를 불러와 리스트로 노출해줄때 적용할 수 있다
private val viewModel by viewModels<ViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestTheme {
Surface(
modifier = Modifier.fillMaxSize()
) {
MainScreen(viewModel)
}
}
}
}
}
@Composable
fun MainScreen(viewModel: ViewModel) {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = {
},
actions = {
IconButton(onClick = { }) {
Icon(Icons.Filled.Send, contentDescription = "")
}
},
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(Icons.Filled.Menu, contentDescription = "")
}
},
modifier = Modifier.fillMaxWidth(),
backgroundColor = MaterialTheme.colors.background,
elevation = 0.dp
)
}
) {
Column(
modifier = Modifier
.padding(it)
.fillMaxSize()
) {
ListScreen() // 리스트 뷰
}
}
}
@Composable
fun ListScreen(
) {
Column() {
Text(text = "RowList", modifier = Modifier.padding(start = 20.dp))
RowList(viewModel.testData.collectAsState())
Text(text = "GridList", modifier = Modifier.padding(start = 20.dp))
GridList(viewModel.testData.collectAsState())
}
}
@Composable
fun GridList(data: State<ArrayList<TestData>?>) { // 그리드뷰
val scrollState = rememberLazyGridState()
LazyVerticalGrid( // lazy는 지연 목록으로, 데이터의 수를 모르는 경우 맞춰서 변할 수 있음
state = scrollState,
columns = GridCells.Fixed(2),
verticalArrangement = Arrangement.spacedBy(40.dp),
horizontalArrangement = Arrangement.spacedBy(40.dp),
modifier = Modifier
.padding(top = 10.dp, start = 30.dp, end = 30.dp),
userScrollEnabled = true
) {
data.value?.let {
items(it) { item ->
// 데이터 마다 카드(item) 생성
GridItemCard(data = item)
}
}
}
}
@Composable
fun RowList(data: State<ArrayList<TestData>?>) {
LazyRow(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState())
.padding(start = 30.dp, end = 30.dp, top = 10.dp, bottom = 30.dp)
) {
data.value?.let {
items(it) { item ->
RowItemCard(item)
}
}
}
}
@Composable
fun GridItemCard(data: TestData) {
Card(
modifier = Modifier
.fillMaxWidth()
.height(230.dp),
shape = MaterialTheme.shapes.small.copy(CornerSize(20.dp)),
elevation = 10.dp
) {
Column() {
val modifier = Modifier.fillMaxHeight(0.6f)
ItemImage(data.image, data.gender)
ItemText(data)
}
}
}
@Composable
fun RowItemCard(data: TestData) {
Card(
modifier = Modifier
.padding(end = 20.dp)
.fillMaxWidth(),
shape = MaterialTheme.shapes.small.copy(CornerSize(20.dp)),
elevation = 10.dp
) {
Surface(shape = MaterialTheme.shapes.small.copy(CornerSize(20.dp))) {
Row(verticalAlignment = Alignment.Bottom) {
ItemImage(data.image, data.gender)
ItemText(data)
}
}
}
}
@Composable
fun ItemText(data: TestData) {
Column(Modifier.padding(10.dp)) {
Text(text = data.name, fontSize = 15.sp, color = Color.Black, modifier = Modifier.padding(bottom = 10.dp))
Text(text = data.age.toString(), fontSize = 13.sp, color = Color.Black)
Text(text = data.gender, fontSize = 13.sp, color = Color.Black)
Text(
text = if (data.student) "student"
else "not student",
fontSize = 13.sp
)
}
}
@Composable
fun ItemImage(image: String, gender: String) {
Surface(shape = MaterialTheme.shapes.small.copy(CornerSize(20.dp))) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(image)
.crossfade(true)
.build(),
contentDescription = null,
contentScale = ContentScale.Crop,
placeholder = painterResource(
when (gender) {
"male" -> com.example.test.R.drawable.man
else -> com.example.test.R.drawable.woman
}
),
modifier = Modifier.size(100.dp)
)
}
}