一步一步構(gòu)建自己的簡單日歷控件 MySimpleCalendar(篇一)

日歷控件大家應(yīng)該不陌生简软,github 上面一搜一大堆,但是我們拿到 github 上面的一個日歷控件钮追,想動手改改功能改改需求,有時可能會覺得無從下手阿迈,(當然了元媚,老司機就忽略我說的 —∶绮祝—)那么刊棕,如果想知道一個日歷控件是如何從無到有構(gòu)建起來的,不妨各位看官快速瀏覽一下我的這篇文章待逞。
文章主要是帶大家一步一步熟悉構(gòu)建的流程甥角,并沒有什么特別酷炫狂拽的效果。

先上一個效果圖鎮(zhèn)鎮(zhèn)樓识樱。


MySimpleCalendar 控件

一嗤无、數(shù)據(jù)準備

1、實體類 MyCalendarBean

/**
 * Created by deeson.woo
 */
public class MyCalendarBean {

    private int year;
    private int month;//1-12
    private int day;//1-31

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

    public int getYear() {
        return year;
    }

    public int getMonth() {
        return month;
    }

    public int getDay() {
        return day;
    }
}

2怜庸、構(gòu)建日期實體

    /**
     * 構(gòu)建具體一天的對象
     * @param year
     * @param month
     * @param day
     * @return
     */
    public MyCalendarBean generateCalendarBean(int year, int month, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, day);
        year = calendar.get(Calendar.YEAR);
        month = calendar.get(Calendar.MONTH) + 1;
        day = calendar.get(Calendar.DATE);

        return new MyCalendarBean(year, month, day);
    }

3当犯、打印當前月份的所有日期

    /**
     * 獲取當前月份的日期列表
     * @param year
     * @param month
     * @return
     */
    public List<MyCalendarBean> getDaysListOfMonth(int year, int month) {

        List<MyCalendarBean> list = new ArrayList<>();

        int daysOfMonth = getDaysOfCertainMonth(year, month);

        for (int i = 0; i < daysOfMonth; i++) {
            MyCalendarBean bean = generateCalendarBean(year, month, i + 1);
            list.add(bean);
        }
        return list;
    }

    /**
     * 獲取具體月份的最大天數(shù)
     *
     * @param year
     * @param month
     * @return
     */
    public static int getDaysOfCertainMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        return calendar.getActualMaximum(Calendar.DATE);
    }
//測試打印2018年2月份
printDaysList(getDaysListOfMonth(2018, 2));

2018年2月 = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 }

二、展示日期

1割疾、將月份的所有日期按照7列展示

自定義ViewGroup(MonthCalendarView)

/**
 * Created by deeson.woo
 * 月份視圖
 */

public class MonthCalendarView extends ViewGroup {

    private int column = 7;

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

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

}
(1)onMeasure()方法
  • 拿到控件的寬度嚎卫,分成七份,賦給 item 的寬度和高度
  • 同時計算控件所需的高度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        
        int parentWidth = MeasureSpec.getSize(MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.EXACTLY));

        //將寬度平均分成七份宏榕,每個item的寬高都等于它
        int itemWidth = parentWidth / column;
        int itemHeight = itemWidth;

        int parentHeight = 0;

        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);
            childView.measure(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY));
            
            //計算控件所需的高度
            if (i % column == 0) {
                parentHeight += childView.getMeasuredHeight();
            }
        }

        setMeasuredDimension(parentWidth, parentHeight);
    }
(2)onLayout()方法
  • 按照七列布局的設(shè)計拓诸,計算出每個 item 的 left, top, right, bottom侵佃,精確地添加到控件里
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        for (int i = 0; i < getChildCount(); i++) {
            View itemView = getChildAt(i);
            int columnCount = i % column;
            int rowCount = i / column;

            int itemWidth = itemView.getMeasuredWidth();
            int itemHeight = itemView.getMeasuredHeight();

            left = columnCount * itemWidth;
            top = rowCount * itemHeight;
            right = left + itemWidth;
            bottom = top + itemHeight;
            itemView.layout(left, top, right, bottom);
        }
    }
