自定义日历

自定义日历

  • 日期的绘制
  • 日期点击事件
  • 日期的事件提醒
  • 日期的颜色设置

1. 日历的绘制

这是参考的网上的部分自定义日历加上自己的修改
public class MonthDateView extends View {
    private static final int NUM_COLUMNS = 7;
    private static final int NUM_ROWS = 6;
    private final int touchSlop;
    private Paint mPaint;
    private int mDayColor = Color.parseColor("#000000");
    private int mSelectDayColor = Color.parseColor("#ffffff");
    private int mSelectBGColor = Color.parseColor("#1FC2F3");
    private int mCurrentColor = Color.parseColor("#ff0000");
    private int mCurrYear, mCurrMonth, mCurrDay;
    private int mSelYear, mSelMonth, mSelDay;
    private int mColumnSize, mRowSize;
    private DisplayMetrics mDisplayMetrics;
    private int mDaySize = 18;
    private TextView tv_date, tv_week;
    private int weekRow;
    private int[][] daysString;
    private int mCircleRadius = 4;
    private DateClick dateClick;
    private int mCircleColor = Color.parseColor("#ff0000");
    private List<Integer> daysHasThingList;
    private List<Integer> grayDayList;
    private boolean grayDay = false;

    public MonthDateView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDisplayMetrics = getResources().getDisplayMetrics();
        Calendar calendar = Calendar.getInstance();
        mPaint = new Paint();
        mCurrYear = calendar.get(Calendar.YEAR);
        //这地方+1是由于系统默认的月份是0-11月 和传统的1-12月有误差
        mCurrMonth = calendar.get(Calendar.MONTH)+1;
        mCurrDay = calendar.get(Calendar.DATE);
        setSelectYearMonth(mCurrYear, mCurrMonth, mCurrDay);
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        if (heightMode == MeasureSpec.AT_MOST) {
            heightSize = mDisplayMetrics.densityDpi * 200;
        }
//        if(widthMode == MeasureSpec.AT_MOST){
//            widthSize = mDisplayMetrics.densityDpi * 300;
//        }
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        initSize();
        daysString = new int[6][7];
        mPaint.setTextSize(mDaySize * mDisplayMetrics.scaledDensity);
        String dayString;
        int mMonthDays = DateHelper.getMonthDays(mSelYear, mSelMonth);
        int weekNumber = DateHelper.getFirstDayWeek(mSelYear, mSelMonth);
        Log.d("DateView", "DateView:" + mSelMonth + "月1号周" + weekNumber);
        for (int day = 0; day < mMonthDays; day++) {
            dayString = (day + 1) + "";
            int column = (day + weekNumber - 1) % 7;
            int row = (day + weekNumber - 1) / 7;
            daysString[row][column] = day + 1;
            int startX = (int) (mColumnSize * column + (mColumnSize - mPaint.measureText(dayString)) / 2);
            int startY = (int) (mRowSize * row + mRowSize / 2 - (mPaint.ascent() + mPaint.descent()) / 2);
//          这个地方可以对背景色进行设置,形状和颜色可以按照自己定义的来            
//            if(dayString.equals(mSelDay+"")){
//                //绘制背景色矩形
//                int startRecX = mColumnSize * column;
//                int startRecY = mRowSize * row;
//                int endRecX = startRecX + mColumnSize;
//                int endRecY = startRecY + mRowSize;
//                mPaint.setColor(mSelectBGColor);
//                canvas.drawRect(startRecX, startRecY, endRecX, endRecY, mPaint);
//                //记录第几行,即第几周
//                weekRow = row + 1;
//            }
//绘制事务圆形标志 我这边是由于公司要点击背景色发生变化,所以设置为背
//景色为空,通过事务来描绘背景的黄色圆圈
            drawCircle(row, column, day + 1, canvas);
            //下面是对日期天数的绘制,可以针对自己的需求自定义修改
            if (dayString.equals(mSelDay + "")) { 
                 mPaint.setColor(mSelectDayColor);
            } else if (dayString.equals(mCurrDay + "") && mCurrDay != mSelDay && mCurrMonth == mSelMonth) {
                //当天
                 mPaint.setColor(mDayColor);
            }else {
                mPaint.setColor(mDayColor);
            }
            canvas.drawText(dayString, startX, startY, mPaint);
            if (tv_date != null) {
                tv_date.setText(mSelYear + "年" + mSelMonth + "月");
            }

            if (tv_week != null) {
                tv_week.setText("第" + weekRow + "周");
            }
        }
    }


