
https://developer.android.com/develop/ui/views/launch/splash-screen?hl=ko
애플리케이션을 실행하면 로고를 보여주고 지정된 시간이 지나면 사라지는 화면
안드로이드 12 출시 이후 구글에서 Splash screen 라이브러리를 제공해줌
최소버전이 12이하인 프로젝트라면 Splash screen 구성은 필수임
정적 이미지와 애니메이션 이미지 사용 가능, 애니메이션 이미지는 GIF 파일 활용
dependencies에 implementation("androidx.core:core-splashscreen:1.0.1") 추가
// build.gradle.kts
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.core:core-splashscreen:1.0.1")
}
사용할 아이콘으로 이미지 에셋 추가


Next를 눌러 이미지 에셋을 만들면 폴더에서 확인 가능하다


themes.xml에 Splash Screen 테마를 구성한다.

themes.xml에 작성
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.AndroidProject4BoardApp" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
<style name="Theme.AndroidProject4BoardApp" parent="Base.Theme.AndroidProject4BoardApp" />
<!-- Splash Screen Theme -->
<style name="AppTheme.Starting" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/ic_logo_background</item>
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_logo</item>
<item name="windowSplashScreenAnimationDuration">1000</item>
<item name="postSplashScreenTheme">@style/Theme.AndroidProject4BoardApp</item>
</style>
</resources>
AppTheme.Starting 테마로 시작해서 1000ms 시간이 지난 후 다시 원래 @style/Theme.AndroidProject4BoardApp 테마로 돌아온다.
AndroidManifest.xml에서 설정된 테마를 AppTheme.Starting로 변경한다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Starting"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.kt에서 스플래시 스크린이 나타나게 한다.
// MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 스플래시 스크린이 나타나게 한다.
// 반드시 setContentView 전에 해야 한다.
// 코틀린에서는 installSplashScreen 메서드가 구현이 되어있어 호출만 하면 된다.
installSplashScreen()
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
}
}
앱을 실행하면 잠깐의 깊고 어두운 스플래시 화면이 보여지고 메인 액티비티가 보여진다.

스플래시화면은 구글에서 권장한 사항이므로 꼭 지켜야 할 필요는 없으나 권장사항인만큼 플레이스토어 노출도에 영향이 있을 것 같다.



fun settingHobbyCheckbox(){
fragmentAddUserInfoBinding.apply {
checkBoxList.add(checkBoxHobbyExercise)
checkBoxList.add(checkBoxHobbyReading)
checkBoxList.add(checkBoxHobbyMovie)
checkBoxList.add(checkBoxHobbyCooking)
checkBoxList.add(checkBoxHobbyMusic)
checkBoxList.add(checkBoxHobbyEtc)
checkBoxHobbyTotal.setOnCheckedChangeListener { checkbox, isChecked ->
when(isChecked){
true -> {
checkBoxList.forEach {
it.isChecked = true
}
}
false -> {
checkBoxList.forEach {
it.isChecked = false
}
}
}
}
checkBoxList.forEach {
it.setOnCheckedChangeListener { button, isChecked ->
when(checkCheckBox()){
CheckboxState.ALL_CHECKED -> {
(checkBoxHobbyTotal as MaterialCheckBox).checkedState = MaterialCheckBox.STATE_CHECKED
}
CheckboxState.NOT_ALL_CHECKED -> {
(checkBoxHobbyTotal as MaterialCheckBox).checkedState = MaterialCheckBox.STATE_INDETERMINATE
}
CheckboxState.UNCHECKED -> {
(checkBoxHobbyTotal as MaterialCheckBox).checkedState = MaterialCheckBox.STATE_UNCHECKED
}
}
}
}
}
}
fun checkCheckBox():CheckboxState{
fragmentAddUserInfoBinding.apply {
val result = if(
checkBoxHobbyExercise.isChecked &&
checkBoxHobbyReading.isChecked &&
checkBoxHobbyMovie.isChecked &&
checkBoxHobbyCooking.isChecked &&
checkBoxHobbyMusic.isChecked &&
checkBoxHobbyEtc.isChecked
){
CheckboxState.ALL_CHECKED
}else if(
checkBoxHobbyExercise.isChecked ||
checkBoxHobbyReading.isChecked ||
checkBoxHobbyMovie.isChecked ||
checkBoxHobbyCooking.isChecked ||
checkBoxHobbyMusic.isChecked ||
checkBoxHobbyEtc.isChecked
){
CheckboxState.NOT_ALL_CHECKED
}else{
CheckboxState.UNCHECKED
}
return result
}
}
enum class CheckboxState{
ALL_CHECKED,
NOT_ALL_CHECKED,
UNCHECKED
}

체크박스 부분은 일부 항목을 클릭 시 "전체" 체크버튼의 상태값이 STATE_INDETERMINATE로 바뀌게 했고 모든 항목이 체크되어있다면 STATE_CHECKED로, 모든 항목이 체크되어있지 않다면 STATE_UNCHECKED로 상태값이 바뀌도록 했다.

일부 항목만 체크되어있는상태에서 "전체" 체크버튼을 누르면 모든 항목이 체크된다.
체크박스의 체크 여부는 각각의 체크 상태를 ALL_CHECKED, NOT_ALL_CHECKED, UNCHECKED로 구분하여 enum class를 만들었고 각 체크박스의체크 상태를 파악하는 메서드를 만든다음에 enum 값을 반환하도록 했다.
"전체"를 제외한 체크박스는 mutableList에 담아두고 "전체"를 클릭할 때에는 이 mutableList에서 forEach로 반복하여 체크상태를 바꿔주도록 했다.
반대로 mutableList에서 forEach로 반복하여 각각의 체크박스에 각 체크박스의 체크 상태를 파악하는 메서드를 호출하게 했다.
이전 회사에서 웹개발을 할때에는 제이쿼리를 사용하다보니 계속 체크박스를 전체로 묶어 불러오는 방식으로만 생각하려는 불상사가 벌어졌다. 덕분에 모든 체크박스 요소를 리스트에 담아 리스너를 등록하는 방식의 생각을 떠올리는데에 한참 시간이 걸렸다.
이제는 안드로이드 개발자의 사고방식으로 작업을 해야하는데 아직 멀었나보다.
리스트에 담는 방법 역시 직접 뷰 하나씩 리스트에 담아주는 과정이 필요한데 이 방법 외에도
달리 한번에 여러 뷰를 가져오는 방법이 있는지 찾아봐야겠다.
지금 생각나는 것으로는 toggleGroup과 같이 부모 뷰로 감싸서 부모로부터 접근하여 모든 자식을 가져오는 방법?이 있을 것 같다.