(3)填充月份日期數(shù)據(jù)
  • 暴露一個公共方法用于填充數(shù)據(jù)
  • 根據(jù)傳進來的年、月恰响,構(gòu)建日期列表
  • 逐一構(gòu)建 itemView趣钱,填充到控件里
  • 調(diào)用requestLayout()方法,重新繪制
    public void setMonth(int year, int month) {
        mList = calendarUtils.getDaysListOfMonth(year, month);
        addAllItem();
        requestLayout();
    }

    private void addAllItem() {
        for (int i = 0; i < mList.size(); i++) {
            MyCalendarBean bean = mList.get(i);

            View itemView = generateDateView(bean);
            addViewInLayout(itemView, i, itemView.getLayoutParams(), true);
        }
    }

    private View generateDateView(MyCalendarBean bean) {
        View itemView = LayoutInflater.from(getContext()).inflate(R.layout.item_date_view, null);
        if (bean.isCurrentMonth()) {
            TextView date = itemView.findViewById(R.id.date);
            date.setText(String.valueOf(bean.getDay()));
        }
        return itemView;
    }

把 item_date_view.xml 布局也放出來

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textSize="14sp"
        android:textColor="@color/text_black"
        />

</RelativeLayout>

2胚宦、在布局中使用

<?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="match_parent"
    android:orientation="vertical"
    android:background="@color/background_white"
    >

    <com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView
        android:id="@+id/month_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent">

    </com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView>

</LinearLayout>

3首有、在 MainActivity 中的使用

package com.example.deesonwoo.mysimplecalendar;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView;
import com.example.deesonwoo.mysimplecalendar.calendar.MyCalendarBean;
import com.example.deesonwoo.mysimplecalendar.calendar.MyCalendarUtils;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    MonthCalendarView monthView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        monthView = findViewById(R.id.month_view);
        initCalendar();
    }

    private void initCalendar() {
        //測試顯示2018年3月
        monthView.setMonth(2018, 3);
    }
}

效果展示如下:

2018年3月

4、添加頂部周布局

<?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="match_parent"
    android:orientation="vertical"
    android:background="@color/background_white"
    >


    <LinearLayout
        android:id="@+id/week_layout"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal"
        android:background="@color/white"
        >

        <TextView
            android:id="@+id/week_00"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周日"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_01"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周一"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_02"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周二"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_03"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周三"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_04"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周四"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_05"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周五"
            android:textColor="@color/text_black"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/week_06"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="周六"
            android:textColor="@color/text_black"
            android:textSize="12sp" />
    </LinearLayout>

    <com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView
        android:id="@+id/month_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent">

    </com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView>

</LinearLayout>

效果如下:


2018年3月

5枢劝、優(yōu)化日期與星期的對應(yīng)關(guān)系

相信你們已經(jīng)發(fā)現(xiàn)井联,上面展示的效果中,日期與星期并沒有進行一一對應(yīng)的排布您旁。接下來烙常,一起我們優(yōu)化一下。

  • 找到當前月份第一天對應(yīng)的星期
  • 修改工具類方法 getDaysListOfMonth()鹤盒, 將前面空缺的上一個月的日期填充到月份列表中
  • 將上個月的日期隱藏
(1)在 MyCalendarUtils 工具類中添加下面“獲取具體一天對應(yīng)的星期”的方法
    /**
     * 獲取具體一天對應(yīng)的星期
     *
     * @param year
     * @param month
     * @param day
     * @return 1-7(周日-周六)
     */
    private int getWeekDayOnCertainDate(int year, int month, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, day);
        return calendar.get(Calendar.DAY_OF_WEEK);
    }