//绘制事务标志
    private void drawCircle(int row, int column, int day, Canvas canvas) {
        if (daysHasThingList != null && daysHasThingList.size() > 0) {
            if (!daysHasThingList.contains(day)) {
//设置事务标志颜色               mPaint.setColor(Color.parseColor("#ffffff"));
                float circleX = (float) (mColumnSize * column + mColumnSize * 0.5);
                float circley = (float) (mRowSize * row + mRowSize * 0.5);
                canvas.drawCircle(circleX, circley, mCircleRadius, mPaint);
                return;
            }
            mPaint.setColor(mCircleColor);
            int startRecX = mColumnSize * column;
            int endRecX = startRecX + mColumnSize;
            //事务圆的半径
            mCircleRadius = (Math.abs(endRecX - startRecX)) * 2 / 7;
            //圆心坐标
            float circleX = (float) (mColumnSize * column + mColumnSize * 0.5);
            float circley = (float) (mRowSize * row + mRowSize * 0.5);
            canvas.drawCircle(circleX, circley, mCircleRadius, mPaint);
        }
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    private int downX = 0, downY = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int eventCode = event.getAction();
        switch (eventCode) {
            case MotionEvent.ACTION_DOWN:
                downX = (int) event.getX();
                downY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                int upX = (int) event.getX();
                int upY = (int) event.getY();
                if (Math.abs(upX - downX) < touchSlop && Math.abs(upY - downY) < touchSlop) {//点击事件
                    performClick();
                    doClickAction((upX + downX) / 2, (upY + downY) / 2);
                }
                break;
        }
        return true;
    }

    /**
     * 初始化列宽行高
     */
    private void initSize() {
        mColumnSize = getWidth() / NUM_COLUMNS;
        mRowSize = getHeight() / NUM_ROWS;
    }

    /**
     * 设置年月
     *
     * @param year
     * @param month
     */
    private void setSelectYearMonth(int year, int month, int day) {
        mSelYear = year;
        mSelMonth = month;
        mSelDay = day;
    }

    /**
     * 执行点击事件
     *
     * @param x
     * @param y
     */
    private void doClickAction(int x, int y) {
        int row = y / mRowSize;
        int column = x / mColumnSize;
        int mMonthDays = DateHelper.getMonthDays(mSelYear, mSelMonth);
        setSelectYearMonth(mSelYear, mSelMonth, daysString[row][column]);
        invalidate();
        //执行activity发送过来的点击处理事件
        if (dateClick != null) {
            dateClick.onClickOnDate();
        }
    }

    /**
     * 左点击,日历向后翻页
     */
    public void onLeftClick() {
        int year = mSelYear;
        int month = mSelMonth;
        int day = mSelDay;
        if (month == 1) {//若果是1月份,则变成12月份
            year = mSelYear - 1;
            month = 12;
        } else if (DateHelper.getMonthDays(year, month) == day) {
            //如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
            month = month - 1;
            day = DateHelper.getMonthDays(year, month);
        } else {
            month = month - 1;
        }
        setSelectYearMonth(year, month, day);
        invalidate();
    }

    /**
     * 右点击,日历向前翻页
     */
    public void onRightClick() {
        int year = mSelYear;
        int month = mSelMonth;
        int day = mSelDay;
        if (month == 12) {//若果是12月份,则变成1月份
            year = mSelYear + 1;
            month = 1;
        } else if (DateHelper.getMonthDays(year, month) == day) {
            //如果当前日期为该月最后一点,当向前推的时候,就需要改变选中的日期
            month = month + 1;
            day = DateHelper.getMonthDays(year, month);
        } else {
            month = month + 1;
        }
        setSelectYearMonth(year, month, day);
        invalidate();
    }

    /**
     * 获取选择的年份
     *
     * @return
     */
    public int getmSelYear() {
        return mSelYear;
    }

    /**
     * 获取选择的月份
     *
     * @return
     */
    public int getmSelMonth() {
        return mSelMonth;
    }

    /**
     * 获取选择的日期
     */
    public int getmSelDay() {
        return this.mSelDay;
    }

    /**
     * 普通日期的字体颜色,默认黑色
     *
     * @param mDayColor
     */
    public void setmDayColor(int mDayColor) {
        this.mDayColor = mDayColor;
    }

    /**
     * 选择日期的颜色,默认为白色
     *
     * @param mSelectDayColor
     */
    public void setmSelectDayColor(int mSelectDayColor) {
        this.mSelectDayColor = mSelectDayColor;
    }

    /**
     * 选中日期的背景颜色,默认蓝色
     *
     * @param mSelectBGColor
     */
    public void setmSelectBGColor(int mSelectBGColor) {
        this.mSelectBGColor = mSelectBGColor;
    }

    /**
     * 当前日期不是选中的颜色,默认红色
     *
     * @param mCurrentColor
     */
    public void setmCurrentColor(int mCurrentColor) {
        this.mCurrentColor = mCurrentColor;
    }

    /**
     * 日期的大小,默认18sp
     *
     * @param mDaySize
     */
    public void setmDaySize(int mDaySize) {
        this.mDaySize = mDaySize;
    }

    /**
     * 设置显示当前日期的控件
     *
     * @param tv_date 显示日期
     */
    public void setTextView(TextView tv_date) {
        this.tv_date = tv_date;
        invalidate();
    }

    /**
     * 设置事务天数
     *
     * @param daysHasThingList
     */
    public void setDaysHasThingList(List<Integer> daysHasThingList) {
        this.daysHasThingList = daysHasThingList;
    }

    /**
     * 设置事务天数
     *
     * @param grayDayList
     */
    public void setGrayDayList(List<Integer> grayDayList) {
        this.grayDayList = grayDayList;
        grayDay = true;
    }

    /***
     * 设置圆圈的半径,默认为6
     *
     * @param mCircleRadius
     */
    public void setmCircleRadius(int mCircleRadius) {
        this.mCircleRadius = mCircleRadius;
    }

    /**
     * 设置圆圈的半径
     *
     * @param mCircleColor
     */
    public void setmCircleColor(int mCircleColor) {
        this.mCircleColor = mCircleColor;
    }

    /**
     * 设置日期的点击回调事件
     *
     * @author shiwei.deng
     */
    public interface DateClick {
        public void onClickOnDate();
    }

    /**
     * 设置日期点击事件
     *
     * @param dateClick
     */
    public void setDateClick(DateClick dateClick) {
        this.dateClick = dateClick;
    }

    /**
     * 跳转至今天
     */
    public void setTodayToView() {
        setSelectYearMonth(mCurrYear, mCurrMonth, mCurrDay);
        invalidate();
    }

