본문 바로가기

전체 글

(99)
[Jetpack Compose] Clickable Ripple Effect 없애기 Android, iOS 등 모바일에서는 버튼이 눌렸다는 사실을 유저에게 알리기위해 Ripple Effect 가 존재합니다. 보통은 호숫가에 던져진 돌에 의해 파동이 일어나듯, 터치한 부분을 중심으로 원이 커져가는 형태입니다. 다만, 텍스트를 버튼 대신 사용하거나, 굳이 Ripple Effect 가 필요하지 않은 곳에는 Ripple Effect 가 없는 편이 UI적으로 더욱 좋은 경우가 있습니다. 안드로이드의 경우, XML 을 사용했을 때는 버튼 이외의 다른 View 에 지정하지 않은 Riffle 이 생성되는 경우가 적었습니다. 하지만 Compose 로 넘어오면서, Modifier.clickable { } 을 통해 클릭 이벤트를 추가해주면 자동으로 Ripple Effect 가 추가됩니다. 이를 없애는 방법..
[Jetpack Compose] ImageCropper 라이브러리 없이 구현하기 현재 진행중인 사이드 프로젝트에서는 카카오 및 구글 로그인을 사용합니다. 그러므로, 이미지를 촬영 또는 디바이스에서 불러와 이를 수정 및 등록할 수 있도록 구현해야 합니다. 당연히 유수한 ImageCropper 라이브러리가 있지만, 앱 내에서 여러 번 사용되는 기능이 아니기에 직접 구현하기로 했습니다. 단순한 기능 하나를 위해 특정 의존성을 추가하는 행위 자체가 꺼려지기도 했고, 불필요한 패키지 사이즈의 증가는 유저로 하여금 다운로드가 꺼려질 수 있기 때문입니다. 또한 UI 와 관련한 라이브러리는 가능하면 배제하자는 것이 제 주관이기도 합니다. Tl ; DR 소스 코드는 제 깃허브에서 보실 수 있습니다. GitHub - jangjh123/Jetpack-Compose-CustomView: Jetpack C..
[Jetpack Compose] 상태 호이스팅 기존 XML 방식에는 큰 문제점이 하나 있었는데, 그것은 바로 View 가 스스로의 상태를 정의하고 보존한다는 것입니다. 상태는 View 를 그 자체로 인식할 수 없도록 하며, 이는 곧 테스트 가능성과 재사용성을 저해하는 원인이 됩니다. State Hoisting Jetpack Compose 를 활용하여 UI 를 작성할 때에 사용할 수 있는 패턴입니다. Composable 은 XML 방식의 View 와 다르게, 그 자체로는 Stateless 상태입니다. 얼마든 재사용할 수 있고, 얼마든 테스트할 수 있습니다. 다만, Composable 이 특정한 상태가 부여되거나 특정 상황에 결속되는 경우가 있습니다. 전자는 TextField, Scrollable 한 Composable 이 해당하고, 후자의 경우 클릭 ..
[Jetpack Compose] LazyColumn/LazyRow/Pager OverScrollEffect 없애기. 개발중인 앱에서 HorizontalPager(LazyColumn, LazyRow, VerticalPager 모두 해당 됩니다.) 를 사용중인데, OverScrollEffect 가 적용되어 있어, Fancy 하지 못한 느낌을 줍니다. CompositionLocalProvider(LocalOverscrollConfiguration.provides(null)) { // Composable } 사용하고자 하는 Composable 을 위 CompositonLocalProvider 블록으로 감싸주면 됩니다. 주의할 점은, 여전히 체험판이기에 @OptIn Annotation 이 필요합니다. @OptIn(ExperimentalPagerApi::class, ExperimentalFoundationApi::class) C..
by 를 사용한 Kotlin 의 Delegation Pattern 안드로이드 개발을 하다보면 iOS 에서의 코드를 봐야하는 경우가 종종 있습니다. iOS 에서의 개발은 화면간의 데이터 공유 및 액션을 위해 Delegation Pattern 을 사용합니다. 제가 알고 있는 코틀린에서의 Delegation 은 늦은 초기화를 위한 by lazy 와 by viewModels() 정도가 거의 전부였기에 코틀린의 Delegation 을 알아보고 싶었습니다.. 먼저, 상속과 조합. Delegation Pattern 에 대해 파악하는 과정 중 유난히 많이 접한 것은 is-A 와 has-A 관계입니다. is-A 관계 is-A 는 상속을 의미합니다. 예를 들자면 Developer is Job, Tiger is Animal 정도가 있겠습니다. 클래스가 임의의 클래스를 상속하게 되면, 클래..
확장 함수 간단 정리 코틀린은 클래스 상속이나 데코레이터 패턴 등을 사용하지 않고도 클래스나 인터페이스를 확장하는 기능을 제공합니다. 이를 확장 함수라 이릅니다. 사용법이 간단해서 여기 저기 써먹기 좋습니다. 기본적인 사용법은 다음과 같습니다. fun Int.multiplier(parameter: Int) : Int { return this * parameter } 정수값에 multiplier(n) 메서드를 호출하면 해당 정수값 x n 해주는 함수입니다. fun main() { 12.multiplier(3) } // Console System.out: 36 제가 직접 사용중인 예제는 아래와 같습니다. private fun ArrayList?.addIfExists(text: String) { this.let { it?.add(..
ViewModel 의 illegalStateException: Can not perform this action after onSaveInstanceState 앱 리팩토링 중 만나게 된 예외입니다. 위치 서비스 권한을 획득하기 위해 Callback 을 두고 Intent 로 위치 서비스 설정 창으로 이동합니다. 위치 서비스를 사용하도록 설정한 뒤 돌아와 즉시 ViewModel 을 참조하니 발생한 에러입니다. java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState onSaveInstanceState() 이후에 해당 액션을 진행할 수 없다고 나옵니다. 이는 안드로이드 액티비티의 생명주기와 관련한 예외입니다. onSaveInstanceState() 에 액티비티에서 참조가 남아있는 객체들을 저장합니다. onSaveInstanceState() 는 onStop() 과 onD..
ChannelFlow, CallbackFlow 제대로 알기 ChannelFlow ProducerScope 를 통해 빌더 코드 블록에 sendChannel 이 제공됩니다. 해당 Channel 로 보내지는 원소들로 Cold Flow 인스턴스를 생성, 이를 반환합니다. 서로 다른 Context 나 동시에 실행되는 코드에서 요소를 방출합니다. 해당 빌더는 Thread Safe 이므로, 다른 Context 에서 동시에 사용될 수 있습니다. 기본적인 용법은 다음과 같습니다. CoroutineScope(Dispatchers.Default).launch { channelFlow { CoroutineScope(Dispatchers.IO).launch { send(3) // 네트워킹 } CoroutineScope(Dispatchers.IO).launch { send(5) // 로..