[Android/Flutter 교육] 44일차

MSU·2024년 2월 29일

Android-Flutter

목록 보기
46/85
post-thumbnail

메모 프로젝트 2일차

MainFragment 화면 기능 구현1

메뉴에 따라 메뉴아이콘 숨기기

// MainFragment.kt

    // 툴바 구성
    fun settingToolbar(){
        fragmentMainBinding.apply {
            toolbarMain.apply {
                // 타이틀
                title = "메모"
                // 메뉴
                inflateMenu(R.menu.main_menu)

                // 상단 메뉴 중에 일자별 보기 메뉴는 보이지 않게 한다.
                menu.findItem(R.id.menuItemMainCalendar).isVisible = false

                // 메뉴의 항목을 눌렀을 때.
                setOnMenuItemClickListener {
                    // 메뉴의 항목 id로 분기한다.
                    when(it.itemId){
                        // 일자별 항목 보기 메뉴
                        R.id.menuItemMainCalendar -> {
                            // 일자별 항목 보기 메뉴를 숨긴다
                            menu.findItem(R.id.menuItemMainCalendar).isVisible = false
                            // 전체 메모 보기 메뉴를 보이게 한다
                            menu.findItem(R.id.menuItemMainShowAll).isVisible = true
                            replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
                        }
                        // 전체 메모 보기 메뉴
                        R.id.menuItemMainShowAll -> {
                            // 일자별 항목 보기 메뉴를 보이게 한다
                            menu.findItem(R.id.menuItemMainCalendar).isVisible = true
                            // 전체 메모 보기 메뉴를 숨긴다
                            menu.findItem(R.id.menuItemMainShowAll).isVisible = false
                            replaceFragment(MainSubFragmentName.SHOW_ALL_FRAGMENT, false, false, null)
                        }
                        // 추가
                        R.id.menuItemMainAdd -> {
                            // 메모를 추가하는 화면이 보이게 한다.
                            mainActivity.replaceFragment(FragmentName.MEMO_ADD_FRAGMENT, true, true, null)
                        }
                    }
                    true
                }

CalendarFragment 화면 기능 구현

CalendarView 오늘 날짜 이동하기

1970-1-1 유닉스타임 참고
https://steemit.com/kr/@ai1love/2038

유닉스는 1960년대 인류가 만든 최초의 컴퓨터 OS

당시 최초의 하드디스크 용량은 4mb였음
년, 월, 일, 시, 분, 초, ms = 총 7개의 기억장소 * 4byte = 28byte가 필요

1970년 1월 1일 0시 0분 0초 0ms 국제표준시 -> 값을 0으로 잡고 1ms(천분의일초)마다 1씩 증가/감소
대략 최대 2억9천만년까지 계산 가능

컴퓨터는 1970년 1월 1일 0시 0분 0초 0ms를 0으로 정한 시간값을 관리한다.
컴퓨터 입장에서 시간을 관리하기 위해 Date클래스를 만들었고
사람 입장에서 시간을 관리하기 위해 Calendar클래스를 만들어놓음

캘린더 날짜의 기본 maxdate는 2100년 12월 31일로 정해져있음
최대 580만년까지 표현 가능하다.

// CalendarFragment.kt
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        fragmentCalendarBinding = FragmentCalendarBinding.inflate(inflater)
        mainActivity = activity as MainActivity

        settingRecyclerMain()
        settingButtonMainToday()

        return fragmentCalendarBinding.root
    }

    // 오늘 버튼 설정
    fun settingButtonMainToday(){
        fragmentCalendarBinding.apply {
            buttonMainToday.setOnClickListener {
                // 현재 시간을 Long값으로 구해 CalendarView에 설정해준다.
                // currentTimeMillis 메서드를 호출한 시점의 값을 Long타입으로 반환해준다.
                calendarMain.date = System.currentTimeMillis()
            }
        }
    }

리사이클러뷰 항목 클릭 시 애니메이션 효과

row_calendar.xml의 최상위 레이아웃의 background 속성으로 android:background="?android:attr/selectableItemBackground" 추가

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="?android:attr/selectableItemBackground"
    android:padding="10dp">

ShowAllFragment 화면 기능 구현

리사이클러뷰 항목 클릭 시 애니메이션 효과

row_show_all.xml의 최상위 레이아웃의 background 속성으로 android:background="?android:attr/selectableItemBackground" 추가

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="?android:attr/selectableItemBackground"
    android:padding="10dp">

MainFragment 화면 기능 구현2

뒤로가기 이동 시 이전 화면 상태 그대로 다시 보여주기

프래그먼트 간 이동을 하게되면 onCreateView가 다시 호출되기 때문에 화면이 새로 생성된다.
프래그먼트는 없어지지만 액티비티는 유지된다.
이동하기 전 마지막 화면 상태를 유지하는 개념이 아니라 복원시켜주는 개념으로 생각하기
복원시켜야 할 데이터를 액티비티에 저장해서 사용
또는 companion object를 사용하거나 다른 방법을 사용해도 된다.

// MainActivity.kt

class MainActivity : AppCompatActivity() {

    ......

    // MainFragment로 돌아올 때 복원을 위한 프로퍼티들
    // MainFragment를 통해 보여줄 Fragment 이름
    var mainSubFragmentNAme = MainSubFragmentName.CALENDAR_FRAGMENT
    // CalendarFragment에서 설정된 날짜를 담을 변수
    var calendarNowTime = System.currentTimeMillis()
    
    ......

기존에 캘린더프래그먼트로 고정시킨 값을 메인 액티비티에서 설정한 프로퍼티값을 넣는 것으로 수정한다.

// MainFragment.kt

		// 일자별 화면이 나오도록 한다.
        replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
		// MainActivity에 정의한 mainSubFragmentName 프로퍼티에 담긴 이름으로 프로퍼티를 보이게 한다.
        replaceFragment(mainActivity.mainSubFragmentNAme, false, false, null)

메뉴 항목을 클릭하면 id로 분기하는 코드에서 클릭한 메뉴에따라 메인 액티비티에서 설정한 프로퍼티에 값을 담는 것으로 수정한다.

// MainFragment.kt

                // 메뉴의 항목을 눌렀을 때.
                setOnMenuItemClickListener {
                    // 메뉴의 항목 id로 분기한다.
                    when(it.itemId){
                        // 일자별 항목 보기 메뉴
                        R.id.menuItemMainCalendar -> {
                            // 일자별 항목 보기 메뉴를 숨긴다
                            menu.findItem(R.id.menuItemMainCalendar).isVisible = false
                            // 전체 메모 보기 메뉴를 보이게 한다
                            menu.findItem(R.id.menuItemMainShowAll).isVisible = true
                            // 현재 보이고 있는 프래그먼트의 이름을 설정해준다.
                            mainActivity.mainSubFragmentNAme = MainSubFragmentName.CALENDAR_FRAGMENT

                            replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
                        }
                        // 전체 메모 보기 메뉴
                        R.id.menuItemMainShowAll -> {
                            // 일자별 항목 보기 메뉴를 보이게 한다
                            menu.findItem(R.id.menuItemMainCalendar).isVisible = true
                            // 전체 메모 보기 메뉴를 숨긴다
                            menu.findItem(R.id.menuItemMainShowAll).isVisible = false
                            // 현재 보이고 있는 프래그먼트의 이름을 설정해준다.
                            mainActivity.mainSubFragmentNAme = MainSubFragmentName.SHOW_ALL_FRAGMENT

                            replaceFragment(MainSubFragmentName.SHOW_ALL_FRAGMENT, false, false, null)
                        }
                        // 추가
                        R.id.menuItemMainAdd -> {
                            // 메모를 추가하는 화면이 보이게 한다.
                            mainActivity.replaceFragment(FragmentName.MEMO_ADD_FRAGMENT, true, true, null)
                        }
                    }
                    true
                }

하위 프래그먼트를 교체하는 메서드 작성

// MainFragment.kt

    // 하위 프래그먼트를 교체하는 메서드
    fun changeSubFragment(name:MainSubFragmentName){

        // 프래그먼트 이름으로 분기한다.
        when(name){
            // 일자별 항목 보기 화면
            MainSubFragmentName.CALENDAR_FRAGMENT -> {
                // 일자별 항목 보기 메뉴를 숨긴다
                fragmentMainBinding.toolbarMain.menu.findItem(R.id.menuItemMainCalendar).isVisible = false
                // 전체 메모 보기 메뉴를 보이게 한다
                fragmentMainBinding.toolbarMain.menu.findItem(R.id.menuItemMainShowAll).isVisible = true
            }
            // 전체 메모 보기 화면
            MainSubFragmentName.SHOW_ALL_FRAGMENT -> {
                // 일자별 항목 보기 메뉴를 보이게 한다
                fragmentMainBinding.toolbarMain.menu.findItem(R.id.menuItemMainCalendar).isVisible = true
                // 전체 메모 보기 메뉴를 숨긴다
                fragmentMainBinding.toolbarMain.menu.findItem(R.id.menuItemMainShowAll).isVisible = false
            }
        }

        // 현재 보이고 있는 프래그먼트의 이름을 설정해준다.
        mainActivity.mainSubFragmentNAme = name
        replaceFragment(name, false, false, null)
    }

앞서 수정한 메뉴 항목을 클릭하면 id로 분기하는 코드를 작성한 메서드로 교체해준다.

// MainFragment.kt

				// 메뉴의 항목을 눌렀을 때.
                setOnMenuItemClickListener {
                    // 메뉴의 항목 id로 분기한다.
                    when(it.itemId){
                        // 일자별 항목 보기 메뉴
                        R.id.menuItemMainCalendar -> {
                            // 일자별 항목 보기 화면이 보이게 한다.
                            changeSubFragment(MainSubFragmentName.CALENDAR_FRAGMENT)
                        }
                        // 전체 메모 보기 메뉴
                        R.id.menuItemMainShowAll -> {
                            // 전체 메모 보기 화면이 보이게 한다.
                            changeSubFragment(MainSubFragmentName.SHOW_ALL_FRAGMENT)
                        }
                        // 추가
                        R.id.menuItemMainAdd -> {
                            // 메모를 추가하는 화면이 보이게 한다.
                            mainActivity.replaceFragment(FragmentName.MEMO_ADD_FRAGMENT, true, true, null)
                        }
                    }
                    true
                }

상단 메뉴에 일자별 보기메뉴 보이지않게 하는 코드 부분은 삭제한다.

// 상단 메뉴 중에 일자별 보기 메뉴는 보이지 않게 한다.
menu.findItem(R.id.menuItemMainCalendar).isVisible = false

onCreateView에서 호출하는 replaceFragment 메서드를

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        fragmentMainBinding = FragmentMainBinding.inflate(inflater)
        mainActivity = activity as MainActivity

        settingToolbar()
        
		// MainActivity에 정의한 mainSubFragmentName 프로퍼티에 담긴 이름으로 프로퍼티를 보이게 한다.
        replaceFragment(mainActivity.mainSubFragmentNAme, false, false, null)
        

        return fragmentMainBinding.root
    }

changeSubFragment로 교체한다.

        // MainActivity에 정의한 mainSubFragmentName 프로퍼티에 담긴 이름으로 프로퍼티를 보이게 한다.
        changeSubFragment(mainActivity.mainSubFragmentNAme)

뒤로가기 이동 시 이전 화면에서 선택한 캘린더 날짜 유지하기

CalendarFragment에서 캘린더 설정 메서드를 작성

// CalendarFragment.kt


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        fragmentCalendarBinding = FragmentCalendarBinding.inflate(inflater)
        mainActivity = activity as MainActivity

        settingRecyclerMain()
        settingButtonMainToday()
        settingCalendarMain()

        return fragmentCalendarBinding.root
    }
    

    // 캘린더 설정
    fun settingCalendarMain(){
        fragmentCalendarBinding.apply {
            calendarMain.apply {
                // 캘린더의 날짜를 MainActivity의 프로퍼티 값으로 지정한다.
                date = mainActivity.calendarNowTime
                // 캘린더의 최대 날짜를 오늘로 설정한다.
                maxDate = System.currentTimeMillis()
                
                // 캘린더 뷰의 날짜가 변경되면 동작하는 리스너
                // 두번째, 세번째, 네번째 : 설정된 년도, 월, 일
                setOnDateChangeListener { view, year, month, dayOfMonth ->
                    // 캘린더의 현재 날짜 값을 MainActivity의 프로퍼티로 넣어준다.
                    // 년월일값을 Long 날짜값으로 변경한다.
                    // 날짜 데이터를 관리하는 객체를 생성하고 새롭게 설정된 날짜 값을 넣어준다.
                    val c1 = Calendar.getInstance()
                    c1.set(year, month, dayOfMonth)
                    // 설정된 날짜값을 Long 형태의 시간값으로 가져와 담아준다.
                    mainActivity.calendarNowTime = c1.timeInMillis
                }
            }
        }
    }

maxDate프로퍼티를 오늘로 설정해주면 오늘 이후로는 날짜를 선택할 수 없다.

오늘 버튼 메서드에도 메인액티비티의 프로퍼티에 값을 넣어주는 코드를 추가해준다.

// CalendarFragment.kt

    // 오늘 버튼 설정
    fun settingButtonMainToday(){
        fragmentCalendarBinding.apply {
            buttonMainToday.setOnClickListener {
                // 현재 시간을 Long값으로 구해 CalendarView에 설정해준다.
                // currentTimeMillis 메서드를 호출한 시점의 값을 Long타입으로 반환해준다.
                calendarMain.date = System.currentTimeMillis()
                // MainActivity의 프로퍼티에 넣어준다.
                mainActivity.calendarNowTime = calendarMain.date
            }
        }
    }

달력 날짜를 변경하고 다른 프래그먼트로 이동했다가

다시 캘린더 프래그먼트로 돌아오면 변경된 날짜로 남아있다.

MemoAddFragment 화면 기능 구현

메모 제목에 자동으로 포커스 주기

MainActivity에 뷰에 포커스를 주고 키보드를 올리는 메서드 작성

// MainActivity.kt

    // 뷰에 포커스를 주고 키보드를 올린다.
    fun showSoftInput(view: View){
        // 뷰에 포커스를 준다.
        view.requestFocus()
        thread {
            //딜레이를 준다.
            SystemClock.sleep(200)
            // 키보드 관리 객체를 가져온다.
            val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
            // 키보드를 올린다.
            inputMethodManager.showSoftInput(view, 0)
        }
    }

MainActivity에 키보드를 내려주고 포커스를 제거하는 메서드 작성

// MainActivity.kt

    // 키보드를 내려주고 포커스를 제거한다.
    fun hideSoftInput(){
        // 포커스를 갖고 있는 view가 있다면 (키보드가 올라온 상태)
        if(window.currentFocus != null){
            // 키보드 관리 객체를 가져온다.
            val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
            // 키보드를 내려준다.
            inputMethodManager.hideSoftInputFromWindow(window.currentFocus?.windowToken,0)
            // 포커스를 제거해준다.
            window.currentFocus?.clearFocus()
        }
    }

MemoAddFragment에 입력 요소 설정하는 메서드 작성

// MemoAddFragment.kt

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        fragmentMemoAddBinding = FragmentMemoAddBinding.inflate(inflater)
        mainActivity = activity as MainActivity

        settingToolbar()
        settingTextField()

        return fragmentMemoAddBinding.root
    }

    // 입력 요소들 설정
    fun settingTextField(){
        fragmentMemoAddBinding.apply {
            // 첫 번째 입력 요소에 포커스를 준다.
            mainActivity.showSoftInput(textFieldMemoAddSubject)
        }
    }