(2)修改 getDaysListOfMonth()方法蚕脏,將前面空缺的上一個月的日期填充到月份列表中
    /**
     * 獲取當前月份的日期列表
     *
     * @param year
     * @param month
     * @return
     */
    public List<MyCalendarBean> getDaysListOfMonth(int year, int month) {

        List<MyCalendarBean> list = new ArrayList<>();

        int daysOfMonth = getDaysOfCertainMonth(year, month);

        //找到當前月第一天的星期,計算出前面空缺的上個月的日期個數(shù)侦锯,填充到當月日期列表中
        int weekDayOfFirstDay = getWeekDayOnCertainDate(year, month, 1);
        int preMonthDays = weekDayOfFirstDay - 1;

        for (int i = preMonthDays; i > 0; i--) {
            MyCalendarBean preMonthBean = generateCalendarBean(year, month, 1 - i);
            list.add(preMonthBean);
        }

        for (int i = 0; i < daysOfMonth; i++) {
            MyCalendarBean monthBean = generateCalendarBean(year, month, i + 1);
            list.add(monthBean);
        }
        return list;
    }

展示效果如下:

2018年3月

顯然驼鞭,上一個月的日期在這里是需要區(qū)別展示或者需要隱藏的,不然會給用戶造成視覺上的困擾尺碰,這里挣棕,我直接做隱藏操作。

(3)給日期實體類增加當前月標識亲桥,isCurrentMonth洛心,并在構(gòu)建數(shù)據(jù)的時候給標識賦值。

實體類如下:

/**
 * Created by deeson.woo
 */
public class MyCalendarBean {

    private int year;
    private int month;//1-12
    private int day;//1-31
    private boolean isCurrentMonth = true;//是否為當前月份的日期

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

    public int getYear() {
        return year;
    }

    public int getMonth() {
        return month;
    }

    public int getDay() {
        return day;
    }

    public boolean isCurrentMonth() {
        return isCurrentMonth;
    }

    public void setCurrentMonth(boolean currentMonth) {
        isCurrentMonth = currentMonth;
    }
}

給標識賦值题篷,在 getDaysListOfMonth()中賦值:

    /**
     * 獲取當前月份的日期列表
     *
     * @param year
     * @param month
     * @return
     */
    public List<MyCalendarBean> getDaysListOfMonth(int year, int month) {

        List<MyCalendarBean> list = new ArrayList<>();

        int daysOfMonth = getDaysOfCertainMonth(year, month);

        //找到當前月第一天的星期词身,計算出前面空缺的上個月的日期個數(shù),填充到當月日期列表中
        int weekDayOfFirstDay = getWeekDayOnCertainDate(year, month, 1);
        int preMonthDays = weekDayOfFirstDay - 1;

        for (int i = preMonthDays; i > 0; i--) {
            MyCalendarBean preMonthBean = generateCalendarBean(year, month, 1 - i);
            preMonthBean.setCurrentMonth(false);
            list.add(preMonthBean);
        }

        for (int i = 0; i < daysOfMonth; i++) {
            MyCalendarBean monthBean = generateCalendarBean(year, month, i + 1);
            monthBean.setCurrentMonth(true);
            list.add(monthBean);
        }
        return list;
    }

最后修改我們自定義月歷類中 generateDateView()方法悼凑,不顯示上個月的日期:

    private View generateDateView(MyCalendarBean bean) {
        View itemView = LayoutInflater.from(getContext()).inflate(R.layout.item_date_view, null);
        if(bean.isCurrentMonth()){
            TextView date = itemView.findViewById(R.id.date);
            date.setText(String.valueOf(bean.getDay()));
        }
        return itemView;
    }

效果如下:


2018年3月

三偿枕、持續(xù)優(yōu)化改進

1、將靜態(tài)日歷改成動態(tài)可切換顯示

(1)添加頭部布局户辫,用于顯示當前月份以及翻頁
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/background_blue"
        >
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textSize="20sp"
            android:textColor="@color/white"
            />

        <ImageView
            android:id="@+id/pre_month"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true"
            android:src="@mipmap/btn_preview"
            />
        <ImageView
            android:id="@+id/next_month"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerVertical="true"
            android:layout_alignParentRight="true"
            android:src="@mipmap/btn_next"
            />

    </RelativeLayout>
(2)修改自定義月歷類
  • 增加當前顯示的年月成員變量

