安卓 自定义日历

安卓 自定义日历


前言

安卓自定义日历

实现思路:

  • 根据当前年份显示当前年的所有月份
  • 根据当前月份显示当前月份的所有天数
  • 改变选择日触发自定义改变事件传递

一、实现

介绍:

  • 完成基本布局
    • 顶部左侧显示当前选择的年月
    • 顶部右侧显示刷新图片
    • 中间
      • 显示当前选择的年份的年月
      • 显示当前选择月份的日

1.整体样式

sl_view_calendar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:background="@color/white"
              android:padding="15dp"
              android:id="@+id/calendar">
    <LinearLayout android:layout_width="match_parent"
                  android:gravity="left"
                  android:orientation="horizontal"
                  android:layout_height="30dp">
        <LinearLayout android:layout_width="wrap_content"
                      android:id="@+id/calendar_title"
                      android:layout_height="match_parent">
            <TextView android:text="2023"
                      android:id="@+id/calendar_title_year"
                      android:gravity="center"
                      android:layout_width="wrap_content"
                      android:layout_height="match_parent"/>
            <TextView android:text=""
                      android:gravity="center"
                      android:layout_width="wrap_content"
                      android:layout_height="match_parent"/>
            <TextView android:text="10"
                      android:gravity="center"
                      android:id="@+id/calendar_title_month"
                      android:layout_width="wrap_content"
                      android:layout_height="match_parent"/>
            <TextView android:text=""
                      android:gravity="center"
                      android:layout_width="wrap_content"
                      android:layout_height="match_parent"/>

            <ImageView
                    android:layout_marginLeft="12dp"
                    android:scaleType="fitXY"
                    android:layout_gravity="center"
                    android:layout_width="18dp"
                    android:layout_height="18dp"
                    android:src="@drawable/sl_rl_xia"
            />
        </LinearLayout>
        <LinearLayout android:layout_width="wrap_content"
                      android:layout_weight="1"
                      android:layout_height="match_parent">
            <TextView android:text="UUMM"
                      android:id="@+id/calendar_title_ym"
                      android:gravity="center"
                      android:layout_weight="1"
                      android:layout_width="wrap_content"
                      android:layout_height="match_parent"/>
        </LinearLayout>
        <LinearLayout android:layout_width="wrap_content"
                      android:gravity="right"
                      android:layout_weight="1"
                      android:layout_height="match_parent">
            <ImageView
                    android:id="@+id/calendar_title_shuaxin"
                    android:layout_marginLeft="12dp"
                    android:scaleType="fitXY"
                    android:layout_gravity="center"
                    android:layout_width="24dp"
                    android:layout_height="24dp"
                    android:src="@drawable/shuaxin"
            />
        </LinearLayout>
    </LinearLayout>
    <View
            android:layout_width="fill_parent"
            android:layout_height="1.5dip"
            android:layout_marginBottom="6dp"
            android:background="@color/gray"/>
    <LinearLayout android:layout_width="match_parent"
                  android:orientation="horizontal"
                  android:visibility="invisible"
                  android:layout_height="30dp">
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
        <TextView android:text=""
                  android:gravity="center"
                  android:layout_weight="1"
                  android:layout_width="wrap_content"
                  android:layout_height="match_parent"/>
    </LinearLayout>
    <View
            android:visibility="gone"
            android:layout_width="fill_parent"
            android:layout_height="1.5dip"
            android:layout_marginBottom="6dp"
            android:background="@color/gray"/>
    <include
            android:visibility="gone"
            layout="@layout/sl_view_calendar_ny"
            android:id="@+id/sl_view_calendar_ny"/>
    <include
            layout="@layout/sl_view_calendar_day"
            android:id="@+id/sl_view_calendar_day"/>
    <View
            android:layout_width="fill_parent"
            android:layout_height="1.5dip"
            android:layout_marginBottom="6dp"
            android:layout_marginTop="6dp"
            android:background="@color/gray"/>
</LinearLayout>
  1. 年月样式
    sl_view_calendar_ny
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:background="@color/white"
              android:id="@+id/calendar_ny">
    <com.example.accounting.utils.toolView.CustomGridView
            android:listSelector="@color/white"
            android:numColumns="2"
            android:id="@+id/calendar_ny_gridview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
</LinearLayout>

sl_view_calendar_ny_list

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="70dp"
              android:orientation="vertical"
              android:id="@+id/calendar_ny_yearmonthbg"
              android:background="@color/white">
    <TextView android:layout_width="wrap_content"
              android:text=""
              android:id="@+id/calendar_ny_yearmonthstr"
              android:layout_gravity="center"
              android:gravity="center"
              android:layout_marginBottom="3dp"
              android:textSize="14dp"
              android:layout_weight="1"
              android:layout_height="wrap_content"></TextView>
    <TextView android:layout_width="wrap_content"
              android:text=""
              android:layout_marginBottom="3dp"
              android:id="@+id/calendar_ny_yearmonthstr1"
              android:textSize="12dp"
              android:layout_gravity="center"
              android:layout_height="wrap_content"></TextView>
</LinearLayout>
  1. 日样式
    sl_view_calendar_days
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:background="@color/white"
              android:id="@+id/calendar_day">
    <com.example.accounting.utils.toolView.CustomGridView
            android:listSelector="@color/white"
            android:numColumns="7"
            android:id="@+id/calendar_days_gridview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
</LinearLayout>