메모 추가 화면 이동 시 메모 제목에 포커스가 주어지고 키보드가 올라간다.

유효성 검사

textInputEditText요소가 아닌 textInputLayout에 error 처리를 해주면 된다.
textInputLayout.error = "오류가 났시유~"

textInputEditText요소에 직접 error처리를 해주면 디자인이 안좋게 보임

에러 처리를 위해 textInputLayout의 아이디가 필요하기 때문에 textInputLayout에 아이디를 부여해준다.

유효성 검사 메서드 작성

//MemoAddFragment.kt

    // 유효성 검사 메서드
    // 반환값 : true - 모두 정상적으로 잘 입력한 것, false - 입력에 문제가 있는 것
    fun checkTextFieldInput() : Boolean{
        fragmentMemoAddBinding.apply {
            // 입력하지 않은 입력 요소 중 가장 위에 있는 view를 담을 변수
            var errorView:View? = null

            // 제목
            if(textFieldMemoAddSubject.text.toString().trim().isEmpty()){
                textInputLayoutMemoAddSubject.error = "메모 제목을 입력해주세요"
                errorView = textFieldMemoAddSubject
            }else{
                textInputLayoutMemoAddSubject.error = null
            }

            // 내용
            if(textFieldMemoAddText.text.toString().trim().isEmpty()){
                textInputLayoutMemoAddText.error = "메모 내용을 입력해주세요"
                if(errorView == null){
                    errorView = textFieldMemoAddText
                }
            }else{
                textInputLayoutMemoAddText.error = null
            }

            // 비어 있는 입력 요소가 있다면
            if(errorView != null){
                // 비어 있는 입력 요소에 포커스를 준다.
                mainActivity.showSoftInput(errorView)
                // 메서드의 수행을 중지 시킨다.
                return false
            }
            return true
        }
    }

