Group Study (2024-2025)/Android

[Android] 스타일 가이드와 디자인 패턴

c2c4 2024. 11. 13. 14:17

코어멤버분께서 만들어주신 강의자료를 공부하였습니다!

  1. 스타일 가이드
  • color
    • Material 3에서는 사용자가 목적에 맞게 사용할 수 있도록 color scheme를 제공함
    • 라이트 모드와 다크모드에 맞게 색상 지정 가능, 어떤 상황에서 어떤 색을 쓰도록 목적에 맞는 색 정의 가능
    • scheme 안에 있는 요소들
      • primary : floating action button, 버튼 색, 컴포넌트들의 배경 색
      • secondary : 필터 칩 등 덜 중요한 요소들
      • teritary : primary, secondary와 비교하면 대비되는 색으로 구성, 사용자가 터치를 했을 때 다음 ux를 유도하는 등 강조 표현으로 사용
  • color system
    • 직접 색상을 지정하여 컬러 변수를 만들 수 있다!
    import androidx.compose.ui.graphics.Color
    
    val Gray900 = Color(0xFF111111) //0xFF 뒤에 6자리는 색상 코드 의미
    val Gray800 = Color(0xFF333333)
    
    //0x -> 16진수로 표현하고 있음, FF -> 투명도 표시 (100%)
    
    val White30 = Color(0x4DFFFFFF) // 0x 뒤의 투명도를 조절해서 표현 가능하다!
    
    • 만들어둔 컬러 변수 텍스트에 적용하기
    	Text(
              modifier = Modifier.padding(16.dp),
              text = "공지사항",
              color = Gray900,  
          )
    
  •  typography
    • 폰트 사용하는 법
      • 폰트 다운로드 받기
      • res → font 폴더 생성 → 폴더 내에 폰트 파일 넣어두기
      • Type.kt에 폰트 패밀리와 사이즈 설정하기
      val Typography = Typography(
          bodyLarge = TextStyle(
              fontFamily = FontFamily.Default,
              fontWeight = FontWeight.Normal,
              fontSize = 16.sp,
              lineHeight = 24.sp,
              letterSpacing = 0.5.sp
          )
      )
      
      val pretendardBold = FontFamily(Font(R.font.pretendard_bold, FontWeight.Bold))
      val pretendardSemiBold = FontFamily(Font(R.font.pretendard_semibold, FontWeight.SemiBold))
      val pretendardRegular = FontFamily(Font(R.font.pretendard_regular, FontWeight.Normal))
      val pretendardMedium = FontFamily(Font(R.font.pretendard_medium, FontWeight.Medium))
      
      val head1Bold = TextStyle(
          fontFamily = pretendardBold,
          fontSize = 36.sp,
      )
      val head2Bold = TextStyle(
          fontFamily = pretendardBold,
          fontSize = 32.sp,
      )
      val body1Semi = TextStyle(
          fontFamily = pretendardSemiBold,
          fontSize = 20.sp,
      )
      //이렇게 폰트와 사이즈를 가지고 다양한 스타일을 만들어둘 수 있다!
      
      • 텍스트에 적용하기
      Text(
                modifier = Modifier.padding(16.dp),
                text = "공지사항",
                style = head1Bold // 폰트 지정
            )
      
       
    •  

