Compose의 기본 레이아웃  -  Android Developers

❗ 레이아웃을 다루는 코드랩이므로 상태와 관련된 내용은 무시했음을 주의 ❗

🎨 디자인 분석

  • 재사용 사능한 컴포저블로 나누기
  • 가장 낮은 수준 컴포저블로 시작해 복잡한 컴포저블 순으로 구현


✨ Modifier

  • 컴포저블의 크기,레이아웃,동작,모양 변경
  • 접근성 라벨과 같은 정보 추가
  • 사용자 입력 처리
  • 요소를 클릭,스크롤,드래그,확대/축소 가능하게 만드는 것과 같은 상호작용 추가

요소 최소 높이 지정

```kotlin
//높이 지정
Modifier.height(56.dp)
//최소 기본 높이 지정 - 단, 사용자가 글꼴 크기 확대 시 크기 커질 수 있음
Modifier.heightIn(min=56.dp) 
```

베이스라인 패딩

//컨텐츠외곽선으로 부터 패딩
Modifier.padding(...)
//베이스 라인(컨텐츠가 놓여있는 선)으로 부터 패딩
Modifier.paddingFromBaseLine(top=40.dp,bottom=8.dp)

clip : 컴포저블 모양 조정

import androidx.compose.foundation.shape.CircleShape

Modifier.clip(CircleShape) // 원형으로 clip
//둥근 코너 모양 : RoundedCornerShape(3.dp)

Size : 컴포저블 사이즈 조정

Modifier.size(56.dp)

verticalScroll(Column), horizontalScroll(Row) : 수동으로 스크롤 동작 추가

Column(
	modifier.verticalScroll(rememberScrollState()) 
)
  • ScrollState
    • 스크롤의 현재상태를 포함
    • 외부에서 스크롤 상태 수정에 사용
    • 스크롤 상태 수정이 필요 없다면 위의 예시처럼 사용


🥨 정렬(Alignment)

***(
	horizontalAlignment=Alignment.~ //Column의 하위 요소 기본 정렬 설정
	verticalAlignment=Alignment.~ //Row의 하위 요소 기본 정렬 설정
	contentAlignment=Alignment.~ //Box의 하위 요소 기본 정렬 설정
){
	Sub***(
		//해당요소의 상위 요소에 대한 정렬 설정
		modifier=modifier=Modifier.align(Aligment.~)
	)
}

(Lazy)Column

  • 하위요소를 가로로 정렬
//왼쪽 정렬
horizontalAlignment=Alignment.Start 
//오른쪽 정렬
horizontalAlignment=Alignment.End 
//가운데 정렬
horizontalAlignment=Alignment.CenterHorizontally 

(Lazy)Row

  • 하위 요소를 세로로 정렬
//위쪽 정렬
verticalAlignment=Alignment.Top
//아래쪽 정렬
verticalAlignment=Alignment.Bottom 
//가운데 정렬
verticalAlignment=Alignment.CenterVertically

Box

  • 하위 요소를 가로 및 세로로 정렬
//왼쪽 위 정렬
contentAlignment=Alignment.TopStart 
//가운데 위 정렬
contentAlignment=Alignment.TopCenter 
//오른쪽 위 정렬
contentAlignment=Alignment.TopEnd

//왼쪽 가운데 정렬
contentAlignment=Alignment.CenterStart 
//중앙에 정렬
contentAlignment=Alignment.Center
//오른쪽 가운데 정렬
contentAlignment=Alignment.CenterEnd 

//왼쪽 아래 정렬
contentAlignment=Alignment.BottomStart 
//가운데 아래 정렬
contentAlignment=ALignment.BottomCenter
//오른쪽 아래 정렬
contentAlignment=Alignment.BottomEnd 


🍞 배치(Arrangement)

정렬(Alignment)이랑 스펠링이 비슷(?)하지만 완전 다르므로 구분해야 한다!

  • 정렬(Alignment) : 기준축에 수직 방향으로 작용
  • 배치(Arrangement) : 기준축 방향으로 작용

(Lazy)Column

//요소사이 고정된 간격추가
verticalArrangment=Arrangement.spacedBy(8.dp)

(Lazy)Row

//요소사이 고정된 간격추가
horizontalArrangment=Arrangement.spacedBy(8.dp)


🧱 Composable

TextField : 검색창 만들기

//material 3
TextField(
        //입력 가능한 텍스트 요소
        value = "",//초기값 지정
        onValueChange = {},//값 바뀔때 호출
        leadingIcon = { //앞쪽 아이콘
            Icon(
                imageVector = Icons.Default.Search,
                contentDescription = null,
            )
        },
        colors = androidx.compose.material3.TextFieldDefaults.colors(//textFiledDefault에서 변경된 backgroundColor만 변경
            unfocusedContainerColor = MaterialTheme.colorScheme.surface
        ),
        placeholder = {
            Text(stringResource(id = R.string.placeholder_search))
        },
        modifier = modifier
            .fillMaxWidth() //상위요소의 전체 가로 공간 차지하도록 설정
            .heightIn(min = 56.dp), //요소의 높이를 고정 높이가 아닌 최소높이로 지정하여 내용물에 따라 크기 변할 수 있도록 설정(권장)

    )