완료 버튼 클릭 리스너에 유효성 검사 메서드 호출

//MemoAddFragment.kt

    // 툴바 설정 메서드
    fun settingToolbar(){
        fragmentMemoAddBinding.apply {
            toolbarMemoAdd.apply {
                // 타이틀
                title = "메모 추가"
                // Back
                setNavigationIcon(R.drawable.arrow_back_24px)
                setNavigationOnClickListener {
                    // 현재 Fragment를 BackStack에서 제거하여 이전 화면이 보이게 한다.
                    mainActivity.removeFragment(FragmentName.MEMO_ADD_FRAGMENT)
                }
                // 메뉴
                inflateMenu(R.menu.memo_add_menu)
                setOnMenuItemClickListener {
                    when(it.itemId){
                        // 완료
                        R.id.menuItemMemoAddDone -> {
                            // 유효성 검사 메서드를 호출한다
                            checkTextFieldInput()
                        }
                    }
                    true
                }
            }
        }
    }

무언가 입력하면 에러메시지를 없애준다.

//MemoAddFragment.kt

    // 입력 요소들 설정
    fun settingTextField(){
        fragmentMemoAddBinding.apply {
            // 첫 번째 입력 요소에 포커스를 준다.
            mainActivity.showSoftInput(textFieldMemoAddSubject)

            // 에러메시지가 보여지는 상황일 때를 대비하여 무언가 입력하면 에러메시지를 없애준다.
            textFieldMemoAddSubject.addTextChangedListener {
                textInputLayoutMemoAddSubject.error = null
            }
            textFieldMemoAddText.addTextChangedListener {
                textInputLayoutMemoAddText.error = null
            }
        }
    }

