The final result

The project address

One, the implementation of infinite scrolling

Recyclerview.adapter getItemCount() returns intege.MAX_VALUE, RecycleView scrollToPosition() to a large enough position, so that the infinite scrolling effect is achieved

Two, date display

Use RecycleView to realize, need to do is to fill ItemView, here for the convenience of obtaining data set, “month” view as ItemView

  • Get date algorithm implementation
  1. Step 1: You need to create a base (including year, month, and current date as the base)
  2. Step 2: Calculate the year and month according to the sliding deltaPosition. After getting the date, bind the ItemView easily
public class DateSet {
    private static final String TAG = "DateSet";
    DateCell baseDateCell;
    int basePosition;

    public DateCell getDateCellByPosition(int position, DateCell dc) {
        if (baseDateCell == null) {
            baseDateCell = new DateCell();
            basePosition = position;
            baseDateCell.toCurrentDate();
        }
        int deltaYear = (position - basePosition) / 12;
        int deltaMonth = (position - basePosition) % 12;
        int month = baseDateCell.month + deltaMonth;
        int year = baseDateCell.year + deltaYear;
        if (month <= 0) {
            --year;
            month += 12;
        } else if (month >= 13) {
            ++year;
            month -= 12;
        }
        dc.setDate(year, month);
        LogUtils.d(TAG, "baseDateCell:" + baseDateCell + "\tdc:" + dc);
        returndc; }}Copy the code

There are many ways to realize the month View. Here I inherit the View and use canvas to draw the annoying point is to calculate the position of each day (left,top,right,bottom). This “day” Cell is described as “DayView” for convenience.

  • Algorithm implementation
  1. Step 1: You can calculate the day of the week of the first day of the month, the number of weeks in the month, and the number of days in the month. This information is mainly used in drawing.
  2. The second step: The width of the DayView is just 1/7 of the width of the month view. The height of the DayView itself can be calculated using a default value (left,top,right,bottom) and the information obtained in the first step. Then use canvas.drawtext () to draw the date. The third argument to drawText is baseLine. BasLine must be accurate if you want to use a font play

Information about baseLine

Calculate DayView (left,right,top,bottom) key code complete code monthview.java

for (int week = 0; week < weeks/* Total number of weeks in the month */; week++) {
            int count = (week == 0)?7 - firstDayOfWeek/* 1st is the day of the week */ + 1 : ((week == weeks - 1)? dateCell.getSumDays() - ((weeks -2) * 7 + 7 - firstDayOfWeek + 1) : 7);
            for (int index = 0; index < count; index++) {
                String day = String.valueOf(((week == 0)? index : (week >1 ? (week - 1) * 7 + 7 - firstDayOfWeek + 1 + index : 7 - firstDayOfWeek + 1 + index)) + 1);
                float l;
                if (week == 0 && firstDayOfWeek > 1) {
                    l = getPaddingLeft() + (firstDayOfWeek - 1 + index) * (getMeasuredWidth() / 7.0 F/*day_view_width*/);
                } else {
                    l = getPaddingLeft() + index * (getMeasuredWidth() / 7.0 F);
                }
                float t = getPaddingTop() + week * (getMeasuredHeight() / (float) weeks);
                float r = l + getMeasuredWidth() / 7.0 F;
                float b = t + getMeasuredHeight() / (float) weeks;
                if (dateCell.isCurMonth() && Integer.parseInt(day) == dateCell.getCurDay()) {
                    canvas.drawCircle(l + (r - l) / 2.0 F, t + (b - t) / 2.0 F, (r - l) / 4.0 F, curDayBgPaint);
                    dayTextPaint.setColor(Color.WHITE);
                } else {
                    dayTextPaint.setColor(Color.BLACK);
                }
                if (week < weeks - 1) {
                    canvas.drawLine(l, b, r, b, bottomLinePaint);
                }
                canvas.drawText(day, l + (r - l) / 2 - dayTextPaint.measureText(day) / 2, t + (b - t) / 2 + (b - t) / 4 - dayTextPaint.getFontMetrics().bottom, dayTextPaint);
                map.put(day, new float[]{l, r, t, b});// Store location information to get the specific date of the click}}Copy the code
  • Listens for month view click events

Since the month View is directly inherited from the View and then created using Canvas, we cannot simply setOnXXXListener; Here I’m overriding the View’s onTouchEvent method; For the specific date of click, the method is also very simple, because the month is a grid, the simplest method is to traverse horizontally to determine the week of the click point on the X axis, and then to traverse the week of the click point with step size of 7, so as to determine the specific date of click

  • The algorithm that gets the specific date of the click
private int getDayByPosition(float x/* Click the X coordinate of the event */.float y/* Click the Y coordinate of the event */) {
        if (map.size() == 0) return 0;
        float[] rectInfo;//[left,right,top,bottom]
        for (int day = 1; day < 8; day++) {// Specify the day of the week to click on
            rectInfo = map.get(String.valueOf(day));
            if (x >= rectInfo[0] && x <= rectInfo[1]) {
                while(rectInfo ! =null && (y < rectInfo[2] || y > rectInfo[3])) {
                    rectInfo = map.get(String.valueOf(day += 7));
                }
                return day > sumDays/* Total number of days in the month */ ? 0: day; }}return 0;
    }
Copy the code

Here all the basic work is basically completed, the next is the process of RecycleView assembly, here will not elaborate; About RecycleView top effect can refer to other people’s implementation, as long as you know the three key methods of ItemDecoration (getItemOffsets, onDraw, onDrawOver) basically no problem;

  • Some methods used in the project to get the date complete code:
public int getSumWeeksOfMonth(a) {// Get the total number of weeks in a month
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, sumDays);
        return calendar.get(Calendar.WEEK_OF_MONTH);
    }

    public int getFirstDayOfWeek(a) {// The first day of the month is the first day of the week
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1.1);
        return calendar.get(Calendar.DAY_OF_WEEK);
    }

    private static int getDaysOfMonth(int year, int moth) {// Get the total number of days in the month
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, moth - 1);
        c.set(Calendar.DATE, 1);
        c.roll(Calendar.DATE, -1);
        return c.get(Calendar.DATE);
    }
Copy the code

Flaw: Currently does not support lunar calendar, holiday display

The project address