您的当前位置:首页正文

Android自定义View实现日历界面(带点击和历史标记)

来源:图艺博知识网

1、自定义view日历星期

public class WeekDayView extends View{
    //上横线颜色
    private int mTopLineColor = Color.parseColor("#CCE4F2");
    //下横线颜色
    private int mBottomLineColor = Color.parseColor("#CCE4F2");
    //周一到周五的颜色
    private int mWeekdayColor = Color.parseColor("#1FC2F3");
    //周六、周日的颜色
    private int mWeekendColor = Color.parseColor("#fa4451");
    //线的宽度
    private int mStrokeWidth = 4;
    private int mWeekSize = 14;
    private Paint paint;
    private DisplayMetrics mDisplayMetrics;
    private String[] weekString = new String[]{"S","M","T","W","T","F","S"};
    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.setAntiAlias(true); //设置抗锯齿的效果
        paint.setStyle(Paint.Style.STROKE); //设置画笔的样式为描边
        //设置画笔的颜色
        paint.setColor(mTopLineColor);
        //设置画笔的宽度
        paint.setStrokeWidth(mStrokeWidth);
        //用指定的开始和停止x、y坐标绘制线段,使用指定的油漆
        canvas.drawLine(0, 0, width, 0, paint);
        //设置下横线的画笔颜色
        paint.setColor(mBottomLineColor);
        canvas.drawLine(0, height, width, height, paint);
        //设置画笔的样式
        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("R") > -1|| text.indexOf("S") > -1){
                paint.setColor(mWeekendColor);
            }else{
                paint.setColor(mWeekdayColor);
            }
            canvas.drawText(text, startX, startY, paint);
        }
    }

    /**
     * 设置顶线的颜色
     * @param mTopLineColor
     */
    public void setmTopLineColor(int mTopLineColor) {
        this.mTopLineColor = mTopLineColor;
    }

    /**
     * 设置底线的颜色
     * @param mBottomLineColor
     */
    public void setmBottomLineColor(int mBottomLineColor) {
        this.mBottomLineColor = mBottomLineColor;
    }

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

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

    /**
     * 设置边线的宽度
     * @param mStrokeWidth
     */
    public void setmStrokeWidth(int mStrokeWidth) {
        this.mStrokeWidth = mStrokeWidth;
    }


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


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

2、简单自定义日历界面

public class MyMediaDayController extends View {
    private static final int NUM_COLUMNS = 7;
    private static final int NUM_ROWS = 6;
    private int mColumnSize,mRowSize;//行宽、高
    private int [][] daysString;//天数
    private DisplayMetrics mDisplayMetrics;
    private Paint mPaint;//画笔
    private int mCurrYear, mCurrMonth, mCurrDay;//年月日
    private int mSelYear, mSelMonth, mSelDay;//设置年月日
    private int mDaySize = 14;//天数字体大小
    private int mMonthDays;//一个月中有几天
    private int mDayColor = Color.parseColor("#666666");//设置字体颜色