//그냥 material1을 사용할 때 변경사항
colors= TextFieldDefaults.textFieldColors(
			backgroundColor=MaterialTheme.colors.surface //textFiledDefault에서 변경된 backgroundColor만 변경
		)

Image : 이미지를 자르고 스케일을 설정하기

Image(
	painter = painterResource(R.drawable.~), // 이미지에 들어갈 드로어블
	contentDescription=null, // 이미지 설명(권장), 다른 부분에 이미지 설명이 있다면 없어도 됨.
	contentScale=ContentScale.Crop, //이미지 스케일링 설정
	modifier=Modifier.
		.size(88.dp) //이미지 크기 설정
		.clip(CircleShape) // 이미지 모양 설정
)

Surface : 모양 설정하기

Surface(
	shape=MaterialTheme.shapes.small
){
	...
}

Text : 텍스트 스타일 변경

  • 웬만하면 material에 정해진 기본 스타일 추천
Text(
	text=...,
	style=MaterialTheme.typograpgy.***)

요소 사이 간격 지정, 내용물 패딩 지정(LazyRow,LazyColum,)

//요소 사이 간격 지정
LazyRow(
	horizontalArrangement=Arrangement.spacedBy(8.dp)
)
LazyColumn(
    verticalArrangement=Arrangement.spacedBy(8.dp)
	
)

//내용물 패딩 지정
LazyRow( //or LazyColumn
	contentPadding=PaddingValues(horizontal=16.dp)
)

❗padding으로 내용물 패딩 지정 시 스크롤이 잘림

LazyGrid

  • LazyHorizontalGrid
LazyHorizontalGrid(
       rows = GridCells.Fixed(2), // 행 개수 지정
       contentPadding = PaddingValues(horizontal = 16.dp), //내용물 패딩 지정
       horizontalArrangement = Arrangement.spacedBy(8.dp), //가로방향 요소 간격 지정
       verticalArrangement = Arrangement.spacedBy(8.dp), //세로방향 요소 간격 지정
       modifier = modifier.height(120.dp) //높이 지정
   ) {
       items(favoriteCollectionsData) { item ->
           //item으로 사용할 Composable 반환
       }
   }

Spacer : padding을 사용하지 않고 빈 공간 만들기

Spacer(Modifier.height(16.dp))

Slot API : 컨테이너 역할을 하는 컴포저블 만들기

@Composable
fun HomeSection(
   @StringRes title: Int,
   modifier: Modifier = Modifier,
   **content: @Composable () -> Unit**
) {
   Column(modifier) {
       Text(stringResource(title))
       content()
   }
}

//사용
HomeSection(...) {/*content에 들어갈 컴포저블*/} //<-후행람다를 사용해 content정의 가능

BottomNavigation : Material을 이용해 하단바 만들기

import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem

BottomNavigation(
	modifier=modifier,
	backgroundColor = MaterialTheme.colors.background// 배경색 설정(onBackground로 설정됨)
) {
			//하단 버튼1
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.Spa,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_home))
           },
           selected = true,
           onClick = {}
       )
			//하단 버튼2
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.AccountCircle,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_profile))
           },
           selected = false,
           onClick = {}
       )
   }

Scaffold : Material Design을 구현하는 화면구조

  • Scaffold의 사전적 의미는 건축 시 쓰는 가설 발판
  • material 디자인을 따른 화면 구조를 정해둔 뼈대느낌 (이름을 잘 지은 것 같다!)
  • Scaffold를 뼈대라고 생각하고 각 구역에 적절한 요소를 넣으면 머티리얼 디자인 완성!
  • 근데 혼자 써본 바로는 머티리얼 3에서는 아직 개선 중인 듯 하다!
@Composable
fun ***App() {
   ***Theme {
       Scaffold(
						// 만든 네비게이션 바를 넣어주면머티리얼 디자인에서 bottombar구역으로 지정한 곳에 적용되는 느낌!
           bottomBar = { SootheBottomNavigation() } 
       ) { padding ->
					//여기는 메인 화면이 들어감
					//padding은 머티리얼 디자인의 각 화면요소로 줄어든 메인 화면 영역을 반영한거라서 아래처럼 padding에 넣어줘야 메인화면과 다른 요소가 겹치지 않는다!
           HomeScreen(Modifier.padding(padding))
       }
   }
}


🎸 기타

문자열을 대문자로 변환하기

String.upperCase(Locale.getDefault())


🤔 이번 코드랩에서 든 생각

  • 일반적으로 매개변수로 전달된 modifier는 가장 바깥의 컨테이너가 되는 컴포저블에 전달해야하는것같다.
  • 매개변수로 문자열 리소스 등을 전달할 때는 String이 아닌 id(Int)로 전달하는것 같다.
  • 컴포저블 UI 구조를 설계할 때 만들 때 가장 작은 UI 단위, 반복되는 부분으로 뜯어서 반복작업을 최소화한다.

댓글남기기