티스토리 뷰

Android 달력 라이브러리 - AirCalendar


현재는 업데이트 되어 바뀌어버렸지만, 그전 에어비앤비 달력은 많은 서비스에서 참고했던 달력이였습니다.

리스트뷰 스타일로 위/아래 무한스크롤 형태의 달력이죠


주로 호텔/펜션등 숙박 예약 서비스에서 많이 사용되어진 달력인데요

그 이유는 예약현황 + 단일 + 다중 날짜 선택이 가능하기 때문입니다( 숙박의 경우 최소 1박 2일 이죠 )


달력 자체가 만들때마다 귀찮고 손이 많이 가는 부분입니다.

그 때문에 "예약현황 + 단일 + 다중" 선택이 모두 가능한 달력 라이브러리름 만들어보았습니다.



  


< 스크린샷 >



1. app.gradle 에 아래 라인을 추가합니다.( 라이브러리 import )

마지막 버전: 

jitpack.io 저장소 추가


allprojects { repositories { ...     maven { url 'https://jitpack.io' } }

}

dependencies 추가

implementation 'com.github.yongbeam:AirCalendar:x.x.x'



2. 프로젝트의 AndroidManifest.xml 에 아래 구문을 추가합니다.

    프로젝트에서 AirCalendar View 를 띄우기 위함입니다.

<activity android:name="com.yongbeom.aircalendar.AirCalendarDatePickerActivity"
            android:theme="@style/Theme.AppCompat.NoActionBar" />



3. 프로젝트에서 AirCalendar 를 호출합니다.

AirCalendarIntent intent = new AirCalendarIntent(this); intent.isBooking(false); intent.isSelect(false); intent.setBookingDateArray('Array Dates( format: yyyy-MM-dd'); intent.setStartDate(yyyy , MM , dd); // int intent.setEndDate(yyyy , MM , dd); // int intent.isMonthLabels(false);

intent.setActiveMonth(3);

intent.setMaxYear(2030);

startActivityForResult(intent, REQUEST_CODE);

호출시 사용되는 옵션은 아래와 같습니다.


intent.isBooking(false);     :  예약현황(특정날짜를 막는경우) 사용여부( true : 사용 / false : 비사용 )

intent.isSelect(false);        : 

intent.setBookingDateArray();  : 예약현황을 사용하는 경우 선택을 막을 날짜를 넘겨줍니다 Array<String> 타입의 yyyy-MM-dd 정보 

intent.setStartDate();  : 초기 시작 날짜를 지정합니다. ( 지정시 선택되저여 있으며, setEndDate() 설정시 중간 날짜도 선택됩니다 )

intent.setEndDate();    : 초기 종료 날짜를 지정합니다.( 지정시 선택되어져 있습니다 )

intent.isMonthLabels(false);  : false 시 라벨이 보여지지 않습니다.

intent.setActiveMonth(3);  : 달력에 활성화할 월을 지정합니다. 3으로 설정시 3개월만 활성화되고 이후 날짜는 비활성화 됩니다.

intent.setMaxYear(2030);  : 달력에 표시할 최대 년도를 설정합니다( 2030 설정시 달력에 2030년까지 노출 )

 


4. AirCalendar 에서 선택한 날짜를 받아오기 위해 onActivityResult를 사용합니다.

( TODO: 차후 자체 콜백으로 변경될 예정입니다 )

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
            if(data != null){
                Toast.makeText(this, "Select Date range : " + data.getStringExtra(AirCalendarDatePickerActivity.RESULT_SELECT_START_DATE) + " ~ " + data.getStringExtra(AirCalendarDatePickerActivity.RESULT_SELECT_END_DATE), Toast.LENGTH_SHORT).show();
            }
        }
    }


선택된 날짜를 받아올때는 단일/다중 요청에 따라 달라집니다.

AirCalendarDatePickerActivity.RESULT_SELECT_START_DATE AirCalendarDatePickerActivity.RESULT_SELECT_END_DATE AirCalendarDatePickerActivity.RESULT_SELECT_START_VIEW_DATE // Day of the week AirCalendarDatePickerActivity.RESULT_SELECT_END_VIEW_DATE // Day of the week AirCalendarDatePickerActivity.RESULT_FLAG AirCalendarDatePickerActivity.RESULT_TYPE AirCalendarDatePickerActivity.RESULT_STATE


RESULT_SELECT_START_DATE : 시작 날짜를 사용합니다.

RESULT_SELECT_END_DATE : 종료 날짜를 사용합니다.

RESULT_SELECT_START_VIEW_DATE : 형식이 지정된 시작 날짜입니다.

RESULT_SELECT_END_VIEW_DATE : 형식이 지정된 종료 날짜입니다.

RESULT_FLAG : 현재는 사용하지 않습니다.

RESULT_TYPE : 결과 타입입니다( 단일/다중 )

RESULT_STATE : 성공/실패 여부 입니다.




단순하게 날짜 선택기능을 사용하는 경우 위처럼만 하시면 쉽게 달력을 사용하실 수 있습니다.

