天天看點

android自定義月曆實作事件提醒

轉載請注明出處:http://blog.csdn.net/ym4189/article/details/77008361

1.概述

前段時間項目需要一個月曆提醒,需求是:可以左右無限滑動,可點選監聽,根據事件日期在視圖中描出,右上角顯示事件個數。

在網上搜了很多,但是不是很滿足項目特定的需求,是以在網上的例子的基礎上自定義了一個,供大家參考。

2.先上圖

android自定義月曆實作事件提醒

這裡日期是自己畫的,沒有使用GridView,使用自定義view更友善。

我們通過計算每個月的日期,然後根據計算出來的位置繪制我們的日期。這裡使用标準的6*7方格圖。

我會把注釋放在代碼裡,直接上代碼:

1.CalendarView

package com.example.calendar;

import java.util.List;

import com.example.calendar.DateInfo;
import com.example.calendar.DateUtil;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public class CalendarView extends View {

    private static final String TAG = "CalendarView";

    /**
     * 列
     */
    private static final int TOTAL_COL = ;
    /**
     * 行
     */
    private static final int TOTAL_ROW = ;

    private Paint BlueBgPaint, HuiseBgPaint, mCirclePaint, linePaint;
    private Paint mTextPaint, mCutTextPaint;
    private int mViewWidth;//控件寬度
    private int mViewHight;//控件高度
    private float mCellSpace, mCellwide;//方格的寬和高
    private Row rows[] = new Row[TOTAL_ROW];//行數組
    private static DateInfo mShowDate;// 自定義的單元格資訊 包括year month day
    private CallBack mCallBack;// 回調
    private int touchSlop;
    private float radius;//提醒圓的半徑
    private Cell mClickCell = null;//點選的單元格
    private float mDownX;
    private float mDownY;
    private boolean callBackCellSpace = false;
    String[] str = { "日", "一", "二", "三", "四", "五", "六" };

    public interface CallBack {

        void clickDate(RepayPlanInfo date);// 回調點選的日期

        void onMesureCellHeight(float mCellSpace, float mCellwide);/// 回調cell的高度确定slidingDrawer高度

        void changeDate(DateInfo date);// 回調滑動viewPager改變的日期
    }

    public CalendarView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

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

    public CalendarView(Context context) {
        super(context);
        init(context);
    }

    public CalendarView(Context context, CallBack mCallBack) {
        super(context);
        // CalendarView.style = style;
        this.mCallBack = mCallBack;
        init(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫頂部的星期
        drawWeek(canvas);
        //畫日期單元格
        for (int i = ; i < TOTAL_ROW; i++) {
            if (rows[i] != null)
                rows[i].drawCells(canvas);
        }
    }

    private void drawWeek(Canvas canvas) {
        for (int i = ; i < TOTAL_COL; i++) {
            if (i == ) {
                mTextPaint.setColor(Color.parseColor("#b1b1b1"));
            } else {
                mTextPaint.setColor(Color.parseColor("#80000000"));
            }
            canvas.drawText(str[i], (float) ((i + ) * mCellSpace - mTextPaint.measureText(str[i]) / ),
                    (float) ( * mCellwide + mTextPaint.measureText(str[i]) / ), mTextPaint);
        }
        canvas.drawLine(, mCellwide, mViewWidth, mCellwide, linePaint);
    }

    //初始化畫筆
    private void init(Context context) {
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCutTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setTextSize(f);
        linePaint.setColor();

        BlueBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BlueBgPaint.setStyle(Paint.Style.FILL);
        BlueBgPaint.setColor(Color.parseColor("#3693fd"));

        HuiseBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        HuiseBgPaint.setStyle(Paint.Style.FILL);
        HuiseBgPaint.setColor(Color.parseColor("#e9e9e9"));

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(Color.parseColor("#fa4548"));

        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        initDate();

    }

    private void initDate() {
        mShowDate = new DateInfo();
        //填充日期的資料
        fillDate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHight = h;
        mCellSpace = mViewWidth / TOTAL_COL;
        radius = mCellSpace / ;//紅色圓圈的半徑,這裡根據單元格寬度确定
        //要在第一行頂部留下畫圓的高度,是以這裡減去半徑
        mCellwide = (mViewHight - radius) / ;
        if (!callBackCellSpace) {
            mCallBack.onMesureCellHeight(mCellSpace, mCellwide);
            callBackCellSpace = true;
        }
        mTextPaint.setTextSize(mCellSpace / );
        mCutTextPaint.setTextSize(mCellSpace / );
        mCutTextPaint.setColor(Color.parseColor("#fffffe"));

    }

    /*
     * 
     * 觸摸事件為了确定點選的位置日期
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mDownX = event.getX();
            mDownY = event.getY();
            break;
        case MotionEvent.ACTION_UP:
            float disX = event.getX() - mDownX;
            float disY = event.getY() - mDownY;
            if (Math.abs(disX) < touchSlop && Math.abs(disY) < touchSlop && event.getY() > mCellwide) {
                int col = (int) (mDownX / mCellSpace);
                int row = (int) ((mDownY - mCellwide) / mCellwide);
                measureClickCell(col, row);
            }
            break;
        }
        return true;
    }

    /** 
     * 計算繪制點選的單元格 
     * @param col 
     * @param row 
     */  
    private void measureClickCell(int col, int row) {
        if (col >= TOTAL_COL || row >= TOTAL_ROW)
            return;
        if (mClickCell != null) {
            rows[mClickCell.j].cells[mClickCell.i] = mClickCell;
        }
        if (rows[row] != null) {
            mClickCell = new Cell(rows[row].cells[col].date, rows[row].cells[col].state, rows[row].cells[col].i,
                    rows[row].cells[col].j);
            rows[row].cells[col].state = State.CLICK_DAY;
            DateInfo date = rows[row].cells[col].date;
            date.week = col;
            mCallBack.clickDate(date);
            invalidate();
        }
    }

    // 組
    class Row {
        public int j;

        Row(int j) {
            this.j = j;
        }

        public Cell[] cells = new Cell[TOTAL_COL];

        public void drawCells(Canvas canvas) {
            for (int i = ; i < cells.length; i++) {
                if (cells[i] != null)
                    cells[i].drawSelf(canvas);
            }

        }
    }

    // 單元格
    class Cell {
        public DateInfo date;
        public State state;
        /**
         * i = 行 j = 列
         */
        public int i;
        public int j;

        public Cell(DateInfo date, State state, int i, int j) {
            super();
            this.date = date;
            this.state = state;
            this.i = i;
            this.j = j;
        }

        // 繪制一個單元格 如果顔色需要自定義可以修改
        public void drawSelf(Canvas canvas) {
            switch (state) {
            case CURRENT_MONTH_DAY:
                mTextPaint.setColor(Color.parseColor("#80000000"));
                break;
            case NEXT_MONTH_DAY:
            case PAST_MONTH_DAY:
                mTextPaint.setColor(Color.parseColor("#b1b1b1"));
                break;
            case TODAY:
                mTextPaint.setColor(Color.parseColor("#F24949"));
                break;
            case CLICK_DAY:
                mTextPaint.setColor(Color.parseColor("#fffffe"));
                canvas.drawRect((float) (mCellSpace * i), (float) (mCellwide * (j + ) + radius / ),
                        (float) (mCellSpace * (i + )), (float) (mCellwide * (j + ) + radius / ), BlueBgPaint);
                break;
            case REMIND_DAY:
                mTextPaint.setColor(Color.parseColor("#80000000"));
                canvas.drawRect((float) (mCellSpace * i), (float) (mCellwide * (j + ) + radius / ),
                        (float) (mCellSpace * (i + )), (float) (mCellwide * (j + ) + radius / ), HuiseBgPaint);

                break;
            }
            // 繪制日期文字
            String content = date.day + "";
            canvas.drawText(content, (float) ((i + ) * mCellSpace - mTextPaint.measureText(content) / ),
                    (float) ((j + ) * mCellwide + mTextPaint.measureText(content, , ) /  + radius / ),
                    mTextPaint);

            // 繪制右上角提示
            String count = date.getCount() + "";
            if (!"0".equals(count) && count != null) {
                canvas.drawCircle((float) (mCellSpace * (i + ) - radius / ),
                        (float) ((j + ) * mCellwide + radius / ), radius / , mCirclePaint);
                canvas.drawText(count, (float) (mCellSpace * (i + ) - radius /  - mCutTextPaint.measureText("3") / ),
                        (float) ((j + ) * mCellwide + radius /  + mCutTextPaint.measureText("3") / ), mCutTextPaint);
            }
        }
    }

    /**
     * 單元格狀态: 目前月日期,過去的月的日期,下個月的日期,今天,點選的日期,提醒日期
     */
    enum State {
        CURRENT_MONTH_DAY, PAST_MONTH_DAY, NEXT_MONTH_DAY, TODAY, CLICK_DAY, REMIND_DAY;
    }

    /**
     * 填充日期的資料
     */
    private void fillDate() {
        fillMonthDate();

    }

    /**
     *  通過getWeekDayFromDate得到一個月第一天是星期幾就可以算出所有的日期的位置 然後依次填充 這裡最好重構一下
     */
    private void fillMonthDate() {
        int monthDay = DateUtil.getCurrentMonthDay();// 今天 
        // 上個月的天數
        int lastMonthDays = DateUtil.getMonthDays(mShowDate.year, mShowDate.month - );
        // 目前月的天數 
        int currentMonthDays = DateUtil.getMonthDays(mShowDate.year, mShowDate.month);
        //當月1号是星期幾
        int firstDayWeek = DateUtil.getWeekDayFromDate(mShowDate.year, mShowDate.month);
        boolean isCurrentMonth = false;
        if (DateUtil.isCurrentMonth(mShowDate)) {
            isCurrentMonth = true;
        }
        int day = ;
        for (int j = ; j < TOTAL_ROW; j++) {
            rows[j] = new Row(j);
            for (int i = ; i < TOTAL_COL; i++) {
                int postion = i + j * TOTAL_COL;// 單元格位置  
                // 這個月的  
                if (postion >= firstDayWeek && postion < firstDayWeek + currentMonthDays) {
                    day++;
                    if (isCurrentMonth && day == monthDay) {
                        DateInfo date = DateInfo.modifiDayForObject(mShowDate, day);
                        mClickCell = new Cell(date, State.TODAY, i, j);
                        date.week = i;
                        rows[j].cells[i] = new Cell(date, State.CLICK_DAY, i, j);
                        continue;
                    }
                    rows[j].cells[i] = new Cell(DateInfo.modifiDayForObject(mShowDate, day),
                            State.CURRENT_MONTH_DAY, i, j);
                } else if (postion < firstDayWeek) {
                 // 上個月
                    rows[j].cells[i] = new Cell(new DateInfo(mShowDate.year, mShowDate.month - ,
                            lastMonthDays - (firstDayWeek - postion - )), State.PAST_MONTH_DAY, i, j);
                } else if (postion >= firstDayWeek + currentMonthDays) {
                 // 下個月
                    rows[j].cells[i] = new Cell((new DateInfo(mShowDate.year, mShowDate.month + ,
                            postion - firstDayWeek - currentMonthDays + )), State.NEXT_MONTH_DAY, i, j);
                }
            }
        }
    }

    /**
     * 繪制提醒單元格
     * 
     * @param i
     * @return
     * 
     */
    public void updateMonthDate(List<DateInfo> dateInfos) {
        DateInfo dateInfo;
        for (int k = ; k < dateInfos.size(); k++) {
            dateInfo = dateInfos.get(k);
            //目前顯示view為提醒月時繪制提醒日期
            if (mShowDate.year == dateInfo.getYear() && mShowDate.month == dateInfo.getMonth()) {
                int[] cut = getSubscript(dateInfo.getDay());
                rows[cut[]].cells[cut[]].state = State.REMIND_DAY;
                rows[cut[]].cells[cut[]].date = dateInfo;
                if (mClickCell != null && mClickCell.date.getDay() == dateInfo.getDay()) {
                    mClickCell = rows[cut[]].cells[cut[]];
                    measureClickCell(cut[], cut[]);
                }
            }
        }
        invalidate();
    }

    /**
     * 根據日期獲得單元格下标
     * @param i
     * @return 
     */
    private int[] getSubscript(int i) {
        int firstDayWeek = DateUtil.getWeekDayFromDate(mShowDate.year, mShowDate.month);
        i = i + firstDayWeek - ;
        int a = i / ;
        int b = i % ;
        int[] cut = { a, b };
        return cut;
    }

    //更新日期,用于月份切換時
    public void update() {
        mClickCell = null;
        mCallBack.changeDate(mShowDate);
        fillDate();
        invalidate();
    }

    //傳回目前時間
    public void backToday() {
        initDate();
        invalidate();
    }

    // 點選選擇切換月份
    public void clickSelect(int year, int month) {
        mShowDate.month = month;
        mShowDate.year = year;
        update();
    }

    // 向右滑動
    public void rightSilde() {
        if (mShowDate.month == ) {
            mShowDate.month = ;
            mShowDate.year += ;
        } else {
            mShowDate.month += ;
        }
        update();
    }

    // 向左滑動
    public void leftSilde() {
        if (mShowDate.month == ) {
            mShowDate.month = ;
            mShowDate.year -= ;
        } else {
            mShowDate.month -= ;
        }
        update();
    }
}
           

這裡紅色圓心不是在右上角的頂角,需要改成在頂角的話,隻需在右邊留下圓半徑距離即可,和留頂部距離方式一樣。

2.DateUtil時間工具類

package com.example.calendar;

import android.annotation.SuppressLint;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class DateUtil {

    public static int getMonthDays(int year, int month) {
        if (month > ) {
            month = ;
            year += ;
        } else if (month < ) {
            month = ;
            year -= ;
        }
        int[] arr = { , , , , , , , , , , ,  };
        int days = ;

        if ((year %  ==  && year %  != ) || year %  == ) {
            arr[] = ; // 閏年2月29天 
        }

        try {
            days = arr[month - ];
        } catch (Exception e) {
            e.getStackTrace();
        }

        return days;
    }

    public static int getYear() {
        return Calendar.getInstance().get(Calendar.YEAR);
    }

    public static int getMonth() {
        return Calendar.getInstance().get(Calendar.MONTH) + ;
    }

    public static int getCurrentMonthDay() {
        return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
    }

    public static int getWeekDay() {
        return Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
    }

    public static int getHour() {
        return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
    }

    public static int getMinute() {
        return Calendar.getInstance().get(Calendar.MINUTE);
    }

    public static int[] getWeekSunday(int year, int month, int day, int pervious) {
        int[] time = new int[];
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        c.set(Calendar.DAY_OF_MONTH, day);
        c.add(Calendar.DAY_OF_MONTH, pervious);
        time[] = c.get(Calendar.YEAR);
        time[] = c.get(Calendar.MONTH) + ;
        time[] = c.get(Calendar.DAY_OF_MONTH);
        return time;

    }

    public static int getWeekDayFromDate(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getDateFromString(year, month));
        int week_index = cal.get(Calendar.DAY_OF_WEEK) - ;
        if (week_index < ) {
            week_index = ;
        }
        return week_index;
    }

    @SuppressLint("SimpleDateFormat")
    public static Date getDateFromString(int year, int month) {
        String dateString = year + "-" + (month >  ? month : ("0" + month)) + "-01";
        Date date = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            date = sdf.parse(dateString);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
        }
        return date;
    }

    public static boolean isToday(RepayPlanInfo date) {
        return (date.year == DateUtil.getYear() && date.month == DateUtil.getMonth()
                && date.day == DateUtil.getCurrentMonthDay());
    }

    public static boolean isCurrentMonth(RepayPlanInfo date) {
        return (date.year == DateUtil.getYear() && date.month == DateUtil.getMonth());
    }

    public static String getTimeParseInt(int year, int month, int day) {
        String dateString = year + "" + (month >  ? month : ("0" + month)) 
                            + (day >  ? day : ("0" + day));
        return dateString;
    }

    public static String getTimeParseInt(int year, int month) {
        String dateString = year + "" + (month >  ? month : ("0" + month));
        return dateString;
    }
}
           