sl_view_calendar_days_list

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="70dp"
              android:orientation="vertical"
              android:id="@+id/calendar_days_r"
              android:background="@color/white">
    <LinearLayout android:layout_width="30dp"
                  android:layout_gravity="center"
                  android:id="@+id/calendar_days_yearmonthstrbg"
                  android:layout_height="30dp">
        <TextView android:layout_width="match_parent"
                  android:text="1"
                  android:id="@+id/calendar_days_yearmonthstr"
                  android:layout_gravity="center"
                  android:gravity="center"
                  android:textSize="14dp"
                  android:layout_height="match_parent"></TextView>
    </LinearLayout>
    <TextView android:layout_width="wrap_content"
              android:text="初一"
              android:id="@+id/calendar_days_yearmonthstr1"
              android:textSize="10dp"
              android:layout_gravity="center"
              android:layout_height="wrap_content"></TextView>
    <TextView android:layout_width="wrap_content"
              android:text="节气"
              android:id="@+id/calendar_days_yearmonthstr2"
              android:textSize="10dp"
              android:layout_gravity="center"
              android:layout_height="wrap_content"></TextView>
    <TextView android:layout_width="wrap_content"
              android:text="节日"
              android:id="@+id/calendar_days_yearmonthstr3"
              android:textSize="10dp"
              android:layout_marginBottom="3dp"
              android:layout_gravity="center"
              android:layout_height="wrap_content"></TextView>
</LinearLayout>

自定义属性 attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Calendarview">
        <attr name="year" format="string"/>
        <attr name="month" format="string"/>
        <attr name="day" format="string"/>
    </declare-styleable>
</resources>

自定义GridView com.example.accounting.utils.toolView.CustomGridView

public class CustomGridView extends GridView {

    public CustomGridView(Context context) {
        super(context);
    }

    public CustomGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CustomGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //  AT_MOST参数表示控件可以自由调整大小,最大不超过Integer.MAX_VALUE/4
        int height=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, height);
    }
}

2. 年月日适配器

GridCalendarNYAdapter

public class GridCalendarNYAdapter extends BaseAdapter {
    List<NYyearmonth> nYyearmonths;
    private Context context;
    private LayoutInflater inflater;

    public GridCalendarNYAdapter(List<NYyearmonth> nYyearmonths, Context context) {
        super();
        this.nYyearmonths = nYyearmonths;
        this.context = context;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return nYyearmonths.size();
    }

    @Override
    public Object getItem(int position) {
        return nYyearmonths.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @SuppressLint("ResourceAsColor")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        NYyearmonth ny = nYyearmonths.get(position);

        final GridCalendarNYHolder holder;
        if (convertView != null) {
            holder = (GridCalendarNYHolder) convertView.getTag();
        } else {
            holder = new GridCalendarNYHolder();
            convertView = View.inflate(context, R.layout.sl_view_calendar_ny_list, null);
            holder.name = convertView.findViewById(R.id.calendar_ny_yearmonthstr);
            holder.name1 = convertView.findViewById(R.id.calendar_ny_yearmonthstr1);
            holder.box = convertView.findViewById(R.id.calendar_ny_yearmonthbg);
            convertView.setTag(holder);
        }

        holder.name.setText(ny.getYear()+"");
        holder.name1.setText(ny.getMonth()+"");

        if(ny.getIs()){
            holder.name.setTextColor(R.color.teal_200);
            holder.name1.setTextColor(R.color.teal_200);
            holder.box.setBackgroundResource(R.drawable.tab_bg_gray);
        }else{
            holder.name.setTextColor(R.color.black);
            holder.name1.setTextColor(R.color.black);
            holder.box.setBackgroundResource(R.color.white);
        }
        return convertView;
    }
}

class GridCalendarNYHolder {
    public TextView name;
    public TextView name1;
    public View box;
}

GridCalendarDaysAdapter

public class GridCalendarDaysAdapter extends BaseAdapter {
    List<NYRjq> nYyearmonths;
    private Context context;
    private LayoutInflater inflater;

    public GridCalendarDaysAdapter(List<NYRjq> nYyearmonths, Context context) {
        super();
        this.nYyearmonths = nYyearmonths;
        this.context = context;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return nYyearmonths.size();
    }

    @Override
    public Object getItem(int position) {
        return nYyearmonths.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @SuppressLint("ResourceAsColor")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        NYRjq ny = nYyearmonths.get(position);

        final GridCalendarDaysHolder holder;
        if (convertView != null) {
            holder = (GridCalendarDaysHolder) convertView.getTag();
        } else {
            holder = new GridCalendarDaysHolder();
            convertView = View.inflate(context, R.layout.sl_view_calendar_days_list, null);
            holder.calendar_days_yearmonthstrbg = convertView.findViewById(R.id.calendar_days_yearmonthstrbg);
            holder.calendar_days_yearmonthstr = convertView.findViewById(R.id.calendar_days_yearmonthstr);
            holder.calendar_days_yearmonthstr1 = convertView.findViewById(R.id.calendar_days_yearmonthstr1);
            holder.calendar_days_yearmonthstr2 = convertView.findViewById(R.id.calendar_days_yearmonthstr2);
            holder.calendar_days_yearmonthstr3 = convertView.findViewById(R.id.calendar_days_yearmonthstr3);
            convertView.setTag(holder);
        }
        holder.calendar_days_yearmonthstr.setText(ny.getCurrent()+"");
        holder.calendar_days_yearmonthstr1.setText(ny.getLunar());
        holder.calendar_days_yearmonthstr2.setText(ny.getSolarTerms());
        holder.calendar_days_yearmonthstr3.setText(ny.getFestival());
        if(ny.getIsCruuent()){
            holder.calendar_days_yearmonthstrbg.setBackgroundResource(R.drawable.tab_bg_gray);
            holder.calendar_days_yearmonthstr.setTextColor(R.color.teal_200);
        }else{
            holder.calendar_days_yearmonthstrbg.setBackgroundResource(R.color.white);
            holder.calendar_days_yearmonthstr.setTextColor(R.color.black);
        }
        return convertView;
    }
}

class GridCalendarDaysHolder {
    public TextView calendar_days_yearmonthstr;
    public TextView calendar_days_yearmonthstr1;
    public TextView calendar_days_yearmonthstr2;
    public TextView calendar_days_yearmonthstr3;
    public View calendar_days_yearmonthstrbg;
}

3. 实体

/**
 * 日 辅助
 */
public class NYRjq {
    /**
     * 当前日
     */
    private int current;
    /**
     * 阴历
     */
    private String Lunar;
    /**
     * 节气
     */
    private String SolarTerms;
    /**
     * 节日
     */
    private String festival;
    private Boolean isCruuent = false;