에러메시지로 인해 생기는 빈공간 해결(선택사항)

초기 화면에서는 입력요소 사이의 공간이 좁았다가

에러메시지가 생기면 생긴만큼의 빈 공간이 더 생긴다

입력공백을 채우고 에러메시지를 없애도 생긴 빈 공간은 그대로 유지된다.

이런 현상이 거슬릴 경우 에러메시지 만큼의 공간을 더 확보해놓으면 된다.

    // 입력 요소들 설정
    fun settingTextField(){
        fragmentMemoAddBinding.apply {
            // 첫 번째 입력 요소에 포커스를 준다.
            mainActivity.showSoftInput(textFieldMemoAddSubject)
            
            // 에러메시지가 생긴만큼의 공백을 미리 확보
            textInputLayoutMemoAddSubject.error = " "
            textInputLayoutMemoAddText.error = " "

            textInputLayoutMemoAddSubject.error = null
            textInputLayoutMemoAddText.error = null

            // 에러메시지가 보여지는 상황일 때를 대비하여 무언가 입력하면 에러메시지를 없애준다.
            textFieldMemoAddSubject.addTextChangedListener {
                textInputLayoutMemoAddSubject.error = null
            }
            textFieldMemoAddText.addTextChangedListener {
                textInputLayoutMemoAddText.error = null
            }
        }
    }

공간이 미리 확보된 상태로 보여진다.

완료 버튼을 누르면 MemoReadFragment로 이동

유효성 검사 후 값이 true로 반환되면 MemoReadFragment로 이동

입력으로 올라온 키보드도 내려줘야 한다.

// MemoAddFragment.kt

    // 툴바 설정 메서드
    fun settingToolbar(){
        fragmentMemoAddBinding.apply {
            toolbarMemoAdd.apply {
                // 타이틀
                title = "메모 추가"
                // Back
                setNavigationIcon(R.drawable.arrow_back_24px)
                setNavigationOnClickListener {
                    // 현재 Fragment를 BackStack에서 제거하여 이전 화면이 보이게 한다.
                    mainActivity.removeFragment(FragmentName.MEMO_ADD_FRAGMENT)
                }
                // 메뉴
                inflateMenu(R.menu.memo_add_menu)
                setOnMenuItemClickListener {
                    when(it.itemId){
                        // 완료
                        R.id.menuItemMemoAddDone -> {
                            // 유효성 검사 메서드를 호출한다
                            val chk = checkTextFieldInput()
                            if(chk == true){
                                // 키보드를 내린다.
                                mainActivity.hideSoftInput()
                                // 모두 제대로 입력을 했다면 MemoReadFragment로 가게 한다.
                                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, null)
                            }
                        }
                    }
                    true
                }
            }
        }
    }

모든 입력 완료후 완료버튼 누르면

메모 보기 화면으로 이동한다.

입력 초기화 메뉴 버튼 추가

restart_alt 아이콘 파일 추가

초기화 메뉴 아이템 추가

    <item
        android:id="@+id/menuItemMemoAddReset"
        android:icon="@drawable/restart_alt_24px"
        android:title="초기화"
        app:showAsAction="always" />

초기화 버튼 클릭시 모든 입력 요소 초기화 설정

// MemoAddFragment.kt


                // 메뉴
                inflateMenu(R.menu.memo_add_menu)
                setOnMenuItemClickListener {
                    when(it.itemId){
                        // 완료
                        R.id.menuItemMemoAddDone -> {
                            // 유효성 검사 메서드를 호출한다
                            val chk = checkTextFieldInput()
                            if(chk == true){
                                // 키보드를 내린다.
                                mainActivity.hideSoftInput()
                                // 모두 제대로 입력을 했다면 MemoReadFragment로 가게 한다.
                                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, null)
                            }
                        }
                        // 초기화
                        R.id.menuItemMemoAddReset -> {
                            // 입력 요소들을 모두 초기화한다.
                            textFieldMemoAddSubject.setText("")
                            textFieldMemoAddText.setText("")
                            textInputLayoutMemoAddSubject.error = null
                            textInputLayoutMemoAddText.error = null
                            // 첫 번째 입력 요소에 포커스를 준다.
                            mainActivity.showSoftInput(textFieldMemoAddSubject)
                        }
                    }
                    true
                }

입력 내용과 에러표시 모두 초기화된다.

MemoReadFragment 화면 기능 구현

뒤로가기 버튼 수정

뒤로가기 처리 메서드 작성

MemoAddFragment에서 작성 완료 후 이동했을 경우도 대비하여 MemoAddFragment도 BackStack에서 지워주는 코드를 추가해준다.

// MemoReadFragment.kt

    // 뒤로가기 처리
    fun backProcess(){
        // 현재의 MemoReadFragment 제거
        mainActivity.removeFragment(FragmentName.MEMO_READ_FRAGMENT)
        // MemoAddFragment에서 넘어온 경우에는 MemoAddFragment도 BackStack에서 제거한다.
        mainActivity.removeFragment(FragmentName.MEMO_ADD_FRAGMENT)
    }

기존의 뒤로가기 코드를 메서드로 교체한다.

// MemoReadFragment.kt

                // Back
                setNavigationIcon(R.drawable.arrow_back_24px)
                setNavigationOnClickListener {
                    //mainActivity.removeFragment(FragmentName.MEMO_READ_FRAGMENT)
                    backProcess()
                }

메모 작성 완료후 메모 보기로 이동했을때에도