    public MyMediaDayController(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDisplayMetrics = getResources().getDisplayMetrics();
        Calendar calendar = Calendar.getInstance();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mCurrYear = calendar.get(Calendar.YEAR);
        mCurrMonth = calendar.get(Calendar.MONTH) + 1;
        mCurrDay = calendar.get(Calendar.DATE);
        setSelectYearMonth(mCurrYear, mCurrMonth, 0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, 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) {
        super.onDraw(canvas);
        initSize();
        daysString = new int[6][7];
        mPaint.setTextSize(mDaySize * mDisplayMetrics.scaledDensity);
        String dayString;
        Calendar calendar = Calendar.getInstance();
        mSelYear = calendar.get(Calendar.YEAR);
        mSelMonth = calendar.get(Calendar.MONTH) + 1;
        calendar.set(Calendar.YEAR, mSelYear);//先指定年份
        calendar.set(Calendar.MONTH, mSelMonth - 1);//再指定月份 Java月份从0开始算
        mMonthDays = calendar.getActualMaximum(Calendar.DATE);//获取指定年份中指定月份有几天
        calendar.set(Calendar.DAY_OF_MONTH, 1); //获取指定年份月份中指定某天是星期几
        int weekNumber = calendar.get(Calendar.DAY_OF_WEEK);//周几
        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);
            mPaint.setColor(mDayColor);
            canvas.drawText(dayString, startX, startY, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    /**
     * 初始化列宽行高
     */
    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;
    }
}

3.xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.eiboran.ace.widget.WeekDayView
        android:layout_width="match_parent"
        android:layout_height="40dp" />
    <com.eiboran.ace.widget.MyMediaDayController
        android:layout_width="match_parent"
        android:layout_height="160dp" />
</LinearLayout>

4.自定义日历界面带标记界面

public class MyMediaDayController extends View {
    private static final int NUM_COLUMNS = 7;
    private static final int NUM_ROWS = 6;
    private int mColumnSize,mRowSize;//行宽、高
    private int [][] daysString;//天数
    private DisplayMetrics mDisplayMetrics;
    private Paint mPaint;//画笔
    private int mCurrYear, mCurrMonth, mCurrDay;//年月日
    private int mSelYear, mSelMonth, mSelDay;//设置年月日
    private int mDaySize = 14;//天数字体大小
    private int mMonthDays;//一个月中有几天
    private int mDayColor = Color.parseColor("#FFFFFF");//设置字体颜色
    private int m15DayColor = Color.parseColor("#00BFFF");
    private int m30DayColor = Color.parseColor("#FF7F50");
    private int m0DayColor = Color.parseColor("#FF0000");


    public MyMediaDayController(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDisplayMetrics = getResources().getDisplayMetrics();
        Calendar calendar = Calendar.getInstance();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mCurrYear = calendar.get(Calendar.YEAR);
        mCurrMonth = calendar.get(Calendar.MONTH) + 1;
        mCurrDay = calendar.get(Calendar.DATE);
        setSelectYearMonth(mCurrYear, mCurrMonth, 0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, 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) {
        super.onDraw(canvas);
        initSize();
        daysString = new int[6][7];
        mPaint.setTextSize(mDaySize * mDisplayMetrics.scaledDensity);
        String dayString;
        Calendar calendar = Calendar.getInstance();
        mSelYear = calendar.get(Calendar.YEAR);
        mSelMonth = calendar.get(Calendar.MONTH) + 1;
        calendar.set(Calendar.YEAR, mSelYear);//先指定年份
        calendar.set(Calendar.MONTH, mSelMonth - 1);//再指定月份 Java月份从0开始算
        mMonthDays = calendar.getActualMaximum(Calendar.DATE);//获取指定年份中指定月份有几天
        calendar.set(Calendar.DAY_OF_MONTH, 1); //获取指定年份月份中指定某天是星期几
        int weekNumber = calendar.get(Calendar.DAY_OF_WEEK);//周几
        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);
            //给日期绘制背景
            int startRecX = mColumnSize * column;
            int startRecY = mRowSize * row;
            int endRecX = startRecX + mColumnSize;
            int endRecY = startRecY + mRowSize;
            if (day > 15 ){
                mPaint.setColor(m15DayColor);
                RectF mColorWheelRectangleS = new RectF(startRecX + (endRecX - startRecX) / 4, startRecY + 5, endRecX - (endRecX - startRecX) / 4, endRecY - 5);//圆圈的矩形范围
                canvas.drawArc(mColorWheelRectangleS, -90, -180, false, mPaint);
                mPaint.setColor(m30DayColor);
                RectF mColorWheelRectangle = new RectF(startRecX + (endRecX - startRecX) / 4, startRecY + 5, endRecX - (endRecX - startRecX) / 4, endRecY - 5);//圆圈的矩形范围
                canvas.drawArc(mColorWheelRectangle, -90, 180, false, mPaint);
            } else {
                mPaint.setColor(m0DayColor);
                int px = DensityUtil.dip2px(getContext(), 12);
                canvas.drawCircle((startRecX + endRecX) / 2, (startRecY + endRecY) / 2, px, mPaint);
            }
            mPaint.setColor(mDayColor);
            canvas.drawText(dayString, startX, startY, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    /**
     * 初始化列宽行高
     */
    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;
    }
}

5.自定义日历带点击事件

public class MyMediaDayController extends View {
    private static final int NUM_COLUMNS = 7;
    private static final int NUM_ROWS = 6;
    private int mColumnSize, mRowSize;//行宽、高
    private int[][] daysString;//天数
    private DisplayMetrics mDisplayMetrics;
    private Paint mPaint;//画笔
    private int mCurrYear, mCurrMonth, mCurrDay;//年月日
    private int mSelYear, mSelMonth, mSelDay;//设置年月日
    private int mDaySize = 14;//天数字体大小
    private int mMonthDays;//一个月中有几天
    private int mDayColor = Color.parseColor("#FFFFFF");//设置字体颜色
    private int m15DayColor = Color.parseColor("#00BFFF");
    private int m30DayColor = Color.parseColor("#FF7F50");
    private int m0DayColor = Color.parseColor("#FF0000");
    private int downX = 0, downY = 0;//点击事件坐标
    private DateClick dateClick;


