Calendar control customization is a common and difficult requirement on mobile development platforms, which usually encounter the following problems:

  • Poor performance, loading speed is slow, the reason is a variety of GridView or RecyclerView ViewGroup calendar, control too many, suppose a month view interface has 42 items, each item there are 2 child TextView: The number of days, the number of lunar calendar and itself 3 controls, so a month view has 42 * 3+1 (RecyclerView or GridView), clear ViewPager features developers will understand, the general ViewPager hold 3 items, Then a calendar control hold the number of View controls will reach 1 (ViewPager) + 3(RecyclerView or GridView) + 3 * 42 * 3 = 382, if you use a View to replace the RecyclerView, etc., Use Canvas instead of various TextViews and the number of views will drop by 360+ instantly, and the memory and performance benefits will be quite significant
  • It is difficult to customize the general calendar framework released at the same time will be determined the UI style, if everyone uses the calendar framework, then will be the same, it is difficult to highlight their own style, or have to change the source code, the cost is too big, not practical
  • Lack of functionality such as the inability to customize week start, change selection mode, set the UI dynamically, and so on
  • The product experience today says we’re going to do this, tomorrow tells you we have to change here, the day after tomorrow we have to limit some dates…

But now there’s a whole new oneCalendarViewControl, which unlocks various poses, and you can tweak it until you’re satisfied…

International practice: put the project github address first

https://github.com/huanghaibin-dev/CalendarView

Domestic practice: no picture

     

     

SAO features of CalendarView

  • Drawing based on Canvas, speed performance
  • Hot plug idea, any custom weekly view, monthly view, plug and play!
  • Support single, multiple, domestic mobile phone calendar default automatic selection and other selection modes
  • Support static, dynamic setup week start, a line of code done
  • Supports static and dynamic setting of calendar item height and calendar filling mode
  • You can set any date range and any interception date
  • Supports multi-touch and smooth finger switching, and rejects interface jitter
  • Since so much support, it must support English, traditional, simplified, arbitrary custom implementation

Next, please look at CalendarView SAO operation and see how it can be adjusted

  • You inherit your monthly and weekly views, and you just need to draw onDrawSelected, draw transaction: onDrawScheme, and draw text: The parameters and coordinates are already implemented in the callback function. The same logic is used for the week view, but the y parameter is not required
** * Created by Huanghaibin on 2017/11/15. */

public class MeiZuMonthView extends MonthView {

    /** * Draw the selected date **@param canvas    canvas
     * @paramCalendar Calendar calendar *@paramX Calendar Card x starting point coordinates *@paramY calendar Card y starting point coordinates *@paramHasScheme hasScheme unmarked date *@returnReturn true to draw the onDrawScheme, where the background colors are not mutually exclusive, so return true */
    @Override
    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
        canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);
        return true;
    }

    /** * Draw marked event day **@param canvas   canvas
     * @paramCalendar Calendar *@paramX Calendar Card x starting point coordinates *@paramY calendar Card y starting point coordinates */
    @Override
    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);
        canvas.drawText(calendar.getScheme(),
                x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
                y + mPadding + mSchemeBaseLine, mTextPaint);
    }

    /** * Draw text **@param canvas     canvas
     * @paramCalendar Calendar *@paramX Calendar Card x starting point coordinates *@paramY calendar Card y starting point coordinates *@paramHasScheme is the date of the mark *@paramIsSelected Whether to select */
    @Override
    protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
        int cx = x + mItemWidth / 2;
        int top = y - mItemHeight / 6;

        boolean isInRange = isInRange(calendar);

        if (isSelected) {
            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
                    mSelectTextPaint);
            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
        } else if (hasScheme) {
            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
                    calendar.isCurrentMonth() && isInRange ? mSchemeTextPaint : mOtherMonthTextPaint);

            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
        } else {
            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
                    calendar.isCurrentDay() ? mCurDayTextPaint :
                            calendar.isCurrentMonth() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint : calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint); }}}Copy the code
  • When you’re done, add features directly to the XML interface for instant preview:

<attr name="month_view" format="string" /><! -- Custom month view path -->
<attr name="week_view" format="string" /> <! -- Custom week view path -->

app:month_view="com.haibin.calendarviewproject.MeiZuCalendarCardView"
app:week_view="com.haibin.calendarviewproject.MeiZuWeekView"

Copy the code
  • However, this static mode may not be enough for your needs. You may need to dynamically transform the custom view interface, so you can use the hot swap feature, plug and play, and switch whenever you want:

mCalendarView.setWeekView(MeizuWeekView.class);

mCalendarView.setMonthView(MeizuMonthView.class);
 
Copy the code
  • CalendarView also provides an efficient and convenient year view that can quickly switch years and months, which is very convenient

  • However, the year view may not be the right fit for product managers, who want to pop up a DatePickerView to jump to dates like Xiaomi calendar, so you can use the following API to link calendars with other controls

CalendarView.scrollToCalendar();

CalendarView.scrollToNext();

CalendarView.scrollToPre();

CalendarView.scrollToXXX();

Copy the code
  • You may need to be able to change the start of the week both statically and dynamically, just like the Meizu calendar

app:week_start_with="Mon, Sun, SAT"

CalendarView.setWeekStarWithSun();

CalendarView.setWeekStarWithMon();

CalendarView.setWeekStarWithSat();

Copy the code
  • If you are doing an APP for hotel, travel and other application scenarios, then you need an optional range of calendar, you can inherit this way, and the normal view implementation is exactly the same
public class CustomRangeMonthView extends RangeMonthView{}public class CustomRangeWeekView extends RangeWeekView{}Copy the code
  • Then you need to set the select mode to range mode: select_mode=”range_mode”

  • Of course, the hotel calendar scene cannot be booked from yesterday or indefinitely, so you need to set the calendar range, static or dynamic, to a specific day!!

<attr name="min_year" format="integer" />
<attr name="max_year" format="integer" />
<attr name="min_year_month" format="integer" />
<attr name="max_year_month" format="integer" />
<attr name="min_year_day" format="integer" />
<attr name="max_year_day" format="integer" />

CalendarView.setRange(int minYear, int minYearMonth, int minYearDay,
         int maxYear, int maxYearMonth, int maxYearDay)

Copy the code
  • Of course, there are more special days can not be selected, such as: N days from a certain date due to a super typhoon, the hotel needs to be closed for N days, this period can not be booked, then the date interceptor will be used
// Set date intercept event
mCalendarView.setOnCalendarInterceptListener(new CalendarView.OnCalendarInterceptListener() {
     @Override
     public boolean onCalendarIntercept(Calendar calendar) {
         // Return true for interception
         return calendar.isWeekend();
     }

     @Override
     public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
         // Todo click to block the date callback}});Copy the code
  • After adding date interceptors and scope Settings, you can get their results on demand in the week-month view

boolean isInRange = isInRange(calendar);// Whether the date is within the range

booleanisEnable = ! onCalendarIntercept(calendar);// Whether the date is available, not intercepted, intercepted can be ash

Copy the code
  • If you are working on a list or task APP, you may have a need to mark the progress of a certain day’s affairs. This is also very simple, because: what the calendar interface looks like is up to you!!

  • If you have a CalendarView, you need to customize your CalendarView. If you have a CalendarView, you need to customize your CalendarView. If you have a CalendarView, you need to customize your CalendarView

  • Setschemedates (Map

    mSchemeDates) is a very efficient API for dynamically marking transactions. Even if your data volume reaches thousands, tens of thousands, or hundreds of thousands, it will not affect the UI rendering
    ,>

  • The Calendar class provides a number of very useful apis

boolean isWeekend(a);// To determine whether it is a weekend, you can use a different brush to draw a weekend style

int getWeek(a);// Get the week

String getSolarTerm(a);// Get the 24 solar terms. You can use different colors to mark different festivals

String getGregorianFestival(a);// Get the Gregorian calendar festival and change it to your favorite color

String getTraditionFestival(a);// Get traditional festivals

boolean isLeapYear(a);// Whether it is a leap year

int getLeapMonth(a);// Get leap month

boolean isSameMonth(Calendar calendar);// Whether the same month

int compareTo(Calendar calendar);// After all, the date size is -1 0 1

long getTimeInMillis(a);// Get the timestamp

int differ(Calendar calendar);// The date is calculated by the number of days
Copy the code

Other various scenes pose is not much to say, you have to go to unlock, together to see Demo and a variety of apps coquettes implementation

     

     

     

In the end, the framework itself is designed to solve a variety of scenarios, the UI itself is drawn by their own, very simple, do not understand please look at the Demo first, you can freely use your imagination to customize the favorite calendar, only you can not think of, the Demo basically gives a variety of scenarios to achieve the idea. Feel can please give a star or leave your valuable advice.

Blog convention: Put your Github address at the end, otherwise you won’t want to go to the top and click

https://github.com/huanghaibin-dev/CalendarView