3.自定義日期類DateInfo

package com.example.calendar.data;

import java.io.Serializable;
import package com.example.calendar.DateUtil;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * 自定義的日期類
 * 
 **/
public class DateInfo implements Serializable {

    private static final long serialVersionUID = L;
    public int year;
    public int month;
    public int day;
    public int week;

    public DateInfo(int year, int month, int day) {
        if (month > ) {
            month = ;
            year++;
        } else if (month < ) {
            month = ;
            year--;
        }
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public DateInfo() {
        this.year = DateUtil.getYear();
        this.month = DateUtil.getMonth();
        this.day = DateUtil.getCurrentMonthDay();
    }

    public static DateInfo modifiDayForObject(RepayPlanInfo date, int day) {
        DateInfo modifiDate = new DateInfo(date.year, date.month, day);
        return modifiDate;
    }

    @Override
    public String toString() {
        return year + "-" + month + "-" + day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getWeek() {
        return week;
    }

    public void setWeek(int week) {
        this.week = week;
    }

}
           

好了,自定義的view已經準備好了,接下來就是使用了。

3.使用

首先,左右滑動使用的是viewpage,為了使能無限滑動,這裡我們自定義一個PagerAdapter 。傳入一個月曆卡數組,讓ViewPager循環複用這幾個月曆卡,避免消耗記憶體。

同時viewpage在左右滑動時要判斷是左滑還是右滑去加載月曆資料,是以這裡自定義了OnPageChangeListener

package com.example.calendar;

import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;

public class CustomViewPagerAdapter<V extends View> extends PagerAdapter {
    private V[] views;

    public CustomViewPagerAdapter(V[] views) {
        super();
        this.views = views;
    }

    @Override
    public void finishUpdate(View arg0) {
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public Object instantiateItem(View arg0, int arg1) {
        if (((ViewPager) arg0).getChildCount() == views.length) {
            ((ViewPager) arg0).removeView(views[arg1 % views.length]);
        }
        ((ViewPager) arg0).addView(views[arg1 % views.length], );

        return views[arg1 % views.length];
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == (arg1);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void destroyItem(View arg0, int arg1, Object arg2) {
        // TODO Auto-generated method stub
    }

    @Override
    public void startUpdate(View arg0) {

    }

    public V[] getAllItems() {
        return views;
    }
}
           

CalendarActivity.java

package com.example.calendar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.calendar.DateInfo;
import com.example.calendar.DateUtil;
import com.example.calendar.CalendarView;
import com.example.calendar.CalendarView.CallBack;
import com.example.calendar.CustomViewPagerAdapter;
import com.example.calendar.HomePopMenuWindow;

import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.PopupWindow.OnDismissListener;

public class CalendarActivityextends Activity implements CallBack {
    private ViewPager viewPager;
    private CustomViewPagerAdapter<CalendarView> viewPagerAdapter;
    private LinearLayout linearRepayPlan;
    private TextView showYearView, showMonthView, title, xhdtxtMenu;

    private List<DateInfo> remindDateInfos = new ArrayList<DateInfo>();
    private List<DateInfo> menuDateInfos = new ArrayList<DateInfo>();
    private CalendarView[] calendarViews;
    private int width;
    private int currentYear = DateUtil.getYear();
    private int currentMonth = DateUtil.getMonth();
    private Context context;


    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
    }

    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calendar);
        context = this;
        initData();
        initView();
    }

    private void initData() {
        for (int i = ; i < ; i++) {
            DateInfo info = new DateInfo();
            info.setYear(currentYear);
            info.setMonth(currentMonth);
            if (currentMonth == ) {
                currentYear = currentYear + ;
                currentMonth = ;
            } else {
                currentMonth += ;
            }
            menuDateInfos.add(, info);
        }

        DateInfo info = new DateInfo();
        info.setBillDate("2017-08-15");
        info.setCount();
        repayDateInfos.add(info);

    }

    private void initView() {
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        showMonthView = (TextView) findViewById(R.id.show_month_view);
        showYearView = (TextView) findViewById(R.id.show_year_view);
        showYearView.setText(TimeUtil.getCurrentYear1());
        showMonthView.setText(TimeUtil.getCurrentMonth1() + "/");

        createMassCalendarViews(this, , this);

        viewPagerAdapter = new CustomViewPagerAdapter<CalendarView>(calendarViews);
        viewPager.setAdapter(viewPagerAdapter);
        viewPager.setCurrentItem();
        viewPager.setOnPageChangeListener(new CalendarViewPagerLisenter(viewPagerAdapter));
        /**
         * 當有提醒資料時,調用此方法繪制提醒日期
         */
        updateData();
    }

    public void OnButtonClick(View view) {
        switch (view.getId()) {
        case R.id.img_calendar:
            showPopMenu();
            break;
        case R.id.xhdTopBack:
            finish();
            break;
        default:
            break;
        }
    }

    /**
     * 顯示彈窗
     */
    private void showPopMenu() {
        // 點選彈出一個popupwindow
        final HomePopMenuWindow pop = new HomePopMenuWindow(this, menuDateInfos, );
        // 定義彈窗按鈕
        pop.showAsDropDown1(findViewById(R.id.img_calendar));
        pop.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                DateInfo info = menuDateInfos.get(position);
                CalendarView[] mShowViews = viewPagerAdapter.getAllItems();
                mShowViews[viewPager.getCurrentItem() % mShowViews.length].clickSelect(info.getYear(), info.getMonth());
                pop.dismiss();
            }
        });
        setBackgroundAlpha(f);
        pop.setOnDismissListener(new OnDismissListener() {

            @Override
            public void onDismiss() {
                setBackgroundAlpha(f);

            }
        });
    }

    /**
     * 設定添加螢幕的背景透明度
     * 
     * @param bgAlpha
     *            螢幕透明度0.0-1.0 1表示完全不透明
     */
    public void setBackgroundAlpha(float bgAlpha) {
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.alpha = bgAlpha;
        getWindow().setAttributes(lp);
    }

    //繪制提醒日期
    private void updateData() {
        CalendarView[] mShowViews = viewPagerAdapter.getAllItems();
        mShowViews[viewPager.getCurrentItem() % mShowViews.length].updateMonthDate(remindDateInfos);
    }

    /**
     * 生産多個CalendarView
     * 
     */
    private void createMassCalendarViews(Context context, int count, CallBack callBack) {
        calendarViews = new CalendarView[count];
        for (int i = ; i < count; i++) {
            calendarViews[i] = new CalendarView(context, callBack);
        }
    }

    class CalendarViewPagerLisenter implements OnPageChangeListener {

        private SildeDirection mDirection = SildeDirection.NO_SILDE;
        int mCurrIndex = ;
        private CalendarView[] mShowViews;

        public CalendarViewPagerLisenter(CustomViewPagerAdapter<CalendarView> viewAdapter) {
            super();
            this.mShowViews = viewAdapter.getAllItems();
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageSelected(int arg0) {
            measureDirection(arg0);
            updateCalendarView(arg0);
            linearRepayPlan.setVisibility(View.GONE);

        }

        private void updateCalendarView(int arg0) {
            if (mDirection == SildeDirection.RIGHT) {
                mShowViews[arg0 % mShowViews.length].rightSilde();
            } else if (mDirection == SildeDirection.LEFT) {
                mShowViews[arg0 % mShowViews.length].leftSilde();
            }
            mDirection = SildeDirection.NO_SILDE;
        }

        /**
         * 判斷滑動方向
         * 
         * @param arg0
         */
        private void measureDirection(int arg0) {
            if (arg0 > mCurrIndex) {
                mDirection = SildeDirection.RIGHT;

            } else if (arg0 < mCurrIndex) {
                mDirection = SildeDirection.LEFT;
            }
            mCurrIndex = arg0;
        }

    }

    enum SildeDirection {
        RIGHT, LEFT, NO_SILDE;
    }

    /**
     * CandlendarView回到目前日期
     */
    private void backTodayCalendarViews() {
        if (calendarViews != null)
            for (int i = ; i < calendarViews.length; i++) {
                calendarViews[i].backToday();
            }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    //viewpage滑動時顯示目前日期
    public void setShowDateViewText(int year, int month) {
        showYearView.setText(year + "");
        if (month < ) {
            showMonthView.setText("0" + month + "/");
        } else {
            showMonthView.setText(month + "/");
        }
    }

    @Override
    public void onMesureCellHeight(float cellSpace, float cellwide) {

    }

    @Override
    public void clickDate(RepayPlanInfo dates) {
        // 當點選月曆時回調
    }

    @Override
    public void changeDate(RepayPlanInfo dates) {
        //viewpage滑動時回調
        setShowDateViewText(dates.year, dates.month);
    }

}
           

上面代碼中我還使用了popupWindow,就是彈出一個listview,可以點選切換月份,我就不貼代碼了

布局activity_calendar

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="40dip"
        android:background="@color/white"
        android:paddingLeft="15dip"
        android:paddingRight="15dip" >

        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="15dp"
            android:orientation="horizontal" >

            <TextView
                android:id="@+id/show_month_view"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_alignParentLeft="true"
                android:gravity="center"
                android:text="01/"
                android:textColor="#646464"
                android:textSize="15sp" />

            <TextView
                android:id="@+id/show_year_view"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:gravity="center"
                android:text="2017"
                android:textColor="#646464"
                android:textSize="15sp" />
        </LinearLayout>

        <ImageView
            android:id="@+id/img_calendar"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:onClick="OnButtonClick"
            android:padding="10dp"
            android:src="@drawable/img_schoolyear" />
    </RelativeLayout>

    <View
        android:layout_width="fill_parent"
        android:layout_height="1px"
        android:background="#20000000" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="280dp"
        android:layout_gravity="center"
        android:background="#ffffff"
        android:paddingLeft="15dip"
        android:paddingRight="15dip" >
    </android.support.v4.view.ViewPager>

</LinearLayout>
           

好了,大功告成了,相關代碼就這些了~~~