뒤로가기 버튼을 누르면 작성화면이 아니라 바로 메인프래그먼트로 돌아온다.

삭제 버튼을 누르면 삭제여부를 묻는 다이얼로그 띄우기

// MemoReadFragment.kt

                // 메뉴
                inflateMenu(R.menu.memo_read_menu)
                setOnMenuItemClickListener {
                    when(it.itemId){
                        // 수정
                        R.id.menuItemMemoReadModify -> {
                            mainActivity.replaceFragment(FragmentName.MEMO_MODIFY_FRAGMENT, true, true, null)
                        }
                        // 삭제
                        R.id.menuItemMemoReadDelete -> {
                            // 삭제를 위한 다이얼로그를 띄운다.
                            val materialAlertDialogBuilder = MaterialAlertDialogBuilder(mainActivity)
                            materialAlertDialogBuilder.setTitle("메모 삭제")
                            materialAlertDialogBuilder.setMessage("메모를 삭제하면 복구할 수 없습니다")
                            materialAlertDialogBuilder.setNegativeButton("취소", null)
                            materialAlertDialogBuilder.setPositiveButton("삭제"){ dialogInterface: DialogInterface, i: Int ->
                                // MainFragment로 돌아간다.
                                backProcess()
                            }
                            materialAlertDialogBuilder.show()
                        }
                    }
                    true
                }

MemoModifyFragment 화면 기능 구현

유효성 검사

유효성 검사를 error로 처리할 경우 모든 요소를 다 체크하여 error를 표시하지만
다이얼로그로 에러를 표시할 경우에는 처음 error요소가 확인될때 다이얼로그를 표시하고 메서드를 중단시켜도 된다.

경고 다이얼로그를 띄우는 메서드 작성

MainActivity에 메서드 작성한다.

// MainActivity.kt

    // 입력 요소가 비어있을 때 보여줄 다이얼로그를 구성하는 메서드
    fun showErrorDialog(view:View, title:String, message:String){
        val materialAlertDialogBuilder = MaterialAlertDialogBuilder(this)
        materialAlertDialogBuilder.setTitle(title)
        materialAlertDialogBuilder.setMessage(message)
        materialAlertDialogBuilder.setPositiveButton("확인"){ dialogInterface: DialogInterface, i: Int ->
            showSoftInput(view)
        }
        materialAlertDialogBuilder.show()
    }

유효성 검사 메서드 작성

// MemoModifyFragment.kt

    // 입력 요소에 대한 유효성 검사 처리
    fun checkTextField():Boolean{
        fragmentMemoModifyBinding.apply {

            // 제목이 비어있다면
            if(textFieldMemoModifySubject.text.toString().trim().isEmpty()){
                mainActivity.showErrorDialog(textFieldMemoModifySubject, "제목 입력 오류", "제목을 입력해주세요")
                return false
            }

            // 내용이 비어있다면
            if(textFieldMemoModifyText.text.toString().trim().isEmpty()){
                mainActivity.showErrorDialog(textFieldMemoModifyText, "내용 입력 오류", "내용을 입력해주세요")
                return false
            }

            return true
        }
    }

수정 완료 버튼 클릭 리스너에 유효성 검사 메서드 호출

유효성 검사 후 수정 여부를 묻는 다이얼로그를 추가로 띄우고 확인을 받아서
MemoReadFragment로 돌아가게 한다.

// MemoModifyFragment.kt

                // 메뉴
                inflateMenu(R.menu.memo_modify_menu)
                // 메뉴를 눌렀을 때
                setOnMenuItemClickListener {
                    // 메뉴의 id로 분기한다.
                    when(it.itemId){
                        R.id.menuItemMemoModifyDone -> {
                            // 유효성 검사 메서드를 호출한다.
                            val chk = checkTextField()
                            // 모든 입력 요소가 모두 입력되어 있다면 수정 여부를 묻는 다이얼로그를 띄운다.
                            if(chk==true){
                                val materialAlertDialogBuilder = MaterialAlertDialogBuilder(mainActivity)
                                materialAlertDialogBuilder.setTitle("수정 확인")
                                materialAlertDialogBuilder.setMessage("수정을 완료하면 이전 내용으로 복구할 수 없습니다.")
                                materialAlertDialogBuilder.setNegativeButton("취소",null)
                                materialAlertDialogBuilder.setPositiveButton("완료"){ dialogInterface: DialogInterface, i: Int ->
                                    // MemoReadFragment로 돌아간다.
                                    mainActivity.removeFragment(FragmentName.MEMO_MODIFY_FRAGMENT)
                                }
                                materialAlertDialogBuilder.show()
                            }
                        }
                    }
                    true
                }

입력 초기화

툴바메뉴에 초기화 버튼 추가

    <item
        android:id="@+id/menuItemMemoModifyReset"
        android:icon="@drawable/restart_alt_24px"
        android:title="초기화"
        app:showAsAction="always" />

툴바 메뉴 분기 코드에 초기화 추가

// MemoModifyFragment.kt


                // 메뉴
                inflateMenu(R.menu.memo_modify_menu)
                // 메뉴를 눌렀을 때
                setOnMenuItemClickListener {
                    // 메뉴의 id로 분기한다.
                    when(it.itemId){
                        R.id.menuItemMemoModifyDone -> {
                            // 유효성 검사 메서드를 호출한다.
                            val chk = checkTextField()
                            // 모든 입력 요소가 모두 입력되어 있다면 수정 여부를 묻는 다이얼로그를 띄운다.
                            if(chk==true){
                                val materialAlertDialogBuilder = MaterialAlertDialogBuilder(mainActivity)
                                materialAlertDialogBuilder.setTitle("수정 확인")
                                materialAlertDialogBuilder.setMessage("수정을 완료하면 이전 내용으로 복구할 수 없습니다.")
                                materialAlertDialogBuilder.setNegativeButton("취소",null)
                                materialAlertDialogBuilder.setPositiveButton("완료"){ dialogInterface: DialogInterface, i: Int ->
                                    // MemoReadFragment로 돌아간다.
                                    mainActivity.removeFragment(FragmentName.MEMO_MODIFY_FRAGMENT)
                                }
                                materialAlertDialogBuilder.show()
                            }
                        }
                        R.id.menuItemMemoModifyReset -> {
                            // 입력 요소 초기화
                            fragmentMemoModifyBinding.apply { 
                                textFieldMemoModifySubject.setText("메모 제목")
                                textFieldMemoModifyText.setText("메모 내용")
                                // 제목에 포커스를 준다.
                                mainActivity.showSoftInput(textFieldMemoModifySubject)
                            }
                        }
                    }
                    true
                }