2. 디자인 패턴

  • 다양한 안드로이드 디자인 패턴들
    • MVC (Model - View - Controller)
      • 동작 : 컨트롤러에서 사용자의 액션 확인 → 모델 업데이트 & 뷰 선택 → 뷰가 모델을 이용해 화면 나타냄
      • 단점 : 테스트 어려움, 뷰 변경 시 컨트롤러도 변경해야 함, 컨트롤러에 코드 집중되면 성능 저하, 유지 보수 어려워짐
    • MVP (Model - View - Presenter)
      • 동작 : 뷰를 통해 사용자 액션 들어옴 → 뷰가 프레젠터한테 데이터 요청 → 프레젠터는 모델한테 데이터 요청 → 모델이 프레젠터한테 데이터 반환 → 프레젠터는 뷰한테 데이터 반환
      • 단점 : 뷰와 프레젠터가 1:1로 강한 의존성, 뷰마다 프레젠터가 존재해 코드가 많아지고 유지 보수 어려워짐
    • MVVM (Model - View - ViewModel)
      • 동작 : 뷰를 통해 사용자 액션 들어옴 → 뷰가 해당 내용 뷰모델한테 전달 → 뷰모델은 모델한테 데이터 요청 → 모델이 뷰모델에 데이터 반환 → 뷰모델은 해당 데이터를 가공하여 저장
      • 장점 : 뷰 → 뷰모델 → 모델 순으로 한쪽 방향으로만 의존 관계가 있어 각 모듈별로 분리하여 개발 가능
      • 단점 : 다른 패턴에 비해 러닝 커브가 높음
    • MVI (Model - View - Intent)
      • 동작 : 사용자의 액션이 intent가 되어 모델에 전달 → 모델이 업데이트 되고 뷰에 반영됨
      • 장점 : 단방향 흐름으로 상태 관리 수월, 추적 쉬움. 사용자 액션을 세세히 나누어 관리하기 때문에 화면에서 일어나는 일 이해하기 쉬움
      • 단점 : 가장 최근에 추가된 패턴이라 자료가 많이 없음, 코드량이 많아짐

 

3. 실습 코드에 MVVM 패턴을 적용하는 과정에서 나온 개념들

  • 실습 코드의 구조
    • Model - ApiFactory, ResponseUserDto, UserService
    • View - UserScreen
    • ViewModel - MainViewModel
  • SharedViewModel : 여러 스크린에서 참조하는 뷰모델
    • 각각의 화면에 모두 MainViewModel을 파라미터로 넣어주게 됨 → MainViewModel은 SharedViewModel이다!
  • 관심사 분리
    • 각각 하나의 로직을 중점으로 다루도록 해주는 게 좋음
    • MainViewModel → 로그인 로직 + 유저 목록을 서버로부터 가져오는 로직
      • 관심사 분리 후 : MainViewModel → 로그인 로직, UserViewModel → 유저 목록 가져오는 로직
  • LiveData vs StateFlow
    • LiveData : observeAsState()
      • LiveData = 상태 저장하고 ui에서 값 상태 관찰하면서 변경될 때마다 ui 업데이트
      • observeAsState() = LiveData 관찰, 그 값을 state으로 표현
    • Flow : collectAsStateWithLifecycle()
      • Flow
        • 코루틴 라이브러리에서 제공하는 상태관리 도구
        • 주로 비동기 프로그래밍(서버 통신 로직 등) 데이터 흐름 관리 시에 사용
      • collectAsStateWithLifecycle()
        • Flow 값 수집해서 Compose State으로 변환
    • 결론 : 간단한 ui 관리에는 LiveData 사용, 서버 통신 로직에는 Flow 사용!
  • init
    • 뷰모델이 처음 초기화될 때 실행되는 코드
    • 바로 실행하고 싶은 로직을 init 함수 안에 작성하면 됨
      • 초기 데이터 설정 : 초기화 시 필요한 데이터 불러와서 livedata나 stateflow에 저장하기
      • 리소스 초기화 : 뷰모델에서 사용하는 리소스 초기화 작업 수행
    • init을 사용하지 않는다면? → LaunchedEffect로 대체 가능
    • 실습 : 유저 화면에서 유저 뷰모델을 초기화할 때마다 유저 정보를 서버에서 불러오도록 하는 데 사용

 

4. Hilt 라이브러리

  • 의존성 주입이 필요한 이유
    • 한 객체가 다른 객체를 ‘직접’ 생성해서 사용하게 되면 ‘강한 결합’ 발생
    • 유지보수와 복잡성 측면에서 여러 문제 발생 가능
  • Hilt 란
    • 안드로이드에서 의존성 주입을 간편하게 사용할 수 있도록 돕는 DI 라이브러리
      • 의존성 관리를 자동화해줌
      • 애플리케이션의 수명 주기에 맞춰 의존성 자동 관리
      • 코드 가독성 높임
    • 프로젝트를 진행하게 되면 필수적으로 사용하게 된다!
    •