android 仿旅游日历控件_撸一个Android高性能日历控件,高仿魅族

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

compile 'com.haibin:calendarview:1.0.2'

先上效果图:

948aa111b76b7cf9a83115d2d2f1fcf3.png

13b0d58eddf488a6b1aa42976139934d.png

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

feaed8a26b1ec660690001a34433e8fa.png

3cfc358a2d5c8515e4e34d75f1f25806.png

好吧,一开始我以为日历界面是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 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 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);

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值