• 撸一个Android高性能日历控件,高仿魅族


    Android原生的CalendarView根本无法满足我们日常开发的需要,在开发吾记APP的过程中,我觉得需要来一款高性能且美观简洁的日历控件,觉得魅族的日历风格十分适合,于是打算撸一款。

    github地址:https://github.com/huanghaibin-dev/CalendarView

    compile 'com.haibin:calendarview:1.0.2'

    先上效果图:

    动手之前我们需要分析一下魅族是怎么设计如此高性能的日历的,我们打开开发者选项中的显示布局边界:

    好吧,一开始我以为日历界面是ViewPager+RecyclerView的,但是这么一看明显就不是了,如果是RecyclerView,那么我们假设每个月的卡片都有5*7=35个item,每个item根布局是RelativeLayout+3个TextView,我们大概估算一下日历初始化时要加载的控件:

    3个ViewPager的item * 35个RecyclerView的Item * 4(每个item的控件数) + 8 (星期栏)= 420+ 

    我的天,这可不能这么干,明显性能大打折扣,我们再来看看月份控件:

    好吧,这里看上去就是ViewPager+RecyclerView来做的,每个RecyclerView的item都只是一个控件,里面绘制了文本 ,这里大概就分析清楚了。

    我们采取折中的方式,日历界面和月份卡界面均采用ViewPager+RecyclerView的方式,不同的是所有的item我们都采用自定义ViewCanvas绘制的方式来做,这样性能虽然比不上魅族,但速度体验基本差不多,下面先看日历界面的item代码:只需要绘制3个文本即可

    public class CellView extends View {
    
        private int mDay = 20;
        private String mLunar;
        private String mScheme;
        private Paint mDayPaint = new Paint();
        private Paint mLunarPaint = new Paint();
        private Paint mSchemePaint = new Paint();
        private Paint mCirclePaint = new Paint();
        private int mRadius;
        private int mCirclePadding;
        private int mCircleColor;
    
        public CellView(Context context) {
            this(context, null);
        }
    
        public CellView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
    
            mDayPaint.setAntiAlias(true);
            mDayPaint.setColor(Color.BLACK);
            mDayPaint.setFakeBoldText(true);
            mDayPaint.setTextAlign(Paint.Align.CENTER);
    
            mLunarPaint.setAntiAlias(true);
            mLunarPaint.setColor(Color.GRAY);
            mLunarPaint.setTextAlign(Paint.Align.CENTER);
    
            mSchemePaint.setAntiAlias(true);
            mSchemePaint.setColor(Color.WHITE);
            mSchemePaint.setFakeBoldText(true);
            mSchemePaint.setTextAlign(Paint.Align.CENTER);
    
            mCirclePaint.setAntiAlias(true);
            mCirclePaint.setStyle(Paint.Style.FILL);
    
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CellView);
            mDayPaint.setTextSize(array.getDimensionPixelSize(R.styleable.CellView_cell_day_text_size, 18));
            mLunarPaint.setTextSize(array.getDimensionPixelSize(R.styleable.CellView_cell_lunar_text_size, 12));
            mRadius = (int) array.getDimension(R.styleable.CellView_cell_scheme_radius, 8);
            mSchemePaint.setTextSize(array.getDimensionPixelSize(R.styleable.CellView_cell_scheme_text_size, 6));
            mCirclePadding = array.getDimensionPixelSize(R.styleable.CellView_cell_circle_padding, 4);
            mCirclePaint.setColor(array.getColor(R.styleable.CellView_cell_circle_color, 0xff16BB7F));
            array.recycle();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int width = getWidth();
            int height = getHeight();
            int w = (width - getPaddingLeft() - getPaddingRight());
            int h = (height - getPaddingTop() - getPaddingBottom()) / 4;
            canvas.drawText(String.valueOf(mDay), w / 2, 2 * h + getPaddingTop(), mDayPaint);
            canvas.drawText(mLunar, w / 2, 4 * h + getPaddingTop(), mLunarPaint);
            if (!TextUtils.isEmpty(mScheme)) {
                canvas.drawCircle(w / 2 + mCirclePadding + mDayPaint.getTextSize(), getPaddingTop() + h, mRadius, mCirclePaint);
                canvas.drawText(mScheme, w / 2 + mCirclePadding + mDayPaint.getTextSize(), getPaddingTop() + mRadius / 2 + h, mSchemePaint);
            }
        }
    
        /**
         * 初始化日历
         * @param day 天
         * @param lunar 农历
         * @param scheme 事件标记
         */
        void init(int day, String lunar, String scheme) {
            this.mDay = day;
            this.mLunar = lunar;
            this.mScheme = scheme;
        }
    
        void setTextColor(int textColor) {
            mDayPaint.setColor(textColor);
            mLunarPaint.setColor(textColor);
        }
    
        void setCircleColor(int circleColor) {
            mCirclePaint.setColor(circleColor);
            invalidate();
        }
    }

    月份卡自定义View

    public class MonthView extends View {
        private int mDiff;//第一天偏离周日多少天
        private int mCount;//总数
        private int mLastCount;//最后一行的天数
        private int mLine;//多少行
        private Paint mPaint = new Paint();
        private Paint mSchemePaint = new Paint();
        private List<Calendar> mSchemes;
        private Calendar mCalendar;
    
        public MonthView(Context context) {
            this(context, null);
        }
    
        public MonthView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mPaint.setAntiAlias(true);
            mPaint.setTextAlign(Paint.Align.CENTER);
            mSchemePaint.setAntiAlias(true);
            mSchemePaint.setTextAlign(Paint.Align.CENTER);
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MonthView);
            mPaint.setTextSize(array.getDimensionPixelSize(R.styleable.MonthView_month_view_text_size, 12));
            mSchemePaint.setTextSize(array.getDimensionPixelSize(R.styleable.MonthView_month_view_text_size, 12));
            mPaint.setColor(array.getColor(R.styleable.MonthView_month_view_text_color, Color.BLACK));
            mSchemePaint.setColor(array.getColor(R.styleable.MonthView_month_view_remark_color, Color.RED));
            array.recycle();
            measureLine();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int width = getWidth();
            int height = getHeight();
            int pLeft = getPaddingLeft();
            int w = (width - getPaddingLeft() - getPaddingRight()) / 7;
            int h = (height - getPaddingTop() - getPaddingBottom()) / 6;
            int d = 0;
            for (int i = 0; i < mLine; i++) {
                if (i == 0) {//第一行
                    for (int j = 0; j < (7 - mDiff); j++) {
                        ++d;
                        canvas.drawText(String.valueOf(j + 1), mDiff * w + j * w + pLeft + w / 2, h, isScheme(d) ? mSchemePaint : mPaint);
                    }
                } else if (i == mLine - 1 && mLastCount != 0) {
                    int first = mCount - mLastCount + 1;
                    for (int j = 0; j < mLastCount; j++) {
                        ++d;
                        canvas.drawText(String.valueOf(first), j * w + pLeft + w / 2, (i + 1) * h, isScheme(d) ? mSchemePaint : mPaint);
                        ++first;
                    }
                } else {
                    int first = i * 7 - mDiff + 1;
                    for (int j = 0; j < 7; j++) {
                        ++d;
                        canvas.drawText(String.valueOf(first), j * w + pLeft + w / 2, (i + 1) * h, isScheme(d) ? mSchemePaint : mPaint);
                        ++first;
                    }
                }
            }
        }
    
        /**
         * 计算行数
         */
        private void measureLine() {
            int offset = mCount - (7 - mDiff);
            mLine = 1 + (offset % 7 == 0 ? 0 : 1) + offset / 7;
            mLastCount = offset % 7;
        }
    
        /**
         * 初始化月份卡
         * @param mDiff 偏离天数
         * @param mCount 当月总天数
         * @param mYear 哪一年
         * @param mMonth 哪一月
         */
         void init(int mDiff, int mCount, int mYear, int mMonth) {
            this.mDiff = mDiff;
            this.mCount = mCount;
            mCalendar = new Calendar();
            mCalendar.setYear(mYear);
            mCalendar.setMonth(mMonth);
            measureLine();
            invalidate();
        }
    
        void setSchemes(List<Calendar> mSchemes) {
            this.mSchemes = mSchemes;
        }
    
        void setSchemeColor(int schemeColor) {
            if (schemeColor != 0)
                mSchemePaint.setColor(schemeColor);
            if(schemeColor == 0xff30393E)
                mSchemePaint.setColor(Color.RED);
        }
    
        private boolean isScheme(int day) {
            if (mSchemes == null || mSchemes.size() == 0)
                return false;
            mCalendar.setDay(day);
            return mSchemes.contains(mCalendar);
        }
    }
    

      

    其它代码没有什么难度,日历算法是github上找的,更多详情请看仓库地址:https://github.com/huanghaibin-dev/CalendarView

  • 相关阅读:
    构造 非构造 代码块
    Random 类生成随机数
    JAVA寄存器
    PyCharm配置远程python解释器和在本地修改服务器代码
    Java实现常见的排序算法
    推荐系统冷启动问题解决方案
    AVL树C代码
    AVL树->图解2
    AVL树->图解1
    二叉查找树(Binary Sort Tree)
  • 原文地址:https://www.cnblogs.com/huanghaibin/p/6612854.html
Copyright © 2020-2023  润新知