private int mYear, mMonth;

  • 修改構(gòu)造方法和填充數(shù)據(jù)的方法
    public MonthCalendarView(Context context) {
        super(context);
        calendarUtils = new MyCalendarUtils(context);
    }

    public MonthCalendarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        calendarUtils = new MyCalendarUtils(context);
    }

    public void setMonth(int year, int month) {
        this.mYear = year;
        this.mMonth = month;
        invalidateMonth();
    }

    private void invalidateMonth() {
        mList = calendarUtils.getDaysListOfMonth(mYear, mMonth);
        removeAllViews();
        addAllItem();
        requestLayout();
    }
  • 增加前翻頁渐夸、后翻頁方法
    /**
     * 展示上一個月
     */
    public void moveToPreMonth() {
        mMonth -= 1;
        invalidateMonth();
    }

    /**
     * 展示下一個月
     */
    public void moveToNextMonth() {
        mMonth += 1;
        invalidateMonth();
    }
  • 增加獲取當前顯示年月的方法
    public String getCurrentYearAndMonth() {
        return MyCalendarUtils.formatYearAndMonth(mYear, mMonth);
    }
(3)增加工具類方法
    /**
     * 格式化標題展示
     * @param year
     * @param month
     * @return
     */
    public static String formatYearAndMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        year = calendar.get(Calendar.YEAR);
        month = calendar.get(Calendar.MONTH) + 1;
        return year + "年" + month + "月";
    }

    /**
     * 獲取系統(tǒng)當前年月日
     *
     * @return
     */
    public static int[] getNowDayFromSystem() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        return new int[]{cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE)};
    }
(4)修改 MainActivity 類
  • 修改主題樣式
  • 增加頭部布局相關(guān)
  • 默認顯示系統(tǒng)當前年月
package com.example.deesonwoo.mysimplecalendar;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.deesonwoo.mysimplecalendar.calendar.MonthCalendarView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    MonthCalendarView monthView;
    ImageView btnPreMonth, btnNextMonth;
    TextView title;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);
        monthView = findViewById(R.id.month_view);
        initCalendar();
        initTitleView();
        updateTitle();
    }

    private void initCalendar() {
        int[] nowDay = MyCalendarUtils.getNowDayFromSystem();
        monthView.setMonth(nowDay[0], nowDay[1]);
    }

    private void initTitleView() {
        title = findViewById(R.id.title);
        btnPreMonth = findViewById(R.id.pre_month);
        btnNextMonth = findViewById(R.id.next_month);
        btnPreMonth.setOnClickListener(this);
        btnNextMonth.setOnClickListener(this);
    }

    /**
     * 刷新標題顯示年月
     */
    private void updateTitle() {
        String yearAndMonth = monthView.getCurrentYearAndMonth();
        title.setText(yearAndMonth);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.pre_month:
                monthView.moveToPreMonth();
                updateTitle();
                break;
            case R.id.next_month:
                monthView.moveToNextMonth();
                updateTitle();
                break;
        }
    }
}

最后顯示的效果如下動圖:


MyCalendar

2、增加高亮顯示系統(tǒng)當天日期

  • 增加工具類方法
    /**
     * 判斷是否為系統(tǒng)當天
     * @param bean
     * @return
     */
    public static boolean isToday(MyCalendarBean bean) {
        int[] nowDay = getNowDayFromSystem();
        return bean.getYear() == nowDay[0] && bean.getMonth() == nowDay[1] && bean.getDay() == nowDay[2];
    }
  • 修改自定義月歷類構(gòu)建日期的方法
    private View generateDateView(MyCalendarBean bean) {
        View itemView = LayoutInflater.from(getContext()).inflate(R.layout.item_date_view, null);
        if (bean.isCurrentMonth()) {
            TextView date = itemView.findViewById(R.id.date);
            if (MyCalendarUtils.isToday(bean)) {
                date.setBackgroundResource(R.drawable.item_today_bg);
            }
            date.setText(String.valueOf(bean.getDay()));
        }
        return itemView;
    }
  • 系統(tǒng)當天高亮顯示的背景 item_today_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid
        android:color="@color/theme_color" />

</shape>

效果如下:


MyCalendar

3渔欢、增加點擊日期效果