绘制周一 -周日

public class WeekDayView extends View {

    //周一到周五的颜色
    private int mWeedayColor = Color.parseColor("#000000");
    //周六、周日的颜色
    private int mWeekendColor = Color.parseColor("#000000");

    private int mWeekSize = 12;
    private Paint paint;
    private DisplayMetrics mDisplayMetrics;
    private String[] weekString = new String[]{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
    public WeekDayView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDisplayMetrics = getResources().getDisplayMetrics();
        paint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        if(heightMode == MeasureSpec.AT_MOST){
            heightSize = mDisplayMetrics.densityDpi * 30;
        }
//        if(widthMode == MeasureSpec.AT_MOST){
//            widthSize = mDisplayMetrics.densityDpi * 300;
//        }
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();

        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(mWeekSize * mDisplayMetrics.scaledDensity);
        int columnWidth = width / 7;
        for(int i=0;i < weekString.length;i++){
            String text = weekString[i];
            int fontWidth = (int) paint.measureText(text);
            int startX = columnWidth * i + (columnWidth - fontWidth)/2;
            int startY = (int) (height/2 - (paint.ascent() + paint.descent())/2);
            if(text.indexOf("日") > -1|| text.indexOf("六") > -1){
                paint.setColor(mWeekendColor);
            }else{
                paint.setColor(mWeedayColor);
            }
            canvas.drawText(text, startX, startY, paint);
        }
    }


    /**
     * 设置周一-五的颜色
     * @return
     */
    public void setmWeedayColor(int mWeedayColor) {
        this.mWeedayColor = mWeedayColor;
    }

    /**
     * 设置周六、周日的颜色
     * @param mWeekendColor
     */
    public void setmWeekendColor(int mWeekendColor) {
        this.mWeekendColor = mWeekendColor;
    }


    /**
     * 设置字体的大小
     * @param mWeekSize
     */
    public void setmWeekSize(int mWeekSize) {
        this.mWeekSize = mWeekSize;
    }


    /**
     * 设置星期的形式
     * @param weekString
     * 默认值  "日","一","二","三","四","五","六"
     */
    public void setWeekString(String[] weekString) {
        this.weekString = weekString;
    }
}

日期帮助类

public class DateHelper {