MemoReadFragment 화면 기능 수정

fragment_memo_read.xml에서 textInput요소에 추가했던 editable 속성이 deprecated됨

기존에 추가했던 editable 속성 삭제

clickable, cursorVisible, focusable 속성 추가 후 모두 false로 설정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:transitionGroup="true"
    tools:context=".MemoReadFragment">

    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbarMemoRead"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="10dp">

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="제목">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/textFieldMemoReadSubject"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="false"
                android:cursorVisible="false"
                android:focusable="false"
                android:inputType="text" />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:hint="작성날짜">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/textFieldMemoReadDate"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="false"
                android:cursorVisible="false"
                android:focusable="false"
                android:inputType="text" />
        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:hint="내용">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/textFieldMemoReadText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="false"
                android:cursorVisible="false"
                android:focusable="false"
                android:inputType="text|textMultiLine" />
        </com.google.android.material.textfield.TextInputLayout>
    </LinearLayout>

</LinearLayout>

다시 실행하여 수정이 안되는지 확인하기

DBHelper 구현

메모 테이블 컬럼 정의

메모 번호
메모 제목
작성 날짜
메모 내용

DBHelper 클래스 작성

// DBHelper.kt

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper(context: Context) : SQLiteOpenHelper(context, "MemoDB.db", null, 1) {
    override fun onCreate(db: SQLiteDatabase?) {
        // 테이블을 만드는 쿼리문
        val sql = """
            create table MemoTable(
            memoIdx integer primary key autoincrement,
            memoSubject text not null,
            memoDate date not null,
            memoText text not null)
        """.trimIndent()

        // 쿼리 실행
        db?.execSQL(sql)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

    }

}

MemoModel 데이터 클래스 작성

// MemoModel.kt

data class MemoModel(
    var memoIdx:Int, 
    var memoSubject:String, 
    var memoDate:String, 
    var memoText:String
)

MemoDAO 작성

데이터를 저장하는 코드

// MemoDao.kt


class MemoDao {

    companion object {

        // insert
        fun insertMemoData(context: Context, memoModel: MemoModel){
            // 쿼리문
            val sql ="""
                insert into MemoTable
                (memoSubject, memoDate, memoText)
                values (?, ?, ?)
            """.trimIndent()

            // ?에 바인딩 될 값
            val args = arrayOf(memoModel.memoSubject, memoModel.memoDate, memoModel.memoText)

            // 쿼리 실행
            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.execSQL(sql, args)
            dbHelper.close()
        }
    }
}

행 하나의 데이터를 담아 반환하는 메서드

// MemoDao.kt

        // 행 하나의 데이터를 담아 반환하는 메서드
        fun getRowData(cursor: Cursor) : MemoModel{
            // 값의 순서를 가져온다.
            val idx1 = cursor.getColumnIndex("memoIdx")
            val idx2 = cursor.getColumnIndex("memoSubject")
            val idx3 = cursor.getColumnIndex("memoDate")
            val idx4 = cursor.getColumnIndex("memoText")

            // 값을 가져온다.
            val memoIdx = cursor.getInt(idx1)
            val memoSubject = cursor.getString(idx2)
            val memoDate = cursor.getString(idx3)
            val memoText = cursor.getString(idx4)
            // 객체를 담는다.
            val memoModel = MemoModel(memoIdx,memoSubject,memoDate,memoText)
            // 객체를 반환한다.
            return memoModel
        }

데이터를 모두 가져오는 메서드

// MemoDao.kt


        // select all
        fun selectMemoDataAll(context: Context) : MutableList<MemoModel>{
            // 쿼리문
            val sql = """
                select memoIdx, memoSubject, memoDate, memoText
                from MemoTable
                order by memoIdx desc
            """.trimIndent()

            // Cursor 객체를 가져온다.
            val dbHelper = DBHelper(context)
            val cursor = dbHelper.writableDatabase.rawQuery(sql, null)
            // 데이터를 담을 리스트
            val memoList = mutableListOf<MemoModel>()

            // 마지막 행까지 반복한다.
            while(cursor.moveToNext()){
                // 행 하나의 데이터를 가져온다.
                val memoModel = getRowData(cursor)
                // 리스트에 담는다.
                memoList.add(memoModel)
            }
            dbHelper.close()

            return memoList
        }

데이터를 하나만 가져오는 메서드

// MemoDao.kt


        // select one
        fun selectMemoDataOne(context: Context, memoIdx:Int) : MemoModel{
            // 쿼리문
            val sql = """
                select memoIdx, memoSubject, memoDate, memoText
                from MemoTable
                where memoIdx = ?
            """.trimIndent()

            // ?에 바인딩 될 값
            val args = arrayOf("$memoIdx")

            // 데이터를 가져온다.
            val dbHelper = DBHelper(context)
            val cursor = dbHelper.writableDatabase.rawQuery(sql, args)
            cursor.moveToNext()
            val memoModel = getRowData(cursor)
            dbHelper.close()

            return memoModel
        }

데이터를 업데이트하는 코드

// MemoDao.kt


        // update
        fun updateMemoData(context: Context, memoModel: MemoModel){
            // 쿼리문
            val sql = """
                update MemoTable
                set memoSubject = ?, memoText = ?
                where memoIdx = ?
            """.trimIndent()

            // ?에 바인딩 될 값
            val args = arrayOf(
                memoModel.memoSubject,
                memoModel.memoText,
                memoModel.memoIdx
            )

            // 쿼리 실행
            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.execSQL(sql, args)
            dbHelper.close()
        }

데이터를 삭제하는 코드

// MemoDao.kt


        // delete
        fun deleteMemoModel(context: Context, memoIdx: Int){
            // 쿼리문
            val sql = """
                delete from MemoTable
                where memoIdx = ?
            """.trimIndent()

            // ?에 바인딩 될 값
            val args = arrayOf("$memoIdx")

            // 쿼리 실행
            val dbHelper = DBHelper(context)
            dbHelper.writableDatabase.execSQL(sql, args)
            dbHelper.close()
        }