만약 스타일의 커스마이징이 필요한 경우 아래 스타일을 별도로 정의해주시면 됩니다.


  • app:colorCurrentDay [color def:#ff999999] 
  • app:colorSelectedDayBackground [color def:#E75F49] 
  • app:colorSelectedDayText [color def:#fff2f2f2] 
  • app:colorPreviousDay [color def:#ff999999] 
  • app:colorNormalDay [color def:#ff999999] 
  • app:colorMonthName [color def:#ff999999]
  • app:colorDayName [color def:#ff999999]
  • app:textSizeDay [dimension def:16sp]
  • app:textSizeMonth [dimension def:16sp] 
  • app:textSizeDayName [dimension def:10sp] 
  • app:headerMonthHeight [dimension def:50dip] 
  • app:drawRoundRect [boolean def:false]
  • app:selectedDayRadius [dimension def:16dip] 
  • app:calendarHeight [dimension def:270dip]
  • app:enablePreviousDay [boolean def:true] 
  • app:currentDaySelected [boolean def:false] 
  • app:firstMonth [enum def:-1] 
  • app:lastMonth [enum def:-1] 





지속적인 업데이트를 통해 다양한 기능이 추가될 예정입니다.

 위 스타일외의 커스마이징을 원하시면 아래 GitHub 에서 코드를 내려받아 직접 개발하실 수 있습니다.


AirCalendar GitHub 바로가기 

       

호출 샘플 바로보기



궁금한 점이나 의견등은 블로그나 github를 통해 언제든 주시면 됩니다 :)

감사합니다.



댓글
  • 프로필사진 비밀댓글입니다 2017.11.09 17:47
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 안녕하세요!
    답변이 늦어서 죄송합니다^^;;
    일단 커스마이징을 통해 표시는 가능합니다.
    현재는 없지만 숙박의 경우 달력에 금액을 표시하는 기능이 필요한 경우가 있어서 고려는 했으나, 언제 지원을 시작할지 명확하게 답을 드리기는 어렵네요
    최대한 빠른 시일내에 해당 기능을 추가할 수 있도록 고려하겠습니다
    2017.11.13 15:30 신고
  • 프로필사진 비밀댓글입니다 2017.11.14 15:21
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 직접 수정하시려면, 라이브러리 core/SimpleMonthView.java 에서, drawMonthNums() 를 보시면됩니다.

    Canvas를 이용해 좌표기반으로 날짜를 뿌려주고 있기때문에 drawMonthNums 하단에 보시면 아래와 같이 날짜(숫자)를 뿌려주는걸 보실 수 있습니다.
    canvas.drawText(String.format("%d", day), x, y, mMonthNumPaint);

    x 좌표는 이미 있기 때문에 따로 계산하실 필요는 없구요 y좌표의 경우 숫자 아래에 체크인/체크아웃 을 표시해야 하니 조금 조절하시면 됩니다.
    2017.11.14 15:46 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 12:11
  • 프로필사진 비밀댓글입니다 2017.11.15 12:13
  • 프로필사진 비밀댓글입니다 2017.11.15 12:19
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 먼저 달력의 UI 처리 부분은 모두 SimpleMonthView.java 에서 하고 있으니 이 클래스만 분석하셔도 하고싶으신건 대부분 하실 수 있을거에요

    라운드 처리의 경우는 이미지가 아닌 Canvas로 그리고 있습니다.
    RectF rectF = new RectF(x - DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) - DAY_SELECTED_CIRCLE_SIZE, x + DAY_SELECTED_CIRCLE_SIZE, (y - MINI_DAY_NUMBER_TEXT_SIZE / 3) + DAY_SELECTED_CIRCLE_SIZE);
    canvas.drawRoundRect(rectF, 150.0f, 150.0f, mSelectedCirclePaint);
    이부분 참고하시면 됩니다.
    라운드 값을 0을 주면 사각형태로 나오겠죠?
    2017.11.15 16:49 신고
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 제가 설명을 드려도 Canvas를 공부하지 않으시면 커스마이징 하시기는 계속 어려우실 거에요

    앞서 가이드 드린 내용을 다시 말씀드리자면, x,y좌표는 있기 떄문에 달력 날짜가 그려지는 시점에 아래처럼 추가하시고 글이 추가되는걸 확인해보세요
    canvas.drawText("TEST", x, y, mMonthNumPaint);
    2017.11.15 16:54 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 16:58
  • 프로필사진 비밀댓글입니다 2017.11.15 17:13
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 라운드를 살짝만 주고 싶으시면 값을 낮게 주시면 되구요
    현재는 체크인,체크아웃 문구는 노출위치 x,y 계산 하신다음에 canvas로 그리는 방법밖에는 없습니다.
    제가 예시드린 대로 해보시고 문구가 나오는지 확인해보세요 그럼 어느정도 감이 잡히실거에요
    2017.11.15 17:28 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 17:30
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom TEST문구를 찍어보신건가요?
    제가 드린 예시 코드로 하시면 선택하면 글귀도 하얀색으로 바뀔거에요
    2017.11.15 17:39 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 17:41
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 네, 제가 예시로 알려드린건 단순히 글을 표시하는 부분이구요
    그런식으로 시작,끝 을 체크하셔서 동일하게 하시면되요
    2017.11.15 17:43 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 17:50
  • 프로필사진 BlogIcon 이용범 Lee Yongbeom 앞서 말씀드린 것처럼 예시를 드린거구요
    원하시는 형태는 SimpleMonthView.java 의 drawMonthNums() 에서 조건만 검사하셔서 처리하시면 됩니다.

    표시되는 UI모양 변경에 대해서는 Canvas로 하시면 되기 때문에 Canvas를 학습하셔야 합니다.

    일단 현재 공식지원 하지 않는 기능이다 보니,
    원하시는 UI대로 제가 만들어 드릴 수는 없기 때문에 어느부분을 수정하면 되는지 예시만 드린거구요
    2017.11.15 17:58 신고
  • 프로필사진 비밀댓글입니다 2017.11.15 17:59
  • 프로필사진 비밀댓글입니다 2018.04.24 12:30
  • 프로필사진 비밀댓글입니다 2018.05.03 14:34
  • 프로필사진 비밀댓글입니다 2018.09.12 20:57
  • 프로필사진 비밀댓글입니다 2018.10.18 16:31
댓글쓰기 폼