    public NYRjq(int current) {
        this.current = current;
    }
    public NYRjq(int current, String lunar, String solarTerms, String festival) {
        this.current = current;
        Lunar = lunar;
        SolarTerms = solarTerms;
        this.festival = festival;
    }

    public NYRjq(int current, String lunar, String solarTerms, String festival, Boolean isCruuent) {
        this.current = current;
        Lunar = lunar;
        SolarTerms = solarTerms;
        this.festival = festival;
        this.isCruuent = isCruuent;
    }
	// get / set
}
/**
 * 年月辅助
 */
public class NYyearmonth {
    /**
     * 年
     */
    private int year;
    /**
     * 月
     */
    private int month;
    /**
     * 是否当前年月
     */
    private Boolean is = false;

    public NYyearmonth(int year, int month) {
        this.year = year;
        this.month = month;
    }

    public NYyearmonth(int year, int month, Boolean is) {
        this.year = year;
        this.month = month;
        this.is = is;
    }


    /**
     * 返回当月天数
     *
     * @return
     */
    public int getDays() {
        int days = 0;
        int FebDay = 28;
        if (isLeap(year))
            FebDay = 29;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                days = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                days = 30;
                break;
            case 2:
                days = FebDay;
                break;
            default:
                days = 0;
                break;
        }
        return days;
    }

    /**
     * 是否是闰年
     *
     * @param year
     * @return
     */
    public static Boolean isLeap(int year) {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    }

    public String GetStr() {
        return year + "-" + repair(month);
    }

    /**
     * 前补 0
     *
     * @param r
     * @return
     */
    public static String repair(int r) {
        String str = "";
        if (r < 10) {
            str = "0" + r;
        } else {
            str = r + "";
        }
        return str;
    }

    public String getStringYearMonth() {
        return year + "年" + repair(month) + "月";
    }
	// get / set
}
/**
 * 时间类型
 */
public enum CurrentType {
    YYYY(1),
    MM(2),
    dd(3),
    HH(4),
    mm(5),
    ss(6);

    CurrentType(int index) {
        this.index = index;
    }

    private int index;

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

4. 工具类

LunarUtils 节气工具类

public class LunarUtils {
    //生肖年
    private String animal;
    //干支年
    private String ganZhiYear;
    //阴历年
    private String lunarYear;
    //阴历月
    private String lunarMonth;
    //阴历日
    private String lunarDay;
    //阳历节日
    private String solarFestival;
    //阴历节日
    private String lunarFestival;
    //节气
    private String lunarTerm;

    /**
     *	 获取查询日期的年份生肖
     * @return
     */
    public String getAnimal() {
        return animal;
    }

    /**
     *	 获取查询日期年份的天干地支
     * @return
     */
    public String getGanZhiYear() {
        return ganZhiYear;
    }

    /**
     *	 获取查询日期的农历年份
     * @return
     */
    public String getLunarYear() {
        return lunarYear;
    }

    /**
     *	 获取查询日期的农历月份
     * @return
     */
    public String getLunarMonth() {
        return lunarMonth;
    }

    /**
     *	 获取查询日期的农历日
     * @return
     */
    public String getLunarDay() {
        return lunarDay;
    }

    /**
     * 	获取查询日期的公历节日(不是节日返回空)
     * @return
     */
    public String getSolarFestival() {
        return solarFestival;
    }

    /**
     * 	获取查询日期的农历节日(不是节日返回空)
     * @return
     */
    public String getLunarFestival() {
        return lunarFestival;
    }

    /**
     *	 获取查询日期的节气数据(不是节气返回空)
     * @return
     */
    public String getLunarTerm() {
        return lunarTerm;
    }