    /**
     * 默认的日期样式:yyyy-MM-dd
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DATE_TIME_FORMAT_SHORT="yyyy-M-d H:m";
    public static final String DATE_TIME_FORMAT_BIG_SHORT="yyyy-MM-dd HH:mm";
    public static final String DATE_TIME_FORMAT="yyyy-MM-dd HH:mm:ss";
    public static final int YEAR = 1;
    public static final int MONTH = 2;
    public static final int DAY = 3;
    public static final int HOUR = 4;
    public static final int MINUTE = 5;
    public static final int SECOND = 6;
    public static final int MILLISECOND = 7;

    public DateHelper(){
    }

    public static int getMonthDays(int year, int month) {
        if (month > 12) {
            month = 1;
            year += 1;
        } else if (month < 1) {
            month = 12;
            year -= 1;
        }
        int[] arr = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        int days = 0;

        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            arr[1] = 29; // 闰年2月29天
        }

        try {
            days = arr[month - 1];
        } 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) + 1;
    }

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

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


    /**
     * 返回当前月份1号位于周几
     * @param year
     *      年份
     * @param month
     *      这个地方是我在绘制日历时候传入的正常的月份
     *      需要做一个减1处理,这又有个地方是周日为第一天和周一为第一天是不一样的,需要自己做处理
     * @return
     *  日:1     一:2     二:3     三:4     四:5     五:6     六:7
     */
    public static int getFirstDayWeek(int year, int month){
        Calendar calendar = Calendar.getInstance();
        int firstDayOfWeek = calendar.getFirstDayOfWeek();
        Log.e("firstDayOfWeek",firstDayOfWeek+"");
        calendar.set(year, month-1, 1);
        int i1 = calendar.get(Calendar.DATE);
        int i = calendar.get(Calendar.DAY_OF_WEEK);
        return i;
    }

}

日期layout

<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:layout_centerInParent="true"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.quwanbei.haihuilai.caledertest.MainActivity">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:gravity="center_vertical"
        android:paddingTop="3dp">

        <LinearLayout
            android:id="@+id/date_operator_ll"
            android:layout_width="fill_parent"
            android:layout_height="60dp"
            android:layout_centerInParent="true"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            android:orientation="horizontal">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/iv_left"
                android:padding="8dp">

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@mipmap/last"
                    android:contentDescription="@null" />
            </RelativeLayout>

            <TextView
                android:id="@+id/date_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dp"
                android:layout_marginRight="16dp"
                android:gravity="center_horizontal"
                android:text=""
                android:textColor="#1d1d1d"
                android:textSize="18sp" />

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/iv_right"
                android:padding="8dp">

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@mipmap/next"
                    android:contentDescription="@null" />
            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#f3f3f3" />

        <com.quwanbei.haihuilai.caledertest.WeekDayView
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_marginTop="14dp" />

        <com.quwanbei.haihuilai.caledertest.MonthDateView
            android:id="@+id/monthDateView"
            android:layout_width="fill_parent"
            android:layout_height="200dp" />
    </LinearLayout>
</LinearLayout>

Activity设置

public class MainActivity extends AppCompatActivity {

    private RelativeLayout iv_left;
    private RelativeLayout iv_right;
    private MonthDateView monthDateView;
    private TextView tv_date;
    private ArrayList<String> list;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        list = new ArrayList<>();
        list.add(10+"");
        list.add(12+"");
        list.add(15+"");
        list.add(16+"");
        iv_left = (RelativeLayout) findViewById(R.id.iv_left);
        iv_right = (RelativeLayout) findViewById(R.id.iv_right);
        monthDateView = (MonthDateView) findViewById(R.id.monthDateView);
        tv_date = (TextView) findViewById(R.id.date_text);
        monthDateView.setTextView(tv_date);
        monthDateView.setDaysHasThingList(list);
        monthDateView.setmCircleRadius(60);
        monthDateView.setmCircleColor(Color.parseColor("#ffda8c"));
        monthDateView.setmSelectDayColor(Color.parseColor("#00beab"));
        monthDateView.setmCurrentColor(Color.parseColor("#000000"));
        monthDateView.setmDaySize(14);
        monthDateView.setDateClick(new MonthDateView.DateClick() {

            @Override
            public void onClickOnDate() {
                if(!list.contains(monthDateView.getmSelDay()+"")) {
                    list.add(monthDateView.getmSelDay()+"");
                    Toast.makeText(getApplication(), "点击了:" + monthDateView.getmSelDay(), Toast.LENGTH_SHORT).show();
                }else{
                    list.remove(monthDateView.getmSelDay()+"");
                }
            }
        });
        setOnlistener();
    }

    private void setOnlistener(){
        iv_left.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                monthDateView.onLeftClick();
            }
        });

        iv_right.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                monthDateView.onRightClick();
            }
        });
    }
}

需要标注的地方都写有注释,有不明白的地方留言问我
刚开始写,技术不太好,多多指教。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值