Jetpack Compose Custom CameraView 촬영-프리뷰 구현하기

현재 서비스중인 앱의 카메라 기능은 전부 XML 기반의 커스텀뷰를 만들어서 사용중이다. Compose를 공부하는 기회에 해당 부분을 Compose로 구현해 봤다. 정말 간단한 기능의 카메라 촬영, 프리뷰 기능만을 구현한 코드를 기록해 두려한다. 코드의 가독성이나 이슈가될 만한 부분들은 상황에 맞게 조절하여 사용하시면 됩니다. @Composable fun CameraComponent( modifier: Modifier = Modifier, selfMode: Boolean, takeAction: Boolean, receiveImageUrl: (Bitmap?) -> Unit ) { val cameraSelector = if (selfMode) { CameraSelector.DEFAULT_FRONT_CAMERA } else { CameraSelector.DEFAULT_BACK_CAMERA } val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current val imageCapture = remember { ImageCapture.Builder().build() } val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) } val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() val preview: androidx.camera.core.Preview = androidx.camera.core.Preview.Builder().build() val cameraViewModel: CameraComponentModel = hiltViewModel() val imageBitmap by came

Jetpack Compose Text 2편

이미지
저번 Text 설명 1편에 이어서 2편을 작성해보도록 하겠습니다. Text는 크게 색다로운 내용이 있다긴 보다 되짚어보는 정리정도 되는거 같습니다.  2편 같은 경우 사용자 상호작용 개념이 있어서 1편보다는 좀더 좋은 기능을 설명하고 있습니다. 1. 사용자 상호작용  사용자 상호작용을 사용 설정할 수 있는 다양한 API를 설명합니다.  - 여러 Composable 레이아웃에서 더 유연하게 텍스트를 선택할 수 있음  - Text Composable 의 부분에 제어자를 추가할 수 없어서 Text의 사용자 상호작용은 다른 Composable 레이아웃과 다름 1) 텍스트 선택하기 기본적으로 Composable은 선택할 수 없습니다. 텍스트 선택 기능을 사용 설정하려면 Text를 SelectionContainer Composable로 래핑해야 합니다. @Composable fun SelectableText() { SelectionContainer { Text("This text is selectable") } } 특정 부분만 선택 표시를 중지 할 수도 있습니다.  선택 불가능한 부분을 DisableSelection Composable로 래핑해서 사용할 수 있습니다. @Composable fun PartiallySelectableText() { SelectionContainer { Column { Text("This text is selectable") Text("This one too") Text("This one as well") DisableSelection { Text("But not this one") Text("Neither this one"

Jetpack Compose Text 1편

이미지
 이번에는 Compose의 텍스트에 관해 정리를 해봤습니다. - Compose는 텍스트를 표시하고 사용자 입력을 처리하는 기본 구조인 BasicText 및 BasicTextField를 제공함 - 상위 수준에서 Compose는 Text 및 TextField를 제공하며 머티리얼 디자인를 따름 (위 Composable은 디자인과 분위기가 Android 사용자에게 적합하며 쉽게 커스텀 할 수 있는 옵션이 포함되어 있으므로 사용을 권장함) 1. 기본  Text  표시 텍스트를 표시하는 가장 기본적인 방법은 Text Composable을 사용하는 것입니다. @Composable fun SimpleText() { Text("Hello World") //문자열 리소스를 사용하는 예제 Text(stringResource(R.string.hello_world)) } 2.  Text  Style 지정 Text Composable에는 콘텐츠의 스타일을 지정할 수 있는 여러 매개변수가 있습니다. 이 매개변수 중 하나를 설정할 때마다 전체 텍스트 값에 스타일이 적용됩니다.  - color, fontSize, fontStyle, fontWeight, textAlign 언어 텍스트 방향에 따라 Text 이동하는 TextAlign.Start와 TextAlign.End를 사용하는 것을 권장함 (TextAlign.Left, TextAlign.Right 은 가급적 제한적 사용) @Composable fun SimpleText() { //텍스트 색상 변경 Text("Hello World", color = Color.Blue) //텍스트 크기 변경 Text("Hello World", fontSize = 30.sp) //텍스트를 기울임꼴로 설정 Text("Hello World", fontStyle = FontStyle.Italic)

Jetpack Navigation + BottomNavigationBar 구현하기

1. Jetpack Navigation 사실 Jetpack Navigation에 대해서는 이전에도 한번 포스트를 쓴 적이 있다. Navigation은 크게 3가지 요소로 이루어져 있다. NavController - 대상(즉, 앱의 화면) 간 이동을 담당하는데, 탐색 동작을 처리하는 역할 - 대상을 탐색하고 딥 링크를 처리하며 대상 백 스택을 관리하는 등의 여러 메소드를 제공 NavGraph - 이동할 컴포저블 대상의 매핑을 담당 - 앱 내의 화면 연결을 보여주는 일종의 지도 역할을 한다. NavHost - 현재 탐색 대상(navigation destination)이 포함된 UI 요소 - NavGraph의 현재 대상을 표시하는 컨테이너 역할을 하는 컴포저블 2. BottomNavigationBar 구현하기 이제 위에서 설명한 Navigation과 Compose를 활용해 BottomNavigationBar를 구현해보자. gradle에 라이브러리 추가 dependencies { implementation("androidx.navigation:navigation-compose:2.7.7") } Bottom Navigation으로 이동할 화면 생성 필자는 여기서 Home, Rating, Profile 3개의 화면을 만들어주었다. @Composable fun HomeScreen() { Text(text = "Home") } @Composable fun RatingScreen() { Text(text = "Rating") } @Composable fun ProfileScreen() { Text(text = "Profile") } BottomNavItem 생성. Bottom Navigation으로 이동할 item 객체 클래스 BottomNavItem 클래스를 생성하고, 그 자식으로 Home, Rating, Profile 을 추가한다. sealed class BottomNa

Jetpack Compose ConstraintLayout

이미지
Compose에 대한 내용을 언급하던 중에 ConstraintLayout 이란 항목이 갑자기 튀어나옵니다.  한껏 Column, Row, Box란 view group 역할을 하는 composable을 한껏 제공해 주고 나서 말이죠.  게다가 ConstraintLayout은 기존 View group 방식에서 view group의 중첩, 다시 말해 layout의 depth가 깊어지는 걸 막기 위해 2017년에 새롭게 등장한 layout입니다. CustomLayout에서 이미 봤듯이 Compose에서는 measure가 한 번만 가능하기 때문에 View의 depth가 깊어지더라도 문제가 발생하지 않습니다.  다만 Compose에서의 ConstraintLayout은 뷰의 구조가 복잡할 때, 여러 view들 간의 상호관계에 따른 배치를 좀 더 쉽게 가능하도록 하는 목적으로 사용됩니다. 추후 설명할 Compose의 constraint의 사용법은 기존 view system에서 사용하던 ConstraintLayout과 거의 동일합니다. (코드로 표현하는 방법이 다를 뿐) 다만 목적은 "기존의 view system에서 사용된 것과는 다르다" 정도만 이해하고 있으면 이번 포스트팅은 어렵지 않게 클리어 가능할 것으로 생각됩니다. 이 글은 Android developer 공식 사이트에서 제공하는 문서를 기반으로 의역, 번역하였습니다. Gradle dependency Constraint layout을 compose에서 사용하기 위해서는  따로 dependency가 필요합니다. 여기서 주의해야 할 점은 기본 compose의 버전을 따라가지 않는다는 겁니다. implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1" 현재 최신 compose 버전은 1.6.7이며, 이 constraintlayout (1.0.1)을 쓰려면 kotlin은 2.0.0을 써야 합니다 정리하면 기본 comp

Jetpack Compose LazyColumn / LazyRow (=RecyclerView)

이미지
이번 포스팅은 Compose의 리스팅 기능을 살펴보고자 한다. 기존 Xml방식은 List를 주로 RecyclerView 혹은 ListView로 많이 구현을 했을것이다. Compose에서는 List를 어떻게 구현해야할지 살펴보겠습니다. 기본적인 Column 또는 Row를 사용하여 각 아이템의 콘텐츠를 표시할 수 있음 verticalScroll() Modifier를 사용하여 Column을 스크롤 가능하게 만들 수 있습니다.  하지만 아이템 갯수만큼 UI가 미리 만들어져 있기 때문에 많은 size의 아이템을 표시해야 하는 경우 성능문제가 발생할 수 있음 @Composable fun MessageList(messages: List<Message>) { Column(modifier = Modifier.verticalScroll(rememberScrollState())) { messages.forEach { message -> MessageRow(message) } } } 안드로이드 Jetpack Compose의 LazyColumn를 이용한 RecyclerView 구현은 기존 XML 방식에 비해서 코드가 간결하여 간단하게 개발할 수 있다. 또한, 아이템 간의 간격을 추가할 때도 Arrangement.spacedBy() 함수를 통해 설정할 수 있으며 별도의 Adapter 클래스가 필요하지 않은 것도 편하게 느껴집니다. RecyclerView를 만들기 위해선 ViewHolder, Adapter 클래스도 만들어주고 또 xml에서 각 아이템의 레이아웃도 만들어줘야하고 할 게 굉장히 많았는데, Compose의 LazyColumn, LazyRow를 이용해서 구현하니 비교도 안될 정도로 간단하게 구현할 수 있었다. LazyColumn, LazyRow는 기존의 RecyclerView와 동일하게 리스트에 속한 모든 View를 한번에 그리지 않고 스크롤하면서 화면에 보여지게 될 때만 그리게 함으로써 리소스 사

Jetpack Compose BackHandler (= onBackPressed) 뒤로가기

안드로이드에서 기존에 뒤로가기 버튼을 눌렀을 때 동작을 커스텀하려면 onBackPressed() 메소드를 오버라이딩 해야 한다. Jetpack Compose 에서는 어떻게 구현해야 할까? BackHandler 라는 내장함수를 사용하면 된다. BackHandler의 enabled 프로퍼티는 BackHandler를 활성화할지 여부를 결정한다.(기본값은 true) BackHandler를 사용하여 다음과 같은 작업을 수행할수 있다. - 뒤로가기 버튼을 사용하여 이전화면으로 돌아가기 / 종료하기 - 뒤로가기 버튼을 사용하여 작업을 취소하기 - 뒤로가기 버튼을 사용하여 특정 기능을 활성화 또는 비활성화 하기 BackHandler(enabled = true, onBack= {     // 뒤로가기 버튼이 눌렸을때 수행할 작업을 정의     ... }) // 뒤로가기 두 번 눌렀을 때 앱 종료 @Composable fun BackOnPressed() { val context = LocalContext.current var backPressedState by remember { mutableStateOf(true) } var backPressedTime = 0L BackHandler(enabled = backPressedState) { if(System.currentTimeMillis() - backPressedTime <= 400L) { // 앱 종료 (context as Activity).finish() } else { backPressedState = true Toast.makeText(context, "한 번 더 누르시면 앱이 종료됩니다.", Toast.LENGTH_SHORT).show() } backPressedTime = System.currentTimeMillis()

Jetpack Compose Scaffold

 본 게시글은 Material3를 기준으로 작성되었습니다. Scaffold Material Design에서 사용되는 Composable function으로 다양한 구성요소와 기타 화면 요소를 제공합니다. Material Design 가이드라인을 따르며, 앱의 상단 앱바, 하단 탐색 막대, 콘텐츠 영역 등을 설정할 수 있습니다. Scaffold 구성 요소 TopAppBar 상단 앱바는 앱의 제목, 액션 버튼, 메뉴 등을 표시할 수 있는 영역입니다. TopAppBar를 사용하여 앱바의 콘텐츠와 동작을 정의할 수 있습니다. BottomAppBar 하단 탐색 막대는 일반적으로 탐색 메뉴나 액션 버튼을 표시하는 데 사용됩니다. BottomAppBar를 사용하여 하단 막대의 콘텐츠와 동작을 정의할 수 있습니다. FloatingActionButton 부동 액션 버튼은 일반적으로 앱에서 가장 중요한 작업을 표시하기 위해 사용됩니다. FloatingActionButton을 사용하여 부동 액션 버튼의 모양과 동작을 정의할 수 있습니다. Content 콘텐츠 영역은 앱의 주요 내용을 표시하는 영역입니다. Content를 사용하여 콘텐츠 영역을 정의할 수 있으며, 보통은 Column이나 Row와 같은 다른 컴포넌트를 사용하여 구성합니다. [Error] **Content padding parameter it is not used** 만약 Scaffold의 구성요소로 content{ } 부분에 에러가 발생하실 수 있습니다. Compose 1.2.0부터는 Scaffold 내의 content에 padding value를 적용해야 합니다. * floatingActionButtonPosition - floating버튼의 위치를 지정할 수 있습니다. 가능한 위치는 Center와 End입니다. * isFloatingActionButtonDocked - floating버튼을 BottomBar의 중간에 걸치고자 한다면 true 값을, 아니면 false값을 사용하시면 됩니다. * navigationI