    public MyMediaDayController(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDisplayMetrics = getResources().getDisplayMetrics();
        Calendar calendar = Calendar.getInstance();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mCurrYear = calendar.get(Calendar.YEAR);
        mCurrMonth = calendar.get(Calendar.MONTH) + 1;
        mCurrDay = calendar.get(Calendar.DATE);
        setSelectYearMonth(mCurrYear, mCurrMonth, 0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, 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) {
        super.onDraw(canvas);
        initSize();
        daysString = new int[6][7];
        mPaint.setTextSize(mDaySize * mDisplayMetrics.scaledDensity);
        String dayString;
        Calendar calendar = Calendar.getInstance();
        mSelYear = calendar.get(Calendar.YEAR);
        mSelMonth = calendar.get(Calendar.MONTH) + 1;
        calendar.set(Calendar.YEAR, mSelYear);//先指定年份
        calendar.set(Calendar.MONTH, mSelMonth - 1);//再指定月份 Java月份从0开始算
        mMonthDays = calendar.getActualMaximum(Calendar.DATE);//获取指定年份中指定月份有几天
        calendar.set(Calendar.DAY_OF_MONTH, 1); //获取指定年份月份中指定某天是星期几
        int weekNumber = calendar.get(Calendar.DAY_OF_WEEK);//周几
        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);
            //给日期绘制背景
            int startRecX = mColumnSize * column;
            int startRecY = mRowSize * row;
            int endRecX = startRecX + mColumnSize;
            int endRecY = startRecY + mRowSize;
            if (mSelDay == (day + 1)){
                mPaint.setColor(Color.parseColor("#FF83FA"));
                int px = DensityUtil.dip2px(getContext(), 12);
                canvas.drawCircle((startRecX + endRecX) / 2, (startRecY + endRecY) / 2, px, mPaint);
            } else {
                if (day > 15) {
                    mPaint.setColor(m15DayColor);
                    RectF mColorWheelRectangleS = new RectF(startRecX + (endRecX - startRecX) / 4, startRecY + 5, endRecX - (endRecX - startRecX) / 4, endRecY - 5);//圆圈的矩形范围
                    canvas.drawArc(mColorWheelRectangleS, -90, -180, false, mPaint);
                    mPaint.setColor(m30DayColor);
                    RectF mColorWheelRectangle = new RectF(startRecX + (endRecX - startRecX) / 4, startRecY + 5, endRecX - (endRecX - startRecX) / 4, endRecY - 5);//圆圈的矩形范围
                    canvas.drawArc(mColorWheelRectangle, -90, 180, false, mPaint);
                } else {
                    mPaint.setColor(m0DayColor);
                    int px = DensityUtil.dip2px(getContext(), 12);
                    canvas.drawCircle((startRecX + endRecX) / 2, (startRecY + endRecY) / 2, px, mPaint);
                }
            }
            mPaint.setColor(mDayColor);
            canvas.drawText(dayString, startX, startY, mPaint);
        }
    }

    @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) < 10 && Math.abs(upY - downY) < 10) {//点击事件
                    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;
        Calendar calendar = Calendar.getInstance();
        int myDay = calendar.get(Calendar.DATE);
        //获取点击是第几天
        setSelectYearMonth(mSelYear, mSelMonth, daysString[row][column]);
        //刷新界面
        invalidate();
        if (dateClick != null) {
            dateClick.onClickOnDate();
        }
    }
    /**
     * 设置日期的点击回调事件
     * @author shiwei.deng
     *
     */
    public interface DateClick{
        void onClickOnDate();
    }

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