- 보통 버튼이나 FAB 클릭하면 명암이 짙어지는 Ripple 효과가 발생하는 것을 볼 수 있다. - 이번엔 Text를 가진 상위 컴포저블로부터 onClick 이벤트를 받아 하위 Text의 굵기를 변경하는 작업을 진행했다. - 일단 아래 두 개 값이 pressed 상태를 경신하고 체크하는 기본 요소가 된다.val interactionSource = remember { MutableInteractionSource() }val isPressed by interactionSource.collectIsPressedAsState() - MutableInteractionSource : InteractionSource는 컴포넌트에서 발생하는 사용자 상호작용을 감지하는 채널로서 Pressed, Focused, Drag..
전체 글
AI가 답을 알고 있어도, 우리는 '왜'인지 알아야 합니다.- 자사 구글 인앱 결제 모듈을 작년 초인가에 리팩토링 했던 기억이 난다. - 특별한 문제없이 정상 서비스되고 있었는데, 저번주 앱 심사에서 갑자기 거절당했다. 이유를 살펴보니 가격이 명시되어야 하는 UI에 Free라고 기입되어 실제 구글 결제 UI에서 나오는 가격과 다르다는 이야기였다; - 상단 이미지가 인앱 Text인데, 똑같은 수량의 달러 표시가 아니다. - Free 부분을 원래 인앱 결제 모듈에서 제공하는 ProductDetails를 통해 자사에서 지정한 가격을 실제 각 국가별 통화, 환율에 맞게 내려주는 것인데 재현은 안되지만 정황을 봤을 때 그 값이 Free라는 String으로 내려오는 것으로 보인다. (또는 0 이거나) - 따라서 가격을 찾는 코드를 아래와 같이 수정했다.val value =..

- 상위 컴포저블로 Surface를 활용한 컴포넌트에 알파 값이 적용된 컬러를 적용했더니 아래처럼 색상이 깨지는 문제가 발생했다.Surface( modifier = Modifier .height(size.value) .clip(RoundedCornerShape(dimensionResource(R.dimen.corner_radius_06))) .tbRipple { onClick.invoke() }, color = if (isDisabled) colorResource(R.color.color_system_fill_disabled_light) else colorResource(appearance.color), contentColor = colorResour..

- 기존에 아래와 같은 Vertical Grid Composable을 사용하고 있었다.LazyVerticalGrid( columns = GridCells.Fixed(2), contentPadding = PaddingValues(8.dp), modifier = Modifier.fillMaxSize()) { items(filteredList) { item -> MemoItemView(item, onClick = { selectedMemo = item coroutineScope.launch { sheetState.show() } }, onEdit = { onEdit.invoke(it) }, o..

- 기본적인 반복문과 print 방법void main() { for (var i = 0; i - Dart의 기본 변수 선언- 타입 추론이 가능하다.void main() { String name = "이승용"; int age = 30; //타입 추론 var title = "Dart"; print("$name $age $title"); bool isTrue = false; double tall = 176.5;} - Dynamic Type을 통해 모든 데이터 타입 처리가 가능하다.//dynamic type : 모든 데이터 타입을 포함할 수 있는 특수 타입dynamic car = 'Car';car = 12345; - Null Safety//Null SafetyString? name = nul..
- Hilt를 기반으로 Network Module을 만들고, Retrofit provide 함수를 생성했을 때, 다음과 같이 baseUrl을 고정해 놓았었다.@Singleton@Providesfun provideRetrofit( okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() .client(okHttpClient) .baseUrl(ServerStatus.API_URL_PRFIX) .addConverterFactory(GsonConverterFactory.create()) .build()} - 하지만 가끔 다른 Base URL을 요구하는 api를 사용해야 하는 경우도 있다. -..
- 이전에 Image 컴포저블을 활용하여 중첩된 원형 프로필 이미지를 구현했었다. - 하지만 프로필 이미지가 기본 drawable이 아니고, File이나 네트워크로부터 수신받아야 하는 경우가 있다. - 이 경우에 Coil의 AsyncImage를 활용하여 보여주도록 처리했다.//A composable that executes an ImageRequest asynchronously and renders the result.@Composablefun AsyncImage( model: Any?, contentDescription: String?, modifier: Modifier = Modifier, transform: (State) -> State = DefaultTransform, ..

- 이미지를 중첩시키고 싶다면 Box 컴포저블을 사용하면 된다. Z 축으로 쌓이는 컨테이너 구조이다. - Image 말고 다른 컴포저블들도 중첩된다.@Composablefun Avatar(~~) { Box( modifier = Modifier.wrapContentSize() ) { Image(~~~) Image( painter = painterResource(id = R.drawable.abc), contentDescription = "Profile", modifier = Modifier .size(size.dp) .padding(3.5.dp) ..

- 기존 내 서비스에서 구성되어 있던 API 호출 구조는 매번 Api Task Class를 만들어 Base를 통해 Retrofit 객체를 생성하고 호출하는 과정이었다.- 각종 초기화 및 고정 Header 값 추가 등의 코드가 난잡하게 구성되어 있어 가독성 및 관리에 좋지 않았다. - 의존성 자동 주입을 위해 Hilt와 이참에 MVVM 패턴까지 적용해 봤다.Network Module- 일단 기존에는 Api Task Class 내부에 매번 API 인터페이스를 다르게 생성했는데, 전반적인 모든 API func을 담을 ApiService를 구성했다.interface ApiService { @GET("api/test") suspend fun getTest( @Query("zoneId") z..
- Hilt 기반으로 Network Module을 구성했는데, 갑자기 제목과 같은 오류가 발생했다. - 다음 함수가 문제였다.@Provides@Singletonfun provideApiService(retrofit: Retrofit, service: Class): T = retrofit.create(service)- Hilt는 DI 그래프를 컴파일 타임에 생성하기 때문에, 어떤 타입을 주입할지 명확히알아야 한다.그런데 위처럼 로 제네릭을 쓰면 어떤 타입인지 컴파일 시점에 알 수 없기 때문에 에러가 발생한 것. - 아래처럼 Api 호출 관련 함수가 하나로 정리된 Interface를 지정해 주면 된다.@Provides@Singletonfun provideApiService(retrofit: Retro..