• 冲刺!


    昨天:弄了一堆的函数方法,又从网上找了好多。

    困难:还是不太明白。

    今天:跟着网上的先弄清楚,然后搞一下点击事件。

    package com.example.zbytexttwo;
    
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.Toast;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    public class MainJmActivity extends AppCompatActivity {
    
        private CustomCalendar cal;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main_jm);
            cal = (CustomCalendar)findViewById(R.id.cal);
    
    
            //TODO 模拟请求当月数据
            final List<DayFinish> list = new ArrayList<>();
            list.add(new DayFinish(1,2,2));
            list.add(new DayFinish(2,1,2));
            list.add(new DayFinish(3,0,2));
            list.add(new DayFinish(4,2,2));
            list.add(new DayFinish(5,2,2));
            list.add(new DayFinish(6,2,2));
            list.add(new DayFinish(7,2,2));
            list.add(new DayFinish(8,0,2));
            list.add(new DayFinish(9,1,2));
            list.add(new DayFinish(10,2,2));
            list.add(new DayFinish(11,5,2));
            list.add(new DayFinish(12,2,2));
            list.add(new DayFinish(13,2,2));
            list.add(new DayFinish(14,3,2));
            list.add(new DayFinish(15,2,2));
            list.add(new DayFinish(16,1,2));
            list.add(new DayFinish(17,0,2));
            list.add(new DayFinish(18,2,2));
            list.add(new DayFinish(19,2,2));
            list.add(new DayFinish(20,0,2));
            list.add(new DayFinish(21,2,2));
            list.add(new DayFinish(22,1,2));
            list.add(new DayFinish(23,2,0));
            list.add(new DayFinish(24,0,2));
            list.add(new DayFinish(25,2,2));
            list.add(new DayFinish(26,2,2));
            list.add(new DayFinish(27,2,2));
            list.add(new DayFinish(28,2,2));
            list.add(new DayFinish(29,2,2));
            list.add(new DayFinish(30,2,2));
            list.add(new DayFinish(31,2,2));
    
            cal.setRenwu("2017年1月", list);
            cal.setOnClickListener(new CustomCalendar.onClickListener() {
                @Override
                public void onLeftRowClick() {
                    Toast.makeText(MainJmActivity.this, "点击减箭头", Toast.LENGTH_SHORT).show();
                    cal.monthChange(-1);
                    new Thread(){
                        @Override
                        public void run() {
                            try{
                                Thread.sleep(1000);
                                MainJmActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        cal.setRenwu(list);
                                    }
                                });
                            }catch (Exception e){
                            }
                        }
                    }.start();
                }
    
                @Override
                public void onRightRowClick() {
                    Toast.makeText(MainJmActivity.this, "点击加箭头", Toast.LENGTH_SHORT).show();
                    cal.monthChange(1);
                    new Thread(){
                        @Override
                        public void run() {
                            try{
                                Thread.sleep(1000);
                                MainJmActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        cal.setRenwu(list);
                                    }
                                });
                            }catch (Exception e){
                            }
                        }
                    }.start();
                }
    
                @Override
                public void onTitleClick(String monthStr, Date month) {
                    Toast.makeText(MainJmActivity.this, "点击了标题:"+monthStr, Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onWeekClick(int weekIndex, String weekStr) {
                    Toast.makeText(MainJmActivity.this, "点击了星期:"+weekStr, Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onDayClick(int day, String dayStr, DayFinish finish) {
                    Toast.makeText(MainJmActivity.this, "点击了日期:"+dayStr, Toast.LENGTH_SHORT).show();
                    Log.w("", "点击了日期:"+dayStr);
                }
            });
        }
    
        class DayFinish{
            int day;
            int all;
            int finish;
            public DayFinish(int day, int finish, int all) {
                this.day = day;
                this.all = all;
                this.finish = finish;
            }
        }
    }
    MainJmActivity
    package com.example.zbytexttwo;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.DashPathEffect;
    import android.graphics.Paint;
    import android.graphics.PathEffect;
    import android.graphics.PointF;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * author : openXu
     * create at : 2017/1/3 9:56
     * blog : http://blog.csdn.net/xmxkf
     * gitHub : https://github.com/openXu
     * project : CustomCalendar
     * class name : CustomCalendar
     * version : 1.0
     * class describe:自定义日历控件
     */
    public class CustomCalendar extends View{
    
        private String TAG = "CustomCalendar";
    
        /** 各部分背景*/
        private int mBgMonth, mBgWeek, mBgDay, mBgPre;
        /** 标题的颜色、大小*/
        private int mTextColorMonth;
        private float mTextSizeMonth;
        private int mMonthRowL, mMonthRowR;
        private float mMonthRowSpac;
        private float mMonthSpac;
        /** 星期的颜色、大小*/
        private int mTextColorWeek, mSelectWeekTextColor;
        private float mTextSizeWeek;
        /** 日期文本的颜色、大小*/
        private int mTextColorDay;
        private float mTextSizeDay;
        /** 任务次数文本的颜色、大小*/
        private int mTextColorPreFinish, mTextColorPreUnFinish, mTextColorPreNull;
        private float mTextSizePre;
        /** 选中的文本的颜色*/
        private int mSelectTextColor;
        /** 选中背景*/
        private int mSelectBg, mCurrentBg;
        private float mSelectRadius, mCurrentBgStrokeWidth;
        private float[] mCurrentBgDashPath;
    
        /** 行间距*/
        private float mLineSpac;
        /** 字体上下间距*/
        private float mTextSpac;
    
        private Paint mPaint;
        private Paint bgPaint;
    
        private float titleHeight, weekHeight, dayHeight, preHeight, oneHeight;
        private int columnWidth;       //每列宽度
    
        private Date month; //当前的月份
        private boolean isCurrentMonth;       //展示的月份是否是当前月
        private int currentDay, selectDay, lastSelectDay;    //当前日期 、 选中的日期 、上一次选中的日期(避免造成重复回调请求)
    
        private int dayOfMonth;    //月份天数
        private int firstIndex;    //当月第一天位置索引
        private int todayWeekIndex;//今天是星期几
        private int firstLineNum, lastLineNum; //第一行、最后一行能展示多少日期
        private int lineNum;      //日期行数
        private String[] WEEK_STR = new String[]{"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat", };
    
    
        public CustomCalendar(Context context) {
            this(context, null);
        }
        public CustomCalendar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            //获取自定义属性的值
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCalendar, defStyleAttr, 0);
    
            mBgMonth = a.getColor(R.styleable.CustomCalendar_mBgMonth, Color.TRANSPARENT);
            mBgWeek = a.getColor(R.styleable.CustomCalendar_mBgWeek, Color.TRANSPARENT);
            mBgDay = a.getColor(R.styleable.CustomCalendar_mBgDay, Color.TRANSPARENT);
            mBgPre = a.getColor(R.styleable.CustomCalendar_mBgPre, Color.TRANSPARENT);
    
            mMonthRowL = a.getResourceId(R.styleable.CustomCalendar_mMonthRowL, R.drawable.custom_calendar_row_left);
            mMonthRowR = a.getResourceId(R.styleable.CustomCalendar_mMonthRowR, R.drawable.custom_calendar_row_right);
            mMonthRowSpac = a.getDimension(R.styleable.CustomCalendar_mMonthRowSpac, 20);
            mTextColorMonth = a.getColor(R.styleable.CustomCalendar_mTextColorMonth, Color.BLACK);
            mTextSizeMonth = a.getDimension(R.styleable.CustomCalendar_mTextSizeMonth, 100);
            mMonthSpac = a.getDimension(R.styleable.CustomCalendar_mMonthSpac, 20);
            mTextColorWeek = a.getColor(R.styleable.CustomCalendar_mTextColorWeek, Color.BLACK);
            mSelectWeekTextColor = a.getColor(R.styleable.CustomCalendar_mSelectWeekTextColor, Color.BLACK);
    
            mTextSizeWeek = a.getDimension(R.styleable.CustomCalendar_mTextSizeWeek, 70);
            mTextColorDay = a.getColor(R.styleable.CustomCalendar_mTextColorDay, Color.GRAY);
            mTextSizeDay = a.getDimension(R.styleable.CustomCalendar_mTextSizeDay, 70);
            mTextColorPreFinish = a.getColor(R.styleable.CustomCalendar_mTextColorPreFinish, Color.BLUE);
            mTextColorPreUnFinish = a.getColor(R.styleable.CustomCalendar_mTextColorPreUnFinish, Color.BLUE);
            mTextColorPreNull  = a.getColor(R.styleable.CustomCalendar_mTextColorPreNull, Color.BLUE);
            mTextSizePre = a.getDimension(R.styleable.CustomCalendar_mTextSizePre, 40);
            mSelectTextColor = a.getColor(R.styleable.CustomCalendar_mSelectTextColor, Color.YELLOW);
            mCurrentBg = a.getColor(R.styleable.CustomCalendar_mCurrentBg, Color.GRAY);
            try {
                int dashPathId = a.getResourceId(R.styleable.CustomCalendar_mCurrentBgDashPath, R.array.customCalendar_currentDay_bg_DashPath);
                int[] array = getResources().getIntArray(dashPathId);
                mCurrentBgDashPath = new float[array.length];
                for(int i=0;i<array.length;i++){
                    mCurrentBgDashPath[i]=array[i];
                }
            }catch (Exception e){
                e.printStackTrace();
                mCurrentBgDashPath = new float[]{2, 3, 2, 3};
            }
            mSelectBg = a.getColor(R.styleable.CustomCalendar_mSelectBg, Color.YELLOW);
            mSelectRadius = a.getDimension(R.styleable.CustomCalendar_mSelectRadius, 20);
            mCurrentBgStrokeWidth = a.getDimension(R.styleable.CustomCalendar_mCurrentBgStrokeWidth, 5);
            mLineSpac = a.getDimension(R.styleable.CustomCalendar_mLineSpac, 20);
            mTextSpac = a.getDimension(R.styleable.CustomCalendar_mTextSpac, 20);
            a.recycle();  //注意回收
    
            initCompute();
    
        }
        /**计算相关常量,构造方法中调用*/
        private void initCompute(){
            mPaint = new Paint();
            bgPaint = new Paint();
            mPaint.setAntiAlias(true); //抗锯齿
            bgPaint.setAntiAlias(true); //抗锯齿
    
            map = new HashMap<>();
    
            //标题高度
            mPaint.setTextSize(mTextSizeMonth);
            titleHeight = FontUtil.getFontHeight(mPaint) + 2 * mMonthSpac;
            //星期高度
            mPaint.setTextSize(mTextSizeWeek);
            weekHeight = FontUtil.getFontHeight(mPaint);
            //日期高度
            mPaint.setTextSize(mTextSizeDay);
            dayHeight = FontUtil.getFontHeight(mPaint);
            //次数字体高度
            mPaint.setTextSize(mTextSizePre);
            preHeight = FontUtil.getFontHeight(mPaint);
            //每行高度 = 行间距 + 日期字体高度 + 字间距 + 次数字体高度
            oneHeight = mLineSpac + dayHeight + mTextSpac + preHeight;
    
            //默认当前月份
            String cDateStr = getMonthStr(new Date());
    //        cDateStr = "2015年08月";
            setMonth(cDateStr);
        }
    
        /**设置月份*/
        private void setMonth(String Month){
            //设置的月份(2017年01月)
            month = str2Date(Month);
    
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            //获取今天是多少号
            currentDay = calendar.get(Calendar.DAY_OF_MONTH);
            todayWeekIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
    
            Date cM = str2Date(getMonthStr(new Date()));
            //判断是否为当月
            if(cM.getTime() == month.getTime()){
                isCurrentMonth = true;
                selectDay = currentDay;//当月默认选中当前日
            }else{
                isCurrentMonth = false;
                selectDay = 0;
            }
            Log.d(TAG, "设置月份:"+month+"   今天"+currentDay+"号, 是否为当前月:"+isCurrentMonth);
            calendar.setTime(month);
            dayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
            //第一行1号显示在什么位置(星期几)
            firstIndex = calendar.get(Calendar.DAY_OF_WEEK)-1;
            lineNum = 1;
            //第一行能展示的天数
            firstLineNum = 7-firstIndex;
            lastLineNum = 0;
            int shengyu = dayOfMonth - firstLineNum;
            while (shengyu>7){
                lineNum ++;
                shengyu-=7;
            }
            if(shengyu>0){
                lineNum ++;
                lastLineNum = shengyu;
            }
            Log.i(TAG, getMonthStr(month)+"一共有"+dayOfMonth+"天,第一天的索引是:"+firstIndex+"   有"+lineNum+
                    "行,第一行"+firstLineNum+"个,最后一行"+lastLineNum+"个");
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            //宽度 = 填充父窗体
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);   //获取宽的尺寸
            columnWidth = widthSize / 7;
            //高度 = 标题高度 + 星期高度 + 日期行数*每行高度
            float height = titleHeight + weekHeight + (lineNum * oneHeight);
            Log.v(TAG, "标题高度:"+titleHeight+" 星期高度:"+weekHeight+" 每行高度:"+oneHeight+
                    " 行数:"+ lineNum + "  
    控件高度:"+height);
            setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                    (int)height);
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            drawMonth(canvas);
            drawWeek(canvas);
            drawDayAndPre(canvas);
        }
    
        /**绘制月份*/
        private int rowLStart, rowRStart, rowWidth;
        private void drawMonth(Canvas canvas){
            //背景
            bgPaint.setColor(mBgMonth);
            RectF rect = new RectF(0, 0, getWidth(), titleHeight);
            canvas.drawRect(rect, bgPaint);
            //绘制月份
            mPaint.setTextSize(mTextSizeMonth);
            mPaint.setColor(mTextColorMonth);
            float textLen = FontUtil.getFontlength(mPaint, getMonthStr(month));
            float textStart = (getWidth() - textLen)/ 2;
            canvas.drawText(getMonthStr(month), textStart,
                    mMonthSpac+FontUtil.getFontLeading(mPaint), mPaint);
            /*绘制左右箭头*/
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), mMonthRowL);
            int h = bitmap.getHeight();
            rowWidth = bitmap.getWidth();
            //float left, float top
            rowLStart = (int)(textStart-2*mMonthRowSpac-rowWidth);
            canvas.drawBitmap(bitmap, rowLStart+mMonthRowSpac , (titleHeight - h)/2, new Paint());
            bitmap = BitmapFactory.decodeResource(getResources(), mMonthRowR);
            rowRStart = (int)(textStart+textLen);
            canvas.drawBitmap(bitmap, rowRStart+mMonthRowSpac, (titleHeight - h)/2, new Paint());
        }
        /**绘制绘制星期*/
        private void drawWeek(Canvas canvas){
            //背景
            bgPaint.setColor(mBgWeek);
            RectF rect = new RectF(0, titleHeight, getWidth(), titleHeight + weekHeight);
            canvas.drawRect(rect, bgPaint);
            //绘制星期:七天
            mPaint.setTextSize(mTextSizeWeek);
    
            for(int i = 0; i < WEEK_STR.length; i++){
                if(todayWeekIndex == i && isCurrentMonth){
                    mPaint.setColor(mSelectWeekTextColor);
                }else{
                    mPaint.setColor(mTextColorWeek);
                }
                int len = (int)FontUtil.getFontlength(mPaint, WEEK_STR[i]);
                int x = i * columnWidth + (columnWidth - len)/2;
                canvas.drawText(WEEK_STR[i], x, titleHeight + FontUtil.getFontLeading(mPaint), mPaint);
            }
        }
        /**绘制日期和次数*/
        private void drawDayAndPre(Canvas canvas){
            //某行开始绘制的Y坐标,第一行开始的坐标为标题高度+星期部分高度
            float top = titleHeight+weekHeight;
            //
            for(int line = 0; line < lineNum; line++){
                if(line == 0){
                    //第一行
                    drawDayAndPre(canvas, top, firstLineNum, 0, firstIndex);
                }else if(line == lineNum-1){
                    //最后一行
                    top += oneHeight;
                    drawDayAndPre(canvas, top, lastLineNum, firstLineNum+(line-1)*7, 0);
                }else{
                    //满行
                    top += oneHeight;
                    drawDayAndPre(canvas, top, 7, firstLineNum+(line-1)*7, 0);
                }
            }
        }
    
        /**
         * 绘制某一行的日期
         * @param canvas
         * @param top 顶部坐标
         * @param count 此行需要绘制的日期数量(不一定都是7天)
         * @param overDay 已经绘制过的日期,从overDay+1开始绘制
         * @param startIndex 此行第一个日期的星期索引
         */
        private void drawDayAndPre(Canvas canvas, float top,
                                   int count, int overDay, int startIndex){
    //        Log.e(TAG, "总共"+dayOfMonth+"天  有"+lineNum+"行"+ "  已经画了"+overDay+"天,下面绘制:"+count+"天");
            //背景
            float topPre = top + mLineSpac + dayHeight;
            bgPaint.setColor(mBgDay);
            RectF rect = new RectF(0, top, getWidth(), topPre);
            canvas.drawRect(rect, bgPaint);
    
            bgPaint.setColor(mBgPre);
            rect = new RectF(0, topPre, getWidth(), topPre + mTextSpac + dayHeight);
            canvas.drawRect(rect, bgPaint);
    
            mPaint.setTextSize(mTextSizeDay);
            float dayTextLeading = FontUtil.getFontLeading(mPaint);
            mPaint.setTextSize(mTextSizePre);
            float preTextLeading = FontUtil.getFontLeading(mPaint);
    //        Log.v(TAG, "当前日期:"+currentDay+"   选择日期:"+selectDay+"  是否为当前月:"+isCurrentMonth);
            for(int i = 0; i<count; i++){
                int left = (startIndex + i)*columnWidth;
                int day = (overDay+i+1);
    
                mPaint.setTextSize(mTextSizeDay);
    
                //如果是当前月,当天日期需要做处理
                if(isCurrentMonth && currentDay == day){
                    mPaint.setColor(mTextColorDay);
                    bgPaint.setColor(mCurrentBg);
                    bgPaint.setStyle(Paint.Style.STROKE);  //空心
                    PathEffect effect = new DashPathEffect(mCurrentBgDashPath, 1);
                    bgPaint.setPathEffect(effect);   //设置画笔曲线间隔
                    bgPaint.setStrokeWidth(mCurrentBgStrokeWidth);       //画笔宽度
                    //绘制空心圆背景
                    canvas.drawCircle(left+columnWidth/2, top + mLineSpac +dayHeight/2,
                            mSelectRadius-mCurrentBgStrokeWidth, bgPaint);
                }
                //绘制完后将画笔还原,避免脏笔
                bgPaint.setPathEffect(null);
                bgPaint.setStrokeWidth(0);
                bgPaint.setStyle(Paint.Style.FILL);
    
                //选中的日期,如果是本月,选中日期正好是当天日期,下面的背景会覆盖上面绘制的虚线背景
                if(selectDay == day){
                    //选中的日期字体白色,橙色背景
                    mPaint.setColor(mSelectTextColor);
                    bgPaint.setColor(mSelectBg);
                    //绘制橙色圆背景,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;
                    canvas.drawCircle(left+columnWidth/2, top + mLineSpac +dayHeight/2, mSelectRadius, bgPaint);
                }else{
                    mPaint.setColor(mTextColorDay);
                }
    
                int len = (int)FontUtil.getFontlength(mPaint, day+"");
                int x = left + (columnWidth - len)/2;
                canvas.drawText(day+"", x, top + mLineSpac + dayTextLeading, mPaint);
    
                //绘制次数
                mPaint.setTextSize(mTextSizePre);
                MainJmActivity.DayFinish finish = map.get(day);
                String preStr = "0/0";
                if(isCurrentMonth){
                    if(day>currentDay){
                        mPaint.setColor(mTextColorPreNull);
                    }else if(finish!=null){
                        //区分完成未完成
                        if(finish.finish >= finish.all) {
                            mPaint.setColor(mTextColorPreFinish);
                        }else{
                            mPaint.setColor(mTextColorPreUnFinish);
                        }
                        preStr = finish.finish+"/"+finish.all;
    
                    }else{
                        mPaint.setColor(mTextColorPreNull);
                    }
                }else{
                    if(finish!=null){
                        //区分完成未完成
                        if(finish.finish >= finish.all) {
                            mPaint.setColor(mTextColorPreFinish);
                        }else{
                            mPaint.setColor(mTextColorPreUnFinish);
                        }
                        preStr = finish.finish+"/"+finish.all;
    
                    }else{
                        mPaint.setColor(mTextColorPreNull);
                    }
                }
    
                len = (int)FontUtil.getFontlength(mPaint, preStr);
                x = left + (columnWidth - len)/2;
                canvas.drawText(preStr, x, topPre + mTextSpac + preTextLeading, mPaint);
            }
        }
    
        /**获取月份标题*/
        private String getMonthStr(Date month){
            SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月");
            return df.format(month);
        }
        private Date str2Date(String str){
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月");
                return df.parse(str);
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
    
    
    
        /****************************事件处理↓↓↓↓↓↓↓****************************/
        //焦点坐标
        private PointF focusPoint = new PointF();
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int action = event.getAction() & MotionEvent.ACTION_MASK;
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    focusPoint.set(event.getX(), event.getY());
                    touchFocusMove(focusPoint, false);
                    break;
                case MotionEvent.ACTION_MOVE:
                    focusPoint.set(event.getX(), event.getY());
                    touchFocusMove(focusPoint, false);
                    break;
                case MotionEvent.ACTION_OUTSIDE:
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    focusPoint.set(event.getX(), event.getY());
                    touchFocusMove(focusPoint, true);
                    break;
            }
            return true;
        }
    
        /**焦点滑动*/
        public void touchFocusMove(final PointF point, boolean eventEnd) {
            Log.e(TAG, "点击坐标:("+point.x+" ,"+point.y+"),事件是否结束:"+eventEnd);
            /**标题和星期只有在事件结束后才响应*/
            if(point.y<=titleHeight){
                //事件在标题上
                if(eventEnd && listener!=null){
                    if(point.x>=rowLStart && point.x<(rowLStart+2*mMonthRowSpac+rowWidth)){
                        Log.w(TAG, "点击左箭头");
                        listener.onLeftRowClick();
                    }else if(point.x>rowRStart && point.x<(rowRStart + 2*mMonthRowSpac+rowWidth)){
                        Log.w(TAG, "点击右箭头");
                        listener.onRightRowClick();
                    }else if(point.x>rowLStart && point.x <rowRStart){
                        listener.onTitleClick(getMonthStr(month), month);
                    }
                }
            }else if(point.y<=(titleHeight+weekHeight)){
                //事件在星期部分
                if(eventEnd && listener!=null){
                    //根据X坐标找到具体的焦点日期
                    int xIndex = (int)point.x / columnWidth;
                    Log.e(TAG, "列宽:"+columnWidth+"  x坐标余数:"+(point.x / columnWidth));
                    if((point.x / columnWidth-xIndex)>0){
                        xIndex += 1;
                    }
                    if(listener!=null){
                        listener.onWeekClick(xIndex-1, WEEK_STR[xIndex-1]);
                    }
                }
            }else{
                /**日期部分按下和滑动时重绘,只有在事件结束后才响应*/
                touchDay(point, eventEnd);
            }
        }
    
        //控制事件是否响应
        private boolean responseWhenEnd = false;
        /**事件点在 日期区域 范围内*/
        private void touchDay(final PointF point, boolean eventEnd){
            //根据Y坐标找到焦点行
            boolean availability = false;  //事件是否有效
            //日期部分
            float top = titleHeight+weekHeight+oneHeight;
            int foucsLine = 1;
            while(foucsLine<=lineNum){
                if(top>=point.y){
                    availability = true;
                    break;
                }
                top += oneHeight;
                foucsLine ++;
            }
            if(availability){
                //根据X坐标找到具体的焦点日期
                int xIndex = (int)point.x / columnWidth;
                if((point.x / columnWidth-xIndex)>0){
                    xIndex += 1;
                }
    //            Log.e(TAG, "列宽:"+columnWidth+"  x坐标余数:"+(point.x / columnWidth));
                if(xIndex<=0)
                    xIndex = 1;   //避免调到上一行最后一个日期
                if(xIndex>7)
                    xIndex = 7;   //避免调到下一行第一个日期
    //            Log.e(TAG, "事件在日期部分,第"+foucsLine+"/"+lineNum+"行, "+xIndex+"列");
                if(foucsLine == 1){
                    //第一行
                    if(xIndex<=firstIndex){
                        Log.e(TAG, "点到开始空位了");
                        setSelectedDay(selectDay, true);
                    }else{
                        setSelectedDay(xIndex-firstIndex, eventEnd);
                    }
                }else if(foucsLine == lineNum){
                    //最后一行
                    if(xIndex>lastLineNum){
                        Log.e(TAG, "点到结尾空位了");
                        setSelectedDay(selectDay, true);
                    }else{
                        setSelectedDay(firstLineNum + (foucsLine-2)*7+ xIndex, eventEnd);
                    }
                }else{
                    setSelectedDay(firstLineNum + (foucsLine-2)*7+ xIndex, eventEnd);
                }
            }else{
                //超出日期区域后,视为事件结束,响应最后一个选择日期的回调
                setSelectedDay(selectDay, true);
            }
        }
        /**设置选中的日期*/
        private void setSelectedDay(int day, boolean eventEnd){
            Log.w(TAG, "选中:"+day+"  事件是否结束"+eventEnd);
            selectDay = day;
            invalidate();
            if(listener!=null && eventEnd && responseWhenEnd && lastSelectDay!=selectDay) {
                lastSelectDay = selectDay;
                listener.onDayClick(selectDay, getMonthStr(month) + selectDay + "日", map.get(selectDay));
            }
            responseWhenEnd = !eventEnd;
        }
    
        /****************************事件处理↑↑↑↑↑↑↑****************************/
    
    
        @Override
        public void invalidate() {
            requestLayout();
            super.invalidate();
        }
    
        /***********************接口API↓↓↓↓↓↓↓**************************/
        private Map<Integer, MainJmActivity.DayFinish> map;
        public void setRenwu(String month, List<MainJmActivity.DayFinish> list){
            setMonth(month);
    
            if(list!=null && list.size()>0){
                map.clear();
                for(MainJmActivity.DayFinish finish : list){
                    map.put(finish.day, finish);
                }
            }
            invalidate();
        }
        public void setRenwu(List<MainJmActivity.DayFinish> list){
            if(list!=null && list.size()>0){
                map.clear();
                for(MainJmActivity.DayFinish finish : list){
                    map.put(finish.day, finish);
                }
            }
            invalidate();
        }
        /**月份增减*/
        public void monthChange(int change){
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(month);
            calendar.add(Calendar.MONTH, change);
            setMonth(getMonthStr(calendar.getTime()));
            map.clear();
            invalidate();
        }
    
        private onClickListener listener;
        public void setOnClickListener(onClickListener listener){
            this.listener = listener;
        }
        interface onClickListener{
    
            public abstract void onLeftRowClick();
            public abstract void onRightRowClick();
            public abstract void onTitleClick(String monthStr, Date month);
            public abstract void onWeekClick(int weekIndex, String weekStr);
            public abstract void onDayClick(int day, String dayStr, MainJmActivity.DayFinish finish);
        }
    
    
        /***********************接口API↑↑↑↑↑↑↑**************************/
    
    }
    CustomCalendar
    package com.example.zbytexttwo;
    
    import android.graphics.Paint;
    
    /**
     * author : openXu
     * create at : 2016/07/8 12:40
     * blog : http://blog.csdn.net/xmxkf
     * gitHub : https://github.com/openXu
     * project : StockChart
     * class name : FontUtil
     * version : 1.0
     * class describe:文字相关处理帮助类
     */
    public class FontUtil {
    
        /**
         * @param paint
         * @param str
         * @return 返回指定笔和指定字符串的长度
         * @add yujiangtao 16/8/5
         */
        public static float getFontlength(Paint paint, String str) {
            return paint.measureText(str);
        }
        /**
         * @return 返回指定笔的文字高度
         * @add yujiangtao 16/8/5
         */
        public static float getFontHeight(Paint paint)  {
            Paint.FontMetrics fm = paint.getFontMetrics();
            return fm.descent - fm.ascent;
        }
        /**
         * @return 返回指定笔离文字顶部的基准距离
         * @add yujiangtao 16/8/5
         */
        public static float getFontLeading(Paint paint)  {
            Paint.FontMetrics fm = paint.getFontMetrics();
            return fm.leading- fm.ascent;
        }
    
    
    }
    FontUtil
    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:openxu="http://schemas.android.com/apk/res-auto"
        android:id="@+id/tab01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <com.example.zbytexttwo.CustomCalendar
                android:id="@+id/cal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
    
                openxu:mMonthRowL="@drawable/custom_calendar_row_left"
                openxu:mMonthRowR="@drawable/custom_calendar_row_right"
                openxu:mMonthRowSpac="20dip"
    
                openxu:mTextSizeMonth="20sp"
                openxu:mTextSizeWeek="17sp"
                openxu:mTextSizeDay="17sp"
                openxu:mTextSizePre="10sp"
    
                openxu:mTextColorMonth="#4b4b4b"
                openxu:mTextColorWeek="#9e9e9d"
                openxu:mSelectWeekTextColor="#f67633"
                openxu:mTextColorDay="#686768"
                openxu:mTextColorPreFinish="#fc7451"
                openxu:mTextColorPreUnFinish="#60ba8d"
                openxu:mTextColorPreNull="#cecdcd"
                openxu:mSelectTextColor="#ffffff"
    
                openxu:mMonthSpac="10dip"
                openxu:mLineSpac="12dip"
                openxu:mTextSpac="8dip"
    
                openxu:mCurrentBg="#6E6E6E"
                openxu:mCurrentBgStrokeWidth="1.5dip"
                openxu:mCurrentBgDashPath="@array/customCalendar_currentDay_bg_DashPath"
                openxu:mSelectBg="#fe7f5c"
                openxu:mSelectRadius="15dip" />
    
    
            <!-- <CalendarView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>-->
        </LinearLayout>
    
    </ScrollView>
    activity_main_jm
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <array name="customCalendar_currentDay_bg_DashPath">
            <item>8</item>
            <item>8</item>
            <item>8</item>
            <item>4</item>
            <item>4</item>
            <item>4</item>
        </array>
    </resources>
    array
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="CustomCalendar">
            <!--这四个颜色分别是月份、星期、日期、任务的背景色,只是方便调试测量时使用,正式试用时可配置透明色-->
            <attr name="mBgMonth" format="color" />
            <attr name="mBgWeek" format="color" />
            <attr name="mBgDay" format="color" />
            <attr name="mBgPre" format="color" />
    
            <attr name="mTextColorMonth" format="color" />           <!--标题字体颜色-->
            <attr name="mTextColorWeek" format="color" />            <!--星期字体颜色-->
            <attr name="mSelectWeekTextColor" format="color" />      <!--当前星期字体颜色-->
            <attr name="mTextColorDay" format="color" />             <!--日期字体颜色-->
            <attr name="mTextColorPreFinish" format="color" />       <!--任务次数字体颜色-->
            <attr name="mTextColorPreUnFinish" format="color" />
            <attr name="mTextColorPreNull" format="color" />
    
            <attr name="mTextSizeMonth" format="dimension" />        <!--标题字体大小-->
            <attr name="mTextSizeWeek" format="dimension" />         <!--星期字体大小-->
            <attr name="mTextSizeDay" format="dimension" />          <!--日期字体大小-->
            <attr name="mTextSizePre" format="dimension" />          <!--任务次数字体大小-->
    
            <attr name="mMonthRowL" format="reference" />            <!--月份箭头-->
            <attr name="mMonthRowR" format="reference" />            <!--月份箭头-->
            <attr name="mMonthRowSpac" format="dimension" />
    
            <attr name="mSelectTextColor" format="color" />          <!--选中日期字体颜色-->
            <attr name="mSelectBg" format="color" />                 <!--选中日期背景-->
            <attr name="mSelectRadius" format="dimension" />         <!--选中日期背景半径-->
            <attr name="mCurrentBg" format="color" />                <!--当天日期背景-->
            <attr name="mCurrentBgStrokeWidth" format="dimension" /> <!--当天日期背景虚线宽度-->
            <attr name="mCurrentBgDashPath" format="reference" />    <!--当天日期背景虚线数组-->
    
            <attr name="mMonthSpac" format="dimension" />            <!--标题月份上下间隔-->
            <attr name="mLineSpac" format="dimension" />             <!--日期行间距-->
            <attr name="mTextSpac" format="dimension" />             <!--日期和任务次数字体上下间距-->
        </declare-styleable>
    </resources>
    attrs

    没想到一个日历控件还有这么多讲究。。。

  • 相关阅读:
    POJ 1789
    南华大学 复读机(并查集)
    C
    F
    POJ 1988 Cube Stacking
    并查集(一)
    把采集到的数据发送到一个Google Docs或者Google Form上 这个网站提供了参考和例子
    几种空气颗粒物和空气质量传感器
    整流桥
    STM32 中的CEC
  • 原文地址:https://www.cnblogs.com/vvxvv/p/12768195.html
Copyright © 2020-2023  润新知