[Android/Flutter 교육] 45일차

MSU·2024년 3월 4일

Android-Flutter

목록 보기
47/85
post-thumbnail

게시판 프로젝트

  • friebase 서비스(데이터 베이스(NoSQL), 저장소)
  • 회원관리
  • DrawerLayout(메뉴버튼 누르면 왼쪽에서 나타나는 메뉴)
  • BottomSheet(게시글 댓글)
  • 이미지 업로드
  • 스플래시 스크린
  • 그 외

Splash 화면

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")
}

사용할 아이콘으로 이미지 에셋 추가

  • Foreground Layer : 전면에 보이는 이미지 설정
    • Asset Type : Image, Clip art, Text 중 하나로 설정 가능
  • Background Layer : 배경 설정
    • Asset Type : Color, Image 중 하나로 설정 가능

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

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

  • windowSplashScreenBackground : SplashScreen의 배경을 설정한다. 색상값이나 이미지 등을 사용할 수 있다.
  • windowSplashScreenAnimationIcon : SplashScreen에서 사용할 아이콘을 설정한다.
  • windowSplashScreenAnimationDuration : SplashScreen을 보여줄 시간을 설정한다. 최대 1000ms
  • postSplashScreenTheme : SplashScreen을 보여주고 난 다음에 나올 화면의 테마를 설정해준다. AndroidManifest.xml에서 application 태그의 android:theme 속성에 있는 것을 설정해주면 된다.
  • windowSplashScreenBrandingImage : 로고 아래에 배치될 브랜드 이미지를 서정한다.(권장하지 않음, 안드로이드os에 따라 나오지 않을 수도 있음)

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과 같이 부모 뷰로 감싸서 부모로부터 접근하여 모든 자식을 가져오는 방법?이 있을 것 같다.

profile
안드로이드공부

0개의 댓글