https://github.com/miso01/SingleRowCalendar
완성본부터..!
사용법, 예제는 위의 링크에 잘 나와있다.
1. 라이브러리 설치
- build.gradle
dependencies {
...
implementation 'com.michalsvec:single-row-calednar:1.0.0'
...
}
- settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
jcenter()
maven { url 'https://jitpack.io' }
}
}
2. 선택된 날짜, 선택되지 않은 날짜 디자인 만들기
<!-- item_selected_calendar.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="110dp"
android:layout_height="35dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:background="@drawable/bg_selected_calendar"
android:orientation="horizontal"
android:weightSum="3"
android:padding="10dp">
<TextView
android:id="@+id/tv_date_calendar_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:textColor="@color/black"
android:textSize="12sp"
android:text="20" />
<TextView
android:id="@+id/tv_month_calendar_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:fontFamily="sans-serif-black"
android:textColor="@color/black"
android:textSize="12sp"
android:text="JAN"/>
<TextView
android:id="@+id/tv_year_calendar_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:fontFamily="sans-serif-black"
android:textColor="@color/black"
android:textSize="12sp"
android:text="2023"/>
</LinearLayout>
<!-- item_unselected_calendar.xml -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="70dp"
android:layout_height="35dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/tv_date_calendar_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="22"
android:textColor="#7F7F7F"
android:textSize="12sp"
android:fontFamily="sans-serif-black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
3. 달력을 띄울 메인 화면에 sigleRowCalendar 추가해주기
<com.michalsvec.singlerowcalendar.calendar.SingleRowCalendar
android:id="@+id/sel_calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
app:deselection="false"
app:longPress="false"
app:multiSelection="false"
app:layout_constraintTop_toBottomOf="@id/btn_calendar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
4. CalendarViewManager (메인 코드 안에)
val myCalendarViewManager = object : CalendarViewManager {
override fun setCalendarViewResourceId(
position: Int,
date: Date,
isSelected: Boolean
): Int {
// return item layout files, which you have created
return if (isSelected) R.layout.item_selected_calendar
else R.layout.item_unselected_calendar
}
override fun bindDataToCalendarView(
holder: SingleRowCalendarAdapter.CalendarViewHolder,
date: Date,
position: Int,
isSelected: Boolean
) {
// bind data to calendar item views
holder.itemView.findViewById<TextView>(R.id.tv_date_calendar_item).text =
DateUtils.getDayNumber(date)
if (isSelected) {
holder.itemView.findViewById<TextView>(R.id.tv_month_calendar_item).text =
DateUtils.getMonth3LettersName(date)
holder.itemView.findViewById<TextView>(R.id.tv_year_calendar_item).text =
DateUtils.getYear(date)
}
}
}
선택된/선택되지 않은 날짜에 대해 레이아웃을 반환해준다.
요일에 따라 다른 아이템 레이아웃을 적용하고 싶다면 예제 코드를 참고하면 된다.
그리고 아이템을 바인딩해줘야 하는데, 예제에 나온대로 따라하면 자꾸 오류가 떠서 삽질을 좀 했다..
자꾸 바인딩이 안 돼서 findViewById로 해결했다.
내가 필요한건 YYYY/MM/DD 였다.
getDayNumber -> 일 반환 (숫자)
getMonth3LettersName -> 월(3글자) 반환 (문자)
getYear -> 년도 반환 (숫자)
5. CalendarSelectionManager (메인 코드 안에)
val mySelectionManager = object : CalendarSelectionManager {
override fun canBeItemSelected(position: Int, date: Date): Boolean {
// return true if item can be selected
curDate = simpleDateFormat.format(date)
MypageService(this@MypageFragment).tryGetDailyRecord(curDate, userIdx)
return true
}
}
아이템이 선택되었을 때 해야 할 일을 작성해준다.
나는 서버로부터 데이터를 받아와야 하기 때문에 통신 코드를 작성해줬다.
6. CalendarChangesObserver (메인 코드 안에)
val myCalendarChangesObserver = object : CalendarChangesObserver {
override fun whenSelectionChanged(isSelected: Boolean, position: Int, date: Date) {
super.whenSelectionChanged(isSelected, position, date)
}
}
7. SingleRowCalendar 설정해주기 (메인 코드 안에)
val today = GregorianCalendar()
var date: Int = today.get(Calendar.DATE)
binding.selCalendar.apply {
calendarViewManager = myCalendarViewManager
calendarChangesObserver = myCalendarChangesObserver
calendarSelectionManager = mySelectionManager
setDates(getFutureDatesOfCurrentMonth())
initialPositionIndex = date - 3
init()
select(date - 1) // 오늘 날짜 선택
}
이제 캘린더에 위에서 만들었던 객체들을 설정해주고, 날짜를 설정해준다.
setDates(getFutureDatesOfCurrentMonth())
-> 오늘 날짜가 포함된 month의 날짜들을 설정해준다.
initialPositionIndex = date - 3
-> 처음 실행했을 때 스크롤을 하지 않았을 때 첫 번째 인덱스가 오늘날짜-2가 되도록 하였다.
(화면에 총 다섯개의 날짜를 띄웠고, 선택된 날짜를 가운데로 보내기 위함)
select(date - 1)
-> 처음 실행했을 때 자동으로 오늘 날짜를 선택하도록 하였다.
8. 날짜 불러오는 함수 (메인 코드 밖에)
private fun getFutureDatesOfCurrentMonth(): List<Date> {
currentYear = calendar[Calendar.YEAR]
currentMonth = calendar[Calendar.MONTH]
return getDates(mutableListOf())
}
private fun getFutureDatesOfSelectMonth(month: Int, year: Int): List<Date> {
currentMonth = month-1
currentYear = year
return getDates(mutableListOf())
}
private fun getDates(list: MutableList<Date>): List<Date> {
calendar.set(Calendar.YEAR, currentYear)
calendar.set(Calendar.MONTH, currentMonth)
calendar.set(Calendar.DAY_OF_MONTH, 1)
list.add(calendar.time)
while (currentMonth == calendar[Calendar.MONTH]) {
calendar.add(Calendar.DATE, +1)
if (calendar[Calendar.MONTH] == currentMonth)
list.add(calendar.time)
}
calendar.add(Calendar.DATE, -1)
return list
}
총 세개의 함수를 작성해줬다.
나는 달력 모양의 버튼이 있어 그 버튼을 클릭하면 달력에서 날짜를 선택할 수 있고,
날짜가 선택되면 해당 날짜에 따라 SingleRowCalendar의 날짜를 바꾸도록 하여서
오늘 날짜가 포함된 month 뿐만 아니라 다른 month의 날짜들도 필요했기 때문이다.
그리고 나는 year도 필요해서 예제코드를 조금 바꿔서 사용했다.
getFutureDatesOfCurrentMonth
-> 오늘 날짜가 포함된 month의 날짜 리스트 반환
getFutureDatesOfSelectMonth
-> 매개변수로 들어온 month와 year의 날짜 리스트 반환
getDates
-> 날짜 리스트 반환
9. 완성!
이렇게 하면 끝..!
아주 잘 작동된다~
'* > Android' 카테고리의 다른 글
[안드로이드] 서버 통신 시 예외 처리가 제대로 안 될 때 (0) | 2023.03.09 |
---|---|
[안드로이드] 디자인 패턴 정리 (MVC, MVP, MVVM) (0) | 2023.03.09 |
[안드로이드] Activity, Fragment LifeCycle (0) | 2023.03.06 |
[안드로이드] 앱 목록에서 아이콘 안 보일 때 (0) | 2023.02.19 |
[안드로이드] Activity, Fragment 간 데이터 주고받기 2 (0) | 2023.02.19 |