티스토리 뷰
레파지토리 전략
main: 프로젝트의 최신 안정 버전을 유지하는 브랜치
dev: 프로젝트의 개발이 이루어지는 브랜치
dev 브랜치에서 기능 구현, 버그 수정, UX 개선 등의 작업을 진행하고,
기능 개발이 완료 되었다면 dev 브랜치를 main 브랜치에 병합한다.
main 브랜치는 프로젝트 백업 및 앱 배포를 진행하는데 사용되는 브랜치이다.
폴더 구조
com.hamond.escapeanchovy/ (패키지명)
│
├── constants/: 전역적으로 사용할 상수들 모음
│
├── data/: 애플리케이션의 데이터 로직 및 API 호출 처리
│ ├── model/: 데이터 모델
│ ├── repository/: 데이터 관련 로직
│ │ └── ex/ (예시)
│ │ ├── ExRepository: 레파지토리 인터페이스
│ │ ├── ExRepositoryImpl: 레파지토리 구현체
│ │ └── ExRepositoryMoudle: 레파지토리 모듈
│ ├── source/:
│ ├── local: 로컬 저장소와의 상호작용 담당
│ └── remote: 원격 서버와의 통신 관리
│
├── presentation/: 사용자에게 보여지는 부분
│ ├── preview/: 미리보기 화면
│ ├── ui/: UI 관련
│ │ ├── components/: 공통적으로 사용될 위젯
│ │ ├── screens/: 앱 화면
│ │ └── state/: 각 화면의 상태
│ └── viewmodel/: 각 화면의 뷰모델
│
├── ui.theme/:
│ ├── Color: 테마별 색상
│ ├── Theme: 앱 테마
│ └── Type: 텍스트 스타일
│
├── utils/: 전역적으로 사용할 유틸리티 함수 모음
│
├── MainActivity: MainActivity 및 내비게이션 설정
└── MyApplication: Hilt 초기화
Compose, MVVM, Respoistory, Hilt를 사용할 것이기에 폴더구조를 이런식으로 짰다.
폰트 시스템 정의
res/font에 사용할 폰트들을 추가한다.
오픈 타입 폰트(otf)가 디자인 자유도가 높다해서 이걸로 추가해줬다.
private val pretendard = FontFamily(
Font(R.font.pretendard_regular, FontWeight.Normal),
Font(R.font.pretendard_medium, FontWeight.Medium),
Font(R.font.pretendard_bold, FontWeight.Bold)
)
data class CustomTypography(
val h1Bold: TextStyle = TextStyle(
fontFamily = pretendard,
fontWeight = FontWeight.Bold,
fontSize = 28.sp,
lineHeight = 38.sp,
),
val h1Medium: TextStyle = TextStyle(
fontFamily = pretendard,
fontWeight = FontWeight.Medium,
fontSize = 28.sp,
lineHeight = 38.sp,
),
val h1Regular: TextStyle = TextStyle(
fontFamily = pretendard,
fontWeight = FontWeight.Normal,
fontSize = 28.sp,
lineHeight = 38.sp,
)
...
)
ui.Theme/Type.kt에 폰트 스타일을 정의한다.
컬러 시스템 정의
private val DarkColorPalette = darkColors(
primary = PrimaryDark,
secondary = SecondaryDark,
...
)
private val LightColorPalette = lightColors(
primary = Primary,
secondaryVariant = Secondary
)
기존 방식으로 테마별 색상을 지정하려면 컬러 팔레트를 활용해야 하는데
이걸 활용하면 색 이름을 내가 원하는대로 지정할 수 없다는 문제점이 있다.
class CustomColorScheme(
background: Color,
...
) {
var background by mutableStateOf(background)
private set
...
}
val customLightColorScheme by lazy {
CustomColorScheme(
background = Color(0xFFF9F9F9),
...
)
}
val customDarkColorScheme by lazy {
CustomColorScheme(
background = Color(0xFF222329),
...
)
}
그래서 ColorScheme 클래스를 선언하고 테마별 색상을 정의해줬다.
디자인 패턴 사용 설정
테마 파일에 정의한 디자인 패턴을 사용할 수 있도록 설정할 것이다.
// CompositionLocal 객체를 생성해 정의한 색상 및 글꼴을 앱 전체에 제공
val LocalColorScheme = staticCompositionLocalOf { customLightColorScheme }
val LocalTypography = staticCompositionLocalOf { CustomTypography() }
@Composable
fun EscapeAnchovyTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
// 정의한 글꼴 데이터 클래스
val typography = CustomTypography()
// 테마별 색상 스키마 클래스
val currentColor = remember {
if (!darkTheme) {
customLightColorScheme
} else {
customDarkColorScheme
}
}
// CompositionLocal 객체 초기화
CompositionLocalProvider(
LocalColorScheme provides currentColor,
LocalTypography provides typography
) {
// 기본 텍스트 스타일 지정
ProvideTextStyle(
typography.b4Regular.copy(color = CustomTheme.colors.text),
content = content
)
}
}
// 전역적으로 사용할 수 있는 색상 및 폰트 제공 객체
object CustomTheme {
val colors: CustomColorScheme
@Composable
@ReadOnlyComposable
get() = LocalColorScheme.current
val typography: CustomTypography
@Composable
@ReadOnlyComposable
get() = LocalTypography.current
}
해당 테마는 앱에서 공통된 색상과 글꼴 스타일을 관리하고,
시스템 테마에 따라 다르게 제공할 수 있도록 해준다.
Hilt 설정
이걸 참고하여 Hilt 종속성을 프로젝트에 추가해준다.
@HiltAndroidApp
class MyApplication : Application() {
override fun onCreate() {
// 앱 시작 전 진행할 초기화 작업
}
}
어플리케이션에서 전역적으로 Hilt를 사용할 수 있도록 설정한다.
Compose Navigation
dependencies {
...
implementation("androidx.navigation:navigation-compose:2.7.5")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
}
앱 수준 그래들 파일에 해당 라이브러리를 추가한다.
object Routes {
const val LOGIN = "login"
const val SIGN_UP = "sign_up"
const val HOME = "home"
...
}
각 화면에 해당하는 루트 네임을 정의해준다.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
EscapeAnchovyTheme {
Surface(color = CustomTheme.colors.background) {
MyApp()
}
}
}
}
}
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = LOGIN
) {
composable(route = LOGIN) { LoginScreen(navController) }
composable(route = SIGN_UP) { SignUpScreen(navController) }
composable(route = HOME) { HomeScreen(navController) }
...
}
}
NavHost를 사용하여 루트 네임에 따른 내비게이션을 지정한다.
한 곳에서 선언된 NavController를 사용하는 이유
NavController는 네비게이션의 상태(백 스택, 현재 경로 등)를 관리하는 객체이다.
위와 같이 한 곳에서 NavController 선언하고 다른 화면에 이를 전달하는 방식을
사용하면 모든 화면이 동일한 네비게이션 상태를 참조하게 된다.
만약 NavController를 각 화면에서 새로 선언하게 되면 화면마다 독립적인
NavController가 생겨 네비게이션 상태가 공유되지 않는다.
'멸치탈출 > 개발일지' 카테고리의 다른 글
Compose 로그인 화면 구현 (구글, 카카오, 네이버 소셜 로그인) (0) | 2024.11.11 |
---|---|
Compose 커스텀 위젯 만들기 (1) | 2024.11.10 |
안드로이드 개인 프로젝트 구상 (기술적 의사 결정) (6) | 2024.10.29 |