MemoAddFragment 저장 기능 구현

입력한 데이터를 저장하는 메서드

// MemoAddFragment.kt

                        // 완료
                        R.id.menuItemMemoAddDone -> {
                            // 유효성 검사 메서드를 호출한다
                            val chk = checkTextFieldInput()
                            if(chk == true){
                                // 글을 저장한다.
                                saveMemoData()
                                // 키보드를 내린다.
                                mainActivity.hideSoftInput()
                                // 모두 제대로 입력을 했다면 MemoReadFragment로 가게 한다.
                                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, null)
                            }
                        }
                        
                        

    // 입력한 데이터를 저장한다.
    fun saveMemoData(){
        fragmentMemoAddBinding.apply {
            // 입력한 문자열 데이터를 추출한다.
            val memoSubject = textFieldMemoAddSubject.text.toString().trim()
            val memoText = textFieldMemoAddText.text.toString().trim()
            // 날짜 데이터를 구한다.
            val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd")
            val memoDate = simpleDateFormat.format(Date())

            // Log.d("test1234","$memoSubject, $memoText, $memoDate")
            // 객체에 담아준다.
            val memoModel = MemoModel(0, memoSubject, memoDate, memoText)
            // 저장한다.
            MemoDao.insertMemoData(mainActivity, memoModel)
        }
    }

MemoReadFragment 메모데이터 불러오기 기능 구현

textField 내용 설정 메서드 수정

// MemoReadFragment.kt

    // textField의 내용을 설정해준다.
    fun settingTextField(){

        // 글의 인덱스 번호를 가져온다.
        val memoIdx = arguments?.getInt("memoIdx")!!

        // 현재의 글을 가져온다.
        val memoModel = MemoDao.selectMemoDataOne(mainActivity, memoIdx)

        fragmentMemoReadBinding.textFieldMemoReadSubject.setText(memoModel.memoSubject)
        fragmentMemoReadBinding.textFieldMemoReadText.setText(memoModel.memoText)
        fragmentMemoReadBinding.textFieldMemoReadDate.setText(memoModel.memoDate)
    }

가장 최근 idx를 반환하는 dao메서드 추가

메모를 추가하면 생성되는 메모객체의 idx는 데이터 중 가장 큰 idx값을 가지게 된다.
따라서 가장 값이 큰 idx를 반환하는 메서드를 만들어주면 새로 추가한 메모의 idx를 가져올 수 있다.

// MemoDao.kt

        // 가장 큰 글 번호를 반환한다.
        fun selectMaxMemoIdx(context: Context):Int{
            // 쿼리문
            val sql = """
                select max(memoIdx) from MemoTable
            """.trimIndent()

            // 데이터를 가져온다.
            val dbHelper = DBHelper(context)
            val cursor = dbHelper.writableDatabase.rawQuery(sql,null)
            cursor.moveToNext()
            val maxMemoIdx = cursor.getInt(0)
            dbHelper.close()
            return maxMemoIdx
        }

MemoAddFragment 완료 버튼 기능 수정

메모 추가를 완료할 때 추가한 메모 idx를 가져와서 번들에 담아 보낸다

// MemoAddFragment.kt

                        // 완료
                        R.id.menuItemMemoAddDone -> {
                            // 유효성 검사 메서드를 호출한다
                            val chk = checkTextFieldInput()
                            if(chk == true){
                                // 글을 저장한다.
                                saveMemoData()

                                // 키보드를 내린다.
                                mainActivity.hideSoftInput()

                                // 모두 제대로 입력을 했다면 MemoReadFragment로 가게 한다.
                                // 글 번호를 가져온다.
                                val maxMemoIdx = MemoDao.selectMaxMemoIdx(mainActivity)
                                // 번들에 담아준다.
                                val memoReadBundle = Bundle()
                                memoReadBundle.putInt("memoIdx",maxMemoIdx)
                                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, memoReadBundle)
                            }
                        }

메모를 작성하면

추가한 내용이 제대로 나온다.

리사이클러뷰 항목 수정

ShowAllFragment 리사이클러뷰

리사이클러뷰 구성을 위한 리스트를 담을 변수

// CalendarFragment.kt


class ShowAllFragment : Fragment() {

    lateinit var fragmentShowAllBinding: FragmentShowAllBinding
    lateinit var mainActivity: MainActivity

    // 리사이클러뷰 구성을 위한 리스트
    var memoList = mutableListOf<MemoModel>()

리사이클러뷰 구성 메서드 수정

// ShowAllFragment.kt


    // RecyclerView 구성 메서드
    fun settingRecyclerShowAll(){
        fragmentShowAllBinding.apply {
            recyclerShowAll.apply {
                // 데이터 베이스에서 데이터를 가져온다.
                memoList = MemoDao.selectMemoDataAll(mainActivity)
                
                // 어댑터 설정
                adapter = RecyclerShowAllAdapter()
                // 레이아웃 매니저
                layoutManager = LinearLayoutManager(mainActivity)
                // 데코
                val deco = MaterialDividerItemDecoration(mainActivity,
                    MaterialDividerItemDecoration.VERTICAL)
                addItemDecoration(deco)
            }
        }
    }
    

리사이클러뷰 어댑터 클래스 수정

// ShowAllFragment.kt

    // RecyclerView의 어댑터
    inner class RecyclerShowAllAdapter : RecyclerView.Adapter<RecyclerShowAllAdapter.RecyclerShowAllViewHolder>(){

	......

        override fun getItemCount(): Int {
            return memoList.size
        }

        override fun onBindViewHolder(holder: RecyclerShowAllViewHolder, position: Int) {
            // position 번째 객체에서 데이터를 가져와 설정해준다.
            holder.rowShowAllBinding.textShowAllSubject.text = memoList[position].memoSubject
            holder.rowShowAllBinding.textShowAllWriteDate.text = memoList[position].memoDate

            // 항목을 누르면 동작하는 리스너
            holder.rowShowAllBinding.root.setOnClickListener {
                // 메모를 보는 화면이 나타나게 한다.
                val memoReadBundle = Bundle()
                memoReadBundle.putInt("memoIdx", memoList[position].memoIdx)
                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, memoReadBundle)
            }
        }

CalendarFragment 리사이클러뷰

CalendarFragment의 경우 달력 일자를 누를때마다 해당 일자의 메모를 받아와야 한다.

MemoDao에서 지정된 날짜에 해당되는 메모를 가져오는 메서드

// MemoDao.kt