(1)修改自定義月歷類
  • 修改構(gòu)建日期方法
    private View generateDateView(MyCalendarBean bean) {
        View itemView = LayoutInflater.from(getContext()).inflate(R.layout.item_date_view, null);
        if (bean.isCurrentMonth()) {
            TextView date = itemView.findViewById(R.id.date);
            if (MyCalendarUtils.isToday(bean)) {
                date.setBackgroundResource(R.drawable.item_today_bg);
            } else {
                date.setBackgroundResource(R.drawable.item_pick_up);
            }
            date.setText(String.valueOf(bean.getDay()));
        }
        return itemView;
    }
  • item_pick_up.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true">
        <shape android:shape="oval">
            <stroke android:color="@color/theme_color" android:width="1dp"/>
        </shape>
    </item>

    <item android:drawable="@android:color/transparent" />
</selector>
  • 增加在主界面點擊的回調(diào)接口方法
    private OnDatePickUpListener onDatePickUpListener;

    public void setOnDatePickUpListener(OnDatePickUpListener onDatePickUpListener) {
        this.onDatePickUpListener = onDatePickUpListener;
    }

    public interface OnDatePickUpListener {
        void onDatePickUp(MyCalendarBean bean);
    }
  • 修改添加日期的方法墓塌,增加點擊監(jiān)聽
    private void addAllItem() {
        for (int i = 0; i < mList.size(); i++) {
            final MyCalendarBean bean = mList.get(i);

            final View itemView = generateDateView(bean);
            addViewInLayout(itemView, i, itemView.getLayoutParams(), true);
            final int position = i;
            itemView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {

                    if (pickUpPosition == position) {
                        return;
                    }

                    if (pickUpPosition != -1) {
                        getChildAt(pickUpPosition).setSelected(false);
                    }
                    itemView.setSelected(true);

                    if (null != onDatePickUpListener) {
                        onDatePickUpListener.onOnDatePickUp(bean);
                    }

                    pickUpPosition = position;
                }
            });
        }
    }