    final static long[] lunarInfo = new long[] {
            0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
            0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
            0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
            0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
            0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,
            0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0,
            0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,
            0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
            0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,
            0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
            0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,
            0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
            0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,
            0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,
            0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0
    };
    //阳历天数
    final static  int[] solarMonths = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    //生肖
    final static  String[] animals = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};
    //天干
    final static String[] tGan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
    //地支
    final static String[] dZhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
    //二十四节气
    final static  String[] solarTerms = new String[]{"小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏",
            "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至"};
    //二十四节气日期偏移度
    private static final  double D = 0.2422;
    //特殊年份节气日期偏移
    private final static Map<Integer,Integer[]> INCREASE_OFFSETMAP = new HashMap<Integer, Integer[]>();//+1偏移
    private final static Map<Integer,Integer[]> DECREASE_OFFSETMAP = new HashMap<Integer, Integer[]>();//-1偏移
    static {
        INCREASE_OFFSETMAP.put(0, new Integer[]{1982});//小寒
        DECREASE_OFFSETMAP.put(0, new Integer[]{2019});//小寒
        INCREASE_OFFSETMAP.put(1, new Integer[]{2082});//大寒
        DECREASE_OFFSETMAP.put(3, new Integer[]{2026});//雨水
        INCREASE_OFFSETMAP.put(5, new Integer[]{2084});//春分
        INCREASE_OFFSETMAP.put(9, new Integer[]{2008});//小满
        INCREASE_OFFSETMAP.put(10, new Integer[]{1902});//芒种
        INCREASE_OFFSETMAP.put(11, new Integer[]{1928});//夏至
        INCREASE_OFFSETMAP.put(12, new Integer[]{1925,2016});//小暑
        INCREASE_OFFSETMAP.put(13, new Integer[]{1922});//大暑
        INCREASE_OFFSETMAP.put(14, new Integer[]{2002});//立秋
        INCREASE_OFFSETMAP.put(16, new Integer[]{1927});//白露
        INCREASE_OFFSETMAP.put(17, new Integer[]{1942});//秋分
        INCREASE_OFFSETMAP.put(19, new Integer[]{2089});//霜降
        INCREASE_OFFSETMAP.put(20, new Integer[]{2089});//立冬
        INCREASE_OFFSETMAP.put(21, new Integer[]{1978});//小雪
        INCREASE_OFFSETMAP.put(22, new Integer[]{1954});//大雪
        DECREASE_OFFSETMAP.put(23, new Integer[]{1918,2021});//冬至
    }
    //定义一个二维数组,第一维数组存储的是20世纪的节气C值,第二维数组存储的是21世纪的节气C值,0到23个,依次代表立春、雨水...大寒节气的C值
    private static final double[][] CENTURY_ARRAY = {
            {6.11,20.84,4.6295,19.4599,6.3826,21.4155,5.59,20.888,6.318,21.86,6.5,22.2,7.928,23.65,8.35,23.95,8.44,23.822,9.098,24.218,8.218,23.08,7.9,22.6},
            {5.4055,20.12,3.87,18.73,5.63,20.646,4.81,20.1,5.52,21.04,5.678,21.37,7.108,22.83,7.5,23.13,7.646,23.042,8.318,23.438,7.438,22.36,7.18,21.94}
    };
    //农历月份
    final static String lunarNumber[] = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" };
    //农历年
    final static  String[] lunarYears = new String[]{"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
    final static  String[] chineseTen = new String[]{"初", "十", "廿", "卅"};
    //农历节日
    final static String[] lunarHoliday = new String[] {"0101 春节", "0115 元宵节", "0202 龙头节", "0505 端午节", "0707 七夕节", "0715 中元节",
            "0815 中秋节", "0909 重阳节", "1001 寒衣节", "1015 下元节", "1208 腊八节", "1223 小年" };
    //公立节日
    final static String[] solarHoliday = new String[] { "0101 元旦", "0214 情人节", "0308 妇女节", "0312 植树节", "0315 消费者权益日",
            "0401 愚人节", "0422 地球日", "0423 读书日", "0501 劳动节", "0504 青年节", "0512 护士节", "0518 博物馆日", "0519 旅游日", "0601 儿童节",
            "0701 建党节", "0801 建军节", "0910 教师节","1001 国庆节", "1024 联合国日", "1204 宪法日", "1224 平安夜", "1225 圣诞节"};
    //格式化日期
    static SimpleDateFormat chineseDateFormat = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);
    static SimpleDateFormat solarDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    /**
     *	 返回农历y年的总天数
     * @param y
     * @return
     */
    private int lunarYearDays(int y) {
        int i, sum = 348;
        for (i = 0x8000; i > 0x8; i >>= 1) {
            sum += ((lunarInfo[y - 1900] & i) != 0 ? 1 : 0);
        }
        return (sum + leapDays(y));
    }

    /**
     * 	返回农历y年闰月的天数
     */
    private int leapDays(int y) {
        if (leapMonth(y) != 0) {
            return ((lunarInfo[y - 1900] & 0x10000) != 0 ? 30 : 29 );
        } else
            return 0;
    }

    /**
     * 	判断y年的农历中那个月是闰月,不是闰月返回0
     * @param y
     * @return
     */
    private int leapMonth(int y) {
        return  (int) (lunarInfo[y - 1900] & 0xf);
    }

    /**
     * 	返回农历y年m月的总天数
     * @param y
     * @param m
     * @return
     */
    private int monthDays(int y, int m) {
        return ((lunarInfo[y - 1900] & (0x10000 >> m))!=0 ? 30 : 29);
    }

    /**
     * 	获取阴历年
     * @param year
     * @return
     */
    private String getLunarYearString(String year) {
        int y1 = Integer.parseInt(year.charAt(0)+"");
        int y2 = Integer.parseInt(year.charAt(1)+"");
        int y3 = Integer.parseInt(year.charAt(2)+"");
        int y4 = Integer.parseInt(year.charAt(3)+"");
        return lunarYears[y1]+lunarYears[y2]+lunarYears[y3]+lunarYears[y4];
    }

    /**
     *	 获取阴历日
     */
    private String getLunarDayString(int day) {
        int n = day % 10 == 0 ? 9 : day % 10 - 1;
        if (day > 30)
            return "";
        if (day == 10)
            return "初十";
        else
            return chineseTen[day / 10] + lunarNumber[n];
    }

    /**
     * 	特例,特殊的年分的节气偏移量,由于公式并不完善,所以算出的个别节气的第几天数并不准确,在此返回其偏移量
     * @param year 年份
     * @param n 节气编号
     * @return 返回其偏移量
     */
    private int specialYearOffset(int year,int n) {
        int offset = 0;
        offset += getOffset(DECREASE_OFFSETMAP,year,n,-1);
        offset += getOffset(INCREASE_OFFSETMAP,year,n,1);
        return offset;
    }

    /**
     * 	节气偏移量计算
     * @param map
     * @param year
     * @param n
     * @param offset
     * @return
     */
    private int getOffset(Map<Integer,Integer[]> map,int year,int n,int offset){
        int off = 0;
        Integer[] years = map.get(n);
        if(null != years){
            for(int i:years){
                if(i == year){
                    off = offset;
                    break;
                }
            }
        }
        return off;
    }

    /**
     *	 获取某年的第n个节气为几日(从0小寒起算)
     * @param year
     * @param n
     * @return
     */
    private int sTerm(int year, int n) {
        double centuryValue = 0;//节气的世纪值,每个节气的每个世纪值都不同
        int centuryIndex = -1;
        if(year>=1901 && year<=2000){//20世纪
            centuryIndex = 0;
        } else if(year>=2001 && year <= 2100){//21世纪
            centuryIndex = 1;
        } else {
            throw new RuntimeException("不支持此年份:"+year+",目前只支持1901年到2100年的时间范围");
        }
        centuryValue = CENTURY_ARRAY[centuryIndex][n];
        int dateNum = 0;

        int y = year%100;//步骤1:取年分的后两位数
        if(year%4 == 0 && year%100 !=0 || year%400 ==0){//闰年
            if(n == 0 || n == 1 || n == 2 || n == 3){
                //注意:凡闰年3月1日前闰年数要减一,即:L=[(Y-1)/4],因为小寒、大寒、立春、雨水这两个节气都小于3月1日,所以 y = y-1
                y = y-1;//步骤2
            }
        }
        dateNum = (int)(y*D+centuryValue)-(int)(y/4);//步骤3,使用公式[Y*D+C]-L计算
        dateNum += specialYearOffset(year,n);//步骤4,加上特殊的年分的节气偏移量
        return dateNum;
    }

    /**
     *	 母亲节和父亲节
     * @param year
     * @param month
     * @param day
     * @return
     */
    private  String getMotherOrFatherDay(int year, int month, int day) {
        if (month != 5 && month != 6) return null;
        if ((month == 5 && (day < 8 || day > 14)) || (month == 6 && (day < 15 || day > 21))) return null;
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        int weekDate = calendar.get(Calendar.DAY_OF_WEEK);
        weekDate = (weekDate == 1) ? 7 : weekDate - 1;
        switch (month) {
            case 5:
                if (day == 15 - weekDate) {
                    return "母亲节";
                }
                break;
            case 6:
                if (day == 22 - weekDate) {
                    return "父亲节";
                }
                break;
        }
        return null;
    }

    /**
     *	 感恩节
     * @param year
     * @param month
     * @param day
     * @return
     */
    private String thanksgiving(int year, int month, int day) {
        if (month != 11) return null;
        if ((month == 11 && (day < 19 || day > 28))) return null;
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        int weekDate = calendar.get(Calendar.DAY_OF_WEEK);
        weekDate = (weekDate == 1) ? 7 : weekDate - 1;
        switch (month) {
            case 11:
                if (day == 29 - weekDate + 4) {
                    return "感恩节";
                }
                break;
        }
        return null;
    }

    /**
     * 	获取复活节
     * @param year
     * @param month
     * @param day
     * @return
     */
    private String getEasterDay(int year, int month, int day) {
        int n = year - 1900;
        int a = n % 19;
        int q = n / 4;
        int b = (7 * a + 1) / 19;
        int m = (11 * a + 4 - b) % 29;
        int w = (n + q + 31 - m) % 7;
        int answer = 25 - m - w;
        String easterDay = "";
        if (answer > 0) {
            easterDay = year+"-"+4+"-"+answer;
        } else {
            easterDay = year+"-"+3+"-"+(31 + answer);
        }
        String searchDay = year+"-"+month+"-"+day;
        if(searchDay.equals(easterDay)) {
            return "复活节";
        }
        return null;
    }

    /**
     * 	输入公历日期初始化当前日期的生肖、天干地支、农历年、农历月、农历日、公历节日、农历节日、24节气
     * 	输入日期的格式为(YYYY-MM-DD)
     * @param currentDate
     */
    public void initLunarCalendarInfo(String currentDate){
        String[] splitDate = currentDate.split("-");
        //设置生肖
        int year = Integer.parseInt(splitDate[0]);
        this.animal=animals[(year - 4) % 12];
        //设置天干地支
        int num = year - 1900 + 36;
        this.ganZhiYear =  (tGan[num % 10] + dZhi[num % 12]);
        ///设置阴历/
        //基准日期
        Date baseDate = null;
        //当前日期
        Date nowaday = null;
        try {
            baseDate = chineseDateFormat.parse("1900年1月31日");
            nowaday = solarDateFormat.parse(currentDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 获取当前日期与1900年1月31日相差的天数
        int offset = (int) ((nowaday.getTime() - baseDate.getTime()) / 86400000L);

        //用offset减去每农历年的天数,计算当天是农历第几天 iYear最终结果是农历的年份
        int iYear, daysOfYear = 0;
        for (iYear = 1900; iYear < 10000 && offset > 0; iYear++) {
            daysOfYear = lunarYearDays(iYear);
            offset -= daysOfYear;
        }
        if (offset < 0) {
            offset += daysOfYear;
            iYear--;
        }
        this.lunarYear = getLunarYearString(iYear+"");
        int leapMonth = leapMonth(iYear); // 闰哪个月,1-12
        boolean leap = false;

        // 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
        int iMonth, daysOfMonth = 0;
        for (iMonth = 1; iMonth < 13 && offset > 0; iMonth++) {
            // 闰月
            if (leapMonth > 0 && iMonth == (leapMonth + 1) && !leap) {
                --iMonth;
                leap = true;
                daysOfMonth = leapDays(iYear);
            } else
                daysOfMonth = monthDays(iYear, iMonth);

            offset -= daysOfMonth;
            // 解除闰月
            if (leap && iMonth == (leapMonth + 1))
                leap = false;
        }
        // offset为0时,并且刚才计算的月份是闰月,要校正
        if (offset == 0 && leapMonth > 0 && iMonth == leapMonth + 1) {
            if (leap) {
                leap = false;
            } else {
                leap = true;
                --iMonth;
            }
        }
        // offset小于0时,也要校正
        if (offset < 0) {
            offset += daysOfMonth;
            --iMonth;
        }
        // 设置对应的阴历月份
        this.lunarMonth = lunarNumber[iMonth - 1] ;
        if("一".equals(this.lunarMonth)){
            this.lunarMonth ="正";
        }
        if("十二".equals(this.lunarMonth)){
            this.lunarMonth ="腊";
        }
        if(leap){
            this.lunarMonth ="闰"+this.lunarMonth;
        }

        //设置阴历日
        int iDay = offset + 1;
        this.lunarDay = getLunarDayString(iDay);

        //设置节气
        int month=Integer.parseInt(splitDate[1]);
        int day=Integer.parseInt(splitDate[2]);
        if (day == sTerm(year, (month - 1) * 2)){
            this.lunarTerm = solarTerms[(month - 1) * 2];
        }else if (day == sTerm(year, (month - 1) * 2 + 1)){
            this.lunarTerm = solarTerms[(month - 1) * 2 + 1];
        }else{
            this.lunarTerm = "";
        }

        //设置阳历节日
        String solarFestival="";
        for (int i = 0; i < solarHoliday.length; i++) {
            // 返回公历节假日名称
            String sd = solarHoliday[i].split(" ")[0]; // 节假日的日期
            String sdv = solarHoliday[i].split(" ")[1]; // 节假日的名称
            String smonth_v = splitDate[1];
            String sday_v = splitDate[2];
            String smd = smonth_v + sday_v;
            if (sd.trim().equals(smd.trim())) {
                solarFestival =  sdv;
                break;
            }
        }
        //判断节日是否是父亲节或母亲节
        String motherOrFatherDay = getMotherOrFatherDay(year, month, day);
        if(motherOrFatherDay != null ){
            solarFestival = motherOrFatherDay;
        }
        //判断节日是否是复活节
        String easterDay = getEasterDay(year, month, day);
        if(easterDay != null ){
            solarFestival = easterDay;
        }
        //判断节日是否是感恩节
        String thanksgiving = thanksgiving(year, month, day);
        if(thanksgiving != null ){
            solarFestival = thanksgiving;
        }
        this.solarFestival = solarFestival;

        //设置阴历节日
        String lunarFestival="";
        for (int i = 0; i < lunarHoliday.length; i++) {
            //阴历闰月节日
            if(leap){
                break;
            }
            // 返回农历节假日名称
            String ld = lunarHoliday[i].split(" ")[0]; // 节假日的日期
            String ldv = lunarHoliday[i].split(" ")[1]; // 节假日的名称
            String lmonth_v = iMonth + "";
            String lday_v = iDay + "";
            String lmd = "";
            if (iMonth < 10) {
                lmonth_v = "0" + iMonth;
            }
            if (iDay < 10) {
                lday_v = "0" + iDay;
            }
            lmd = lmonth_v + lday_v;
            if ("12".equals(lmonth_v)) { // 除夕夜需要特殊处理
                if ((daysOfMonth == 29 && iDay == 29) || (daysOfMonth == 30 && iDay == 30)) {
                    lunarFestival = "除夕";
                    break;
                }
            }
            if (ld.trim().equals(lmd.trim())) {
                lunarFestival = ldv;
                break;
            }
        }
        if("清明".equals(this.lunarTerm)){
            lunarFestival = "清明节";
        }
        this.lunarFestival = lunarFestival;
    }


    /**
     * 根据日期获取当前周几
     * @param strDate   yyyy-MM-dd
     * @return  0 周日   1-6  周一到周六
     * @throws ParseException
     */
    public static int getWeek(String strDate) {
        int year = Integer.parseInt(strDate.substring(0, 4));
        int month = Integer.parseInt(strDate.substring(5, 7));
        int day = Integer.parseInt(strDate.substring(8, 10));
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month - 1);
        c.set(Calendar.DAY_OF_MONTH, day);
        int weekIndex = c.get(Calendar.DAY_OF_WEEK);
        return weekIndex - 1;
    }
}

5. 自定义组合控件

public class Calendarview extends LinearLayout {
    Context context;

    public Calendarview(Context context) {
        super(context);
        context = context;
        initView();
    }

    public Calendarview(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        initTypedArray(context, attrs);
        initView();
    }

    public Calendarview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initTypedArray(context, attrs);
        initView();
    }
    /**
     * 监听
     */
    private onChangeDateListener onChangeDateListener;
    public static interface onChangeDateListener {
        public void onChangeDate(String str);
    }
    public void setOnChangeDate(onChangeDateListener listener) {
        onChangeDateListener = listener;
    }
    
    /**
     * 属性
     *
     * @param c
     * @param attrs
     */
    private void initTypedArray(Context c, AttributeSet attrs) {
        TypedArray mTypedArray = c.obtainStyledAttributes(attrs, R.styleable.Calendarview);
        String year = mTypedArray.getString(R.styleable.Calendarview_year);
        String month = mTypedArray.getString(R.styleable.Calendarview_month);
        String day = mTypedArray.getString(R.styleable.Calendarview_day);
        if(!(year==null || year.equals("")) && !(month==null || month.equals(""))){
            nYYearMonthChoose = new NYyearmonth(Integer.parseInt(year),Integer.parseInt(month),true);
        }else{
            nYYearMonthChoose = new NYyearmonth(getCurrent(CurrentType.YYYY) ,getCurrent(CurrentType.MM) ,true);
        }
        if(!(day==null || day.equals(""))){
            nyRjqfz = new NYRjq(Integer.parseInt(day));
        }else{
            nyRjqfz = new NYRjq(getCurrent(CurrentType.dd));
        }
        //获取资源后要及时回收
        mTypedArray.recycle();
    }
    
    /**
     * 年月适配器
     */
    GridCalendarNYAdapter gridGNAdapter;
    /**
     * 日 适配器
     */
    GridCalendarDaysAdapter gridCalendarDaysAdapter;
    /**
     * 过去 100 年
     */
    private int past = 100;
    /**
     * 未来 100 年
     */
    private int future = 100;

    /**
     * 所有年月
     */
    private List<NYyearmonth> nYyearmonthLists;
    /**
     * 当前所有年月
     */
    private List<NYyearmonth> CurrentLists;
    /**
     * 当前选择的年月
     */
    private NYyearmonth nYYearMonthChoose;
    /**
     * 当前选择的日
     */
    private NYRjq nyRjqfz;
    /**
     * 当前选择月份显示日
     */
    ArrayList<NYRjq> nyRjqs;
    /**
     * 上个月显示几位
     */
    int start;
    /**
     * 下个月显示几位
     */
    int end;
    /**
     * 年月
     */
    View sl_view_calendar_ny;
    /**
     * 日
     */
    View sl_view_calendar_day;
    /**
     * 初始化
     */
    private void initView() {
        LayoutInflater.from(context).inflate(R.layout.sl_view_calendar, this, true);
        sl_view_calendar_ny = (View) findViewById(R.id.sl_view_calendar_ny);
        sl_view_calendar_day = (View) findViewById(R.id.sl_view_calendar_day);
        
        InitNyList(false);
        InitNy(nYYearMonthChoose.getYear());
        InitDay();
        InitDay2();
        InitTop();
    }

    /**
     * 顶部布局
     */
    private void InitTop() {
        View calendar_title = (View) findViewById(R.id.calendar_title);
        ImageView calendar_title_shuaxin = (ImageView) findViewById(R.id.calendar_title_shuaxin);
        /**
         * 左侧年月点击
         */
        calendar_title.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (sl_view_calendar_ny.getVisibility() == VISIBLE) {
                    sl_view_calendar_ny.setVisibility(GONE);
                } else {
                    sl_view_calendar_ny.setVisibility(VISIBLE);
                }
                if (sl_view_calendar_day.getVisibility() == VISIBLE) {
                    sl_view_calendar_day.setVisibility(GONE);
                } else {
                    sl_view_calendar_day.setVisibility(VISIBLE);
                }
            }
        });
        /**
         * 右侧刷新点击
         */
        calendar_title_shuaxin.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                InitNyList(true);
                InitNy(getCurrent(CurrentType.YYYY));
                InitDay();
                InitDay2();
                InitTop();
            }
        });
        LeftBuJu();
    }
    /**
     * 顶部左侧  中
     */
    private void LeftBuJu() {
        TextView calendar_title_year = findViewById(R.id.calendar_title_year);
        TextView calendar_title_month = findViewById(R.id.calendar_title_month);
        TextView calendar_title_ym = findViewById(R.id.calendar_title_ym);
        calendar_title_year.setText(nYYearMonthChoose.getYear() + "");
        calendar_title_month.setText(NYyearmonth.repair(nYYearMonthChoose.getMonth()));
        LunarUtils festival = new LunarUtils();
        festival.initLunarCalendarInfo(nYYearMonthChoose.GetStr() + "-01");
        calendar_title_ym.setText(festival.getGanZhiYear() + festival.getAnimal() + "年");
    }
    /**
     * 初始化   日
     */
    private void InitDay() {
        NYyearmonth nYyearmonth = nYYearMonthChoose;
        NYyearmonth abovenYyearmonth = null;
        NYyearmonth nextnYyearmonth = null;

        abovenYyearmonth = nYyearmonthLists.stream()
                .filter((NYyearmonth s) -> nYyearmonth.getMonth() == 1 ?
                        s.getYear() == nYyearmonth.getYear() - 1 && s.getMonth() == 12 :
                        s.getYear() == nYyearmonth.getYear() && s.getMonth() == nYyearmonth.getMonth() - 1)
                .findFirst().get();
        nextnYyearmonth = nYyearmonthLists.stream()
                .filter((NYyearmonth s) -> nYyearmonth.getMonth() == 12 ?
                        s.getYear() == nYyearmonth.getYear() + 1 && s.getMonth() == 1 :
                        s.getYear() == nYyearmonth.getYear() && s.getMonth() == nYyearmonth.getMonth() + 1)
                .findFirst().get();


        /**
         * 当前月份天数
         */
        int days = nYyearmonth.getDays();
        /**
         * 上月份天数
         */
        int abovedays = abovenYyearmonth.getDays();
        /**
         * 下月份天数
         */
        int nextdays = nextnYyearmonth.getDays();
        /**
         * 日 一行显示
         */
        int column = 7;
        start = LunarUtils.getWeek(nYyearmonth.GetStr() + "-01");
        end = 6 * column - start - days;
        nyRjqs = new ArrayList<>();


        for (int i = abovedays - start; i < abovedays; i++) {
            LunarUtils festival = new LunarUtils();
            festival.initLunarCalendarInfo(abovenYyearmonth.GetStr() + "-" + NYyearmonth.repair(i + 1));
            nyRjqs.add(new NYRjq(i + 1, festival.getLunarDay(), festival.getLunarTerm(), festival.getSolarFestival() + " " + festival.getLunarFestival()));
        }
        o = 0;
        oo = false;
        setDayLists(nYyearmonth, days, nyRjqs);
        setDayLists(nextnYyearmonth, end, nyRjqs);


        // Log.d("日期选择初始化选择为:------------", nYyearmonth.getStringYearMonth() + nyRjqfz.getCurrent() + "日");

        if(onChangeDateListener!=null) onChangeDateListener.onChangeDate(nYyearmonth.GetStr()+"-"+NYyearmonth.repair(nyRjqfz.getCurrent()));
    }

    private void InitDay2() {
        gridCalendarDaysAdapter = new GridCalendarDaysAdapter(nyRjqs, context);
        CustomGridView customGridView = sl_view_calendar_day.findViewById(R.id.calendar_days_gridview);
        customGridView.setAdapter(gridCalendarDaysAdapter);

        customGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                NYRjq nymItem = nyRjqs.get(position);
                nymItem.setIsCruuent(true);
                if (position + 1 <= start) {
                    nYYearMonthChoose = GetIsnYYearMonthChoose(-1);
                } else if (position + 1 > nyRjqs.size() - end) {
                    nYYearMonthChoose = GetIsnYYearMonthChoose(1);
                } else {
                    for (int i = 0; i < nyRjqs.size(); i++) {
                        nyRjqs.get(i).setIsCruuent(false);
                        if (i == position) {
                            nyRjqs.get(i).setIsCruuent(true);
                        }
                    }
                }
                nyRjqfz = nymItem;
                LeftBuJu();
                InitDay();
                InitDay2();
                InitNy(nYYearMonthChoose.getYear());
                gridGNAdapter.notifyDataSetChanged();
                gridCalendarDaysAdapter.notifyDataSetChanged();
            }
        });
    }
    private NYyearmonth GetIsnYYearMonthChoose(int i) {
        int year = nYYearMonthChoose.getYear();
        int month = nYYearMonthChoose.getMonth();
        if (month == 1 && i<0) {
            year = year - 1;
            month = 12;
        }else if (month == 12 && i>0) {
            year = year + 1;
            month = 1;
        }else{
            month = month + i;
        }

        return new NYyearmonth(year, month, true);
    }

    int o = 0;
    Boolean oo = false;
    private void setDayLists(NYyearmonth nextnYyearmonth, int end, List<NYRjq> nyRjqs) {
        for (int i = 1; i <= end; i++) {
            LunarUtils festival = new LunarUtils();
            festival.initLunarCalendarInfo(nextnYyearmonth.GetStr() + "-" + NYyearmonth.repair(i));
            if (i == nyRjqfz.getCurrent() && o == 0) {
                o = 1;
                oo = true;
            } else {
                oo = false;
            }
            nyRjqs.add(new NYRjq(i, festival.getLunarDay(), festival.getLunarTerm(), festival.getSolarFestival() + " " + festival.getLunarFestival(), oo));
        }
    }
    /**
     * 初始化 年月
     */
    private void InitNy(int year) {
        CustomGridView customGridView = sl_view_calendar_ny.findViewById(R.id.calendar_ny_gridview);
        List<NYyearmonth> list = GetCurentYear(year);
        gridGNAdapter = new GridCalendarNYAdapter(list, context);
        customGridView.setAdapter(gridGNAdapter);
        customGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                NYyearmonth nymItem = list.get(position);
                nymItem.setIs(true);
                for (int i = 0; i < list.size(); i++) {
                    list.get(i).setIs(false);
                    if (i == position) {
                        list.get(i).setIs(true);
                    }
                }
                nYYearMonthChoose = nymItem;
                if (sl_view_calendar_ny.getVisibility() == VISIBLE) {
                    sl_view_calendar_ny.setVisibility(GONE);
                } else {
                    sl_view_calendar_ny.setVisibility(VISIBLE);
                }
                if (sl_view_calendar_day.getVisibility() == VISIBLE) {
                    sl_view_calendar_day.setVisibility(GONE);
                } else {
                    sl_view_calendar_day.setVisibility(VISIBLE);
                }
                LeftBuJu();
                InitDay();
                InitDay2();
                gridGNAdapter.notifyDataSetChanged();
                gridCalendarDaysAdapter.notifyDataSetChanged();
            }
        });
    }
    /**
     * 获取指定年份的集合
     *
     * @return
     */
    private List<NYyearmonth> GetCurentYear(int year) {
        List<NYyearmonth> list = new ArrayList<>();
        List<NYyearmonth> list1 = new ArrayList<>();
        list = nYyearmonthLists.stream()
                .filter((NYyearmonth s) -> s.getYear() == year)
                .collect(Collectors.toList());
        for (int i = 0; i < list.size(); i++) {
            NYyearmonth n = list.get(i);
            n.setIs(false);
            if(n.getYear()==nYYearMonthChoose.getYear() && n.getMonth()==nYYearMonthChoose.getMonth()){
                n.setIs(true);
            }
            list1.add(n);
        }
        CurrentLists = list1;
        return list1;
    }
    /**
     * 初始化年月 List
     */
    private void InitNyList(Boolean b) {
        nYyearmonthLists = getNYAll(past, future);
        if(b){
            nYYearMonthChoose = new NYyearmonth(getCurrent(CurrentType.YYYY), getCurrent(CurrentType.MM), true);
            nyRjqfz = new NYRjq(getCurrent(CurrentType.dd));
        }
    }
    /**
     * 根据过去和未来获取所有年月
     *
     * @param past   过去
     * @param future 未来
     */
    private List<NYyearmonth> getNYAll(int past, int future) {
        /**
         * 年
         */
        int year = getCurrent(CurrentType.YYYY);
        /**
         * 过去年
         */
        int pastyear = getCurrent(CurrentType.YYYY) - past;
        /**
         * 未来年
         */
        int futureyear = getCurrent(CurrentType.YYYY) + future;
        /**
         * 年 汇总
         */
        List<Integer> zList = new ArrayList<>();
        /**
         * 月
         */
        int month = getCurrent(CurrentType.MM);
        int mzNum = 12;
        /**
         * 年月 汇总
         */
        List<NYyearmonth> zNYList = new ArrayList<>();

        for (int i = 0; i < past; i++) {
            zList.add(pastyear + i);
        }
        for (int i = future; i >= 0; i--) {
            zList.add(futureyear - i);
        }

        for (int j = 0; j < zList.size(); j++) {
            for (int i = 0; i < mzNum; i++) {
                zNYList.add(new NYyearmonth(zList.get(j), i + 1, zList.get(j) == year && (i + 1) == month));
            }
        }

        return zNYList;

    }
    /**
     * 获取当前时间
     *
     * @return
     */
    private int getCurrent(CurrentType type) {
        /**
         * 当前时间
         */
        Calendar current = Calendar.getInstance();
        current.setTime(new Date());
        int t = 0;
        switch (type) {
            case YYYY:
                t = current.get(Calendar.YEAR);
                break;
            case MM:
                t = current.get(Calendar.MONTH) + 1;
                break;
            case dd:
                t = current.get(Calendar.DATE);
                break;
            case HH:
                // t = current.get(Calendar.HOUR);	 //(12小时制)
                t = current.get(Calendar.HOUR_OF_DAY); // (24小时制)
                break;
            case mm:
                t = current.get(Calendar.MINUTE);     //分
                break;
            case ss:
                t = current.get(Calendar.SECOND);     //秒
                break;
        }
        return t;
    }
}

总结

使用
提示:刚开始构思的时候没有考虑适配,所以用了过去/未来两个变量,后面考虑到了之后就懒得想了

  <com.example.accounting.utils.toolView.Calendarview
                        xmlns:custom="http://schemas.android.com/apk/res-auto"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        custom:year="2024"
                        custom:month="10"
                        custom:day="1"
                        android:id="@+id/zdyrl"
                />
Calendarview c = findViewById(R.id.zdyrl);
c.setOnChangeDate(new Calendarview.onChangeDateListener() {
	@Override
    public void onChangeDate(String str) {
         // str   例子: 2023-10-16   
    }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值