        // 지정된 날짜에 해당하는 메모 모두를 가져오는 메서드
        fun selectMemoDataDate(context: Context, memoDate:String) : MutableList<MemoModel>{
            // 쿼리문
            val sql = """
                select memoIdx, memoSubject, memoDate, memoText
                from MemoTable
                where memodate = ?
                order by memoIdx desc
            """.trimIndent()

            // ?에 바인딩 될 값
            val args = arrayOf(memoDate)

            // Cursor 객체를 가져온다.
            val dbHelper = DBHelper(context)
            val cursor = dbHelper.writableDatabase.rawQuery(sql, args)
            // 데이터를 담을 리스트
            val memoList = mutableListOf<MemoModel>()

            // 마지막 행까지 반복한다.
            while(cursor.moveToNext()){
                // 행 하나의 데이터를 가져온다.
                val memoModel = getRowData(cursor)
                // 리스트에 담는다.
                memoList.add(memoModel)
            }
            dbHelper.close()

            return memoList
        }

리사이클러뷰 구성을 위한 리스트

// CalendarFragment.kt


class CalendarFragment : Fragment() {

    lateinit var fragmentCalendarBinding: FragmentCalendarBinding
    lateinit var mainActivity: MainActivity

    // 리사이클러뷰 구성을 위한 리스트
    var memoList = mutableListOf<MemoModel>()

리사이클러뷰 어댑터 클래스 수정

// CalendarFragment.kt


    // RecyclerView의 어댑터
    inner class RecyclerMainAdapter : RecyclerView.Adapter<RecyclerMainAdapter.RecyclerMainViewHolder>(){
    	......
    
        override fun getItemCount(): Int {
            return memoList.size
        }

        override fun onBindViewHolder(holder: RecyclerMainViewHolder, position: Int) {
            holder.rowCalendarBinding.textCalendarSubject.text = memoList[position].memoSubject

            // 항목을 누르면 동작하는 리스너
            holder.rowCalendarBinding.root.setOnClickListener {
                // 메모를 보는 화면이 나타나게 한다.
                val memoReadBundle = Bundle()
                memoReadBundle.putInt("memoIdx", memoList[position].memoIdx)
                mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, memoReadBundle)
            }
        }
    }

캘린더에 설정되어 있는 날짜의 메모 내용을 가져와 리사이클러뷰를 갱신하는 메서드

// CalendarFragment.kt


    // 캘린더에 설정되어 있는 날짜의 메모 내용을 가져와 리사이클러뷰를 갱신한다.
    fun getMemoDataDate(){
        // 캘린더에 설정되어 있는 날짜 데이터를 년-월-일 형태로 만들어준다
        // 데이터 베이스에 이렇게 저장되어 있기 때문에...
        val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd")
        val targetDate = simpleDateFormat.format(mainActivity.calendarNowTime)
        // 데이터를 가져온다.
        memoList = MemoDao.selectMemoDataDate(mainActivity, targetDate)
        // 리사이클러뷰를 갱신한다.
        fragmentCalendarBinding.recyclerMain.adapter?.notifyDataSetChanged()
    }

리사이클러뷰 갱신 메서드 적용

작성된 메서드 3군데에 리사이클러뷰 갱신 메서드를 추가한다.

// CalendarFragment.kt


    // 오늘 버튼 설정
    fun settingButtonMainToday(){
        fragmentCalendarBinding.apply {
            buttonMainToday.setOnClickListener {
                // 현재 시간을 Long값으로 구해 CalendarView에 설정해준다.
                // currentTimeMillis 메서드를 호출한 시점의 값을 Long타입으로 반환해준다.
                calendarMain.date = System.currentTimeMillis()
                // MainActivity의 프로퍼티에 넣어준다.
                mainActivity.calendarNowTime = calendarMain.date
                // 리사이클러뷰를 갱신한다.
                getMemoDataDate()
            }
        }
    }
    
    // 캘린더 설정
    fun settingCalendarMain(){
        fragmentCalendarBinding.apply {
            calendarMain.apply {
                // 캘린더의 날짜를 MainActivity의 프로퍼티 값으로 지정한다.
                date = mainActivity.calendarNowTime
                // 캘린더의 최대 날짜를 오늘로 설정한다.
                maxDate = System.currentTimeMillis()
                
                // 캘린더 뷰의 날짜가 변경되면 동작하는 리스너
                // 두번째, 세번째, 네번째 : 설정된 년도, 월, 일
                setOnDateChangeListener { view, year, month, dayOfMonth ->
                    // 캘린더의 현재 날짜 값을 MainActivity의 프로퍼티로 넣어준다.
                    // 년월일값을 Long 날짜값으로 변경한다.
                    // 날짜 데이터를 관리하는 객체를 생성하고 새롭게 설정된 날짜 값을 넣어준다.
                    val c1 = Calendar.getInstance()
                    c1.set(year, month, dayOfMonth)
                    // 설정된 날짜값을 Long 형태의 시간값으로 가져와 담아준다.
                    mainActivity.calendarNowTime = c1.timeInMillis

                    // 리사이클러뷰를 갱신한다.
                    getMemoDataDate()
                }
            }
        }
    }
    
        // RecyclerView 설정
    fun settingRecyclerMain(){
        fragmentCalendarBinding.apply {
            recyclerMain.apply {
                // 어댑터 설정
                adapter = RecyclerMainAdapter()
                // 레이아웃 매니저
                layoutManager = LinearLayoutManager(mainActivity)
                // 데코
                val deco = MaterialDividerItemDecoration(mainActivity,MaterialDividerItemDecoration.VERTICAL)
                addItemDecoration(deco)

                // 리사이클러뷰를 갱신한다.
                getMemoDataDate()
            }
        }
    }

profile
안드로이드공부

0개의 댓글