(2)在MainActivity中調(diào)用
    private void initCalendar() {
        int[] nowDay = MyCalendarUtils.getNowDayFromSystem();
        monthView.setMonth(nowDay[0], nowDay[1]);
        monthView.setOnDatePickUpListener(new MonthCalendarView.OnDatePickUpListener() {
            @Override
            public void onDatePickUp(MyCalendarBean bean) {
                Toast.makeText(MainActivity.this, bean.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }

效果如下動圖:


MyCalendar

四、整合自定義控件

大家可能覺得我們的自定義控件到這里就完結(jié)了,但是young苫幢、simple访诱、naive......(瞎bb)
秉著高內(nèi)聚低耦合的原則(再次瞎bb),我將剛剛出現(xiàn)的操作全部整合到一個控件SimpleCalendarView 中韩肝。
直接上代碼吧触菜,也沒幾行,就不做什么解釋了哀峻。

1涡相、SimpleCalendarView 類

  • 無非就是將標題視圖、星期視圖剩蟀、月歷視圖逐一添加到自定義SimpleCalendarView 類中催蝗,再將相關(guān)接口補上,請看下面代碼
package com.example.deesonwoo.mysimplecalendar.calendar;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.deesonwoo.mysimplecalendar.R;


public class SimpleCalendarView extends LinearLayout implements View.OnClickListener, MonthCalendarView.OnDatePickUpListener {

    private MonthCalendarView monthCalendarView;// 月歷
    private OnDatePickListener onDatePickListener;

    private TextView title;

    public SimpleCalendarView(Context context) {
        this(context, null);
    }

    public SimpleCalendarView(Context context, AttributeSet attrs) {
        super(context, attrs);

        setOrientation(VERTICAL);
        setBackgroundColor(context.getResources().getColor(R.color.white));

        // 年月標題育特、翻頁按鈕
        LayoutParams titleParams = new LayoutParams(LayoutParams.MATCH_PARENT, MyCalendarUtils.dp2px(context, 50));
        RelativeLayout titleLayout = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.title_layout, null);
        title = titleLayout.findViewById(R.id.title);
        ImageView preMonth = titleLayout.findViewById(R.id.pre_month);
        ImageView nextMonth = titleLayout.findViewById(R.id.next_month);
        preMonth.setOnClickListener(this);
        nextMonth.setOnClickListener(this);
        addView(titleLayout, titleParams);

        //星期布局
        LayoutParams weekParams = new LayoutParams(LayoutParams.MATCH_PARENT, MyCalendarUtils.dp2px(context, 40));
        LinearLayout weekLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.week_layout, null);
        addView(weekLayout, weekParams);

        //月歷視圖
        LayoutParams monthParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        monthCalendarView = new MonthCalendarView(context);
        initCalendarDate();
        monthCalendarView.setOnDatePickUpListener(this);
        addView(monthCalendarView, monthParams);
    }

    private void initCalendarDate() {
        int[] nowDay = MyCalendarUtils.getNowDayFromSystem();
        monthCalendarView.setMonth(nowDay[0], nowDay[1]);
        updateTitle();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.pre_month:
                if (null != monthCalendarView) {
                    monthCalendarView.moveToPreMonth();
                }
                updateTitle();
                break;
            case R.id.next_month:
                if (null != monthCalendarView) {
                    monthCalendarView.moveToNextMonth();
                }
                updateTitle();
                break;
        }
    }

    private void updateTitle() {
        if (null != title && null != monthCalendarView) {
            title.setText(monthCalendarView.getCurrentYearAndMonth());
        }
    }

    @Override
    public void onDatePickUp(MyCalendarBean bean) {
        if (null != onDatePickListener) {
            onDatePickListener.onDatePick(bean);
        }
    }

    public void setOnDatePickListener(OnDatePickListener onDatePickListener) {
        this.onDatePickListener = onDatePickListener;
    }

    public interface OnDatePickListener {
        void onDatePick(MyCalendarBean bean);
    }
}

2丙号、在布局中使用,非常簡單

<?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="match_parent"
    android:background="@color/background_white"
    android:orientation="vertical">

    <com.example.deesonwoo.mysimplecalendar.calendar.SimpleCalendarView
        android:id="@+id/calendarView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </com.example.deesonwoo.mysimplecalendar.calendar.SimpleCalendarView>

</LinearLayout>

3缰冤、在MainActivity 中調(diào)用

package com.example.deesonwoo.mysimplecalendar;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

import com.example.deesonwoo.mysimplecalendar.calendar.MyCalendarBean;
import com.example.deesonwoo.mysimplecalendar.calendar.SimpleCalendarView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        SimpleCalendarView calendarView = findViewById(R.id.calendarView);
        calendarView.setOnDatePickListener(new SimpleCalendarView.OnDatePickListener() {
            @Override
            public void onDatePick(MyCalendarBean bean) {
                Toast.makeText(MainActivity.this, bean.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

最后的效果就是文章開頭的動態(tài)圖犬缨。

五、后續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涮拗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迂苛,老刑警劉巖三热,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異三幻,居然都是意外死亡就漾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門念搬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抑堡,“玉大人,你說我怎么就攤上這事朗徊∈籽” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵爷恳,是天一觀的道長有缆。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么棚壁? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任杯矩,我火速辦了婚禮,結(jié)果婚禮上袖外,老公的妹妹穿的比我還像新娘史隆。我一直安慰自己,他們只是感情好曼验,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布泌射。 她就那樣靜靜地躺著,像睡著了一般蚣驼。 火紅的嫁衣襯著肌膚如雪魄幕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天颖杏,我揣著相機與錄音纯陨,去河邊找鬼。 笑死留储,一個胖子當著我的面吹牛翼抠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播获讳,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阴颖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了丐膝?” 一聲冷哼從身側(cè)響起量愧,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帅矗,沒想到半個月后偎肃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡浑此,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年累颂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凛俱。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡紊馏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒲犬,到底是詐尸還是另有隱情朱监,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布原叮,位于F島的核電站赌朋,受9級特大地震影響凰狞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沛慢,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一赡若、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧团甲,春花似錦逾冬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至匹厘,卻和暖如春嘀趟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背愈诚。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工她按, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炕柔。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓酌泰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匕累。 傳聞我的和親對象是個殘疾皇子陵刹,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354