CalendarView使用笔记

2022-03-11  本文已影响0人  紫鹰

背景

遇到一个需求,自定义一个日历。日历有两种背景展示,文字有三种颜色

于是github上找了一个满足条件且star最多的自定义日历的控件

项目地址

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

优势

canves绘制,方便实现背景颜色样式、文字内容和颜色的自定义控制

使用

<com.haibin.calendarview.CalendarView android:id="@+id/calendarView" 
  android:layout_width="match_parent" android:layout_height="wrap_content" 
  android:layout_marginTop="@dimen/dp_32" android:background="#fff"     
  app:current_month_lunar_text_color="#CFCFCF" 
  app:current_month_text_color="#333333" app:layout_constraintLeft_toLeftOf="parent" 
  app:layout_constraintTop_toBottomOf="@+id/tv_current_month" app:min_year="2004" 
  app:month_view="XXX.SportsMatchMonthView" 
  app:month_view_show_mode="mode_only_current" 
  app:other_month_text_color="#e1e1e1" app:scheme_lunar_text_color="#ffffff" 
  app:scheme_text="假" app:scheme_text_color="#fff" 
  app:scheme_theme_color="#128c4b" app:selected_lunar_text_color="#fff" 
  app:selected_text_color="#fff" app:selected_theme_color="#108cd4" 
  app:week_background="#fff" app:week_text_color="#111" 
  app:year_view_day_text_color="#333333" app:year_view_day_text_size="9sp" 
  app:year_view_month_text_color="#ff0000" app:year_view_month_text_size="20sp" 
  app:year_view_scheme_color="#f17706" />

如下配置代码是自定义样式内容的入口

<com.haibin.calendarview.CalendarView android:id="@+id/calendarView" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_marginTop="@dimen/dp_32"
    android:background="#fff" 
    app:current_month_lunar_text_color="#CFCFCF" 
    app:current_month_text_color="#333333" 
    app:layout_constraintLeft_toLeftOf="parent" 
    app:layout_constraintTop_toBottomOf="@+id/tv_current_month" 
    app:min_year="2004" app:month_view="XXX.SportsMatchMonthView" 
    app:month_view_show_mode="mode_only_current" 
    app:other_month_text_color="#e1e1e1" 
    app:scheme_lunar_text_color="#ffffff" 
    app:scheme_text="假" app:scheme_text_color="#fff" 
    app:scheme_theme_color="#128c4b" app:selected_lunar_text_color="#fff" 
    app:selected_text_color="#fff" app:selected_theme_color="#108cd4" 
    app:week_background="#fff" app:week_text_color="#111" 
    app:year_view_day_text_color="#333333" 
    app:year_view_day_text_size="9sp" 
    app:year_view_month_text_color="#ff0000" 
    app:year_view_month_text_size="20sp" 
    app:year_view_scheme_color="#f17706" />

该XXX.SportsMatchMonthView继承自MonthView,代码如下

public class SportsMatchMonthView extends MonthView {
    public SportsMatchMonthView(Context context) {
     super(context);
    } 
    @Override
     protected void onPreviewHook() { 
    }
    /**
    如果需要点击Scheme没有效果,则return true
     *
     * @param canvas canvas
     * @param calendar 日历日历calendar
     * @param x 日历Card x起点坐标
     * @param y 日历Card y起点坐标
     * @param hasScheme hasScheme 非标记的日期
     * @return false 则不绘制onDrawScheme,因为这里背景色是互斥的
     */
     @Override
     protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) { 
        return true;
     } 
    /**
     * 左右相对日期控件本身缩进比例
     */
     private float widthGapRadio = 0.04f;
     /**
     * 上下相对日期控件本身缩进比例
     */
     private float heightGapRadio = 0.06f; 
    /**
     * 默认文字大小
     */
     private float textFount = 16; 
     @Override
     protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) { 
        float radius = 0.14f * mItemWidth; 
        float leftX = x + widthGapRadio * mItemWidth;
         float topY = y + heightGapRadio * mItemHeight;
         float rightX = x + (1 - widthGapRadio) * mItemWidth;
         float bottomY = y + (1 - heightGapRadio) * mItemHeight; 
         Path path = new Path();
         //起点,顶部横线左侧
         path.moveTo(leftX + radius, topY);
         //绘制顶部横线
         path.lineTo(rightX - radius, topY);
         //右上角圆弧
         path.quadTo(rightX, topY, rightX, topY + radius);
         //右侧横线
         path.lineTo(rightX, bottomY - radius);
         //右下角圆弧
         path.quadTo(rightX, bottomY, rightX - radius, bottomY);
         //底部横线
         path.lineTo(leftX + radius, bottomY);
         //左下圆弧
         path.quadTo(leftX, bottomY, leftX, bottomY - radius);
         //左侧横线
         path.lineTo(leftX, topY + radius);
         //左上圆弧
         path.quadTo(leftX, topY, leftX + radius, topY);
         //封闭子图形
         path.close();
         canvas.drawPath(path, mSchemePaint);
     } 
    @SuppressWarnings("IntegerDivisionInFloatingPointContext")
     @Override
     protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
         float textLength = getDefaultTextPaint().measureText(String.valueOf(calendar.getDay()));
         int cx = x + mItemWidth / 2 - (int) textLength/2;
         int top = y ;
         mSchemePaint.getColor();
         Log.v("onDrawText", "mSchemePaint.getColor() = " + mSchemePaint.getColor());
         calendar.getScheme();
         Log.v("onDrawText", "calendar.getScheme() = " + calendar.getScheme());
         //Calendar.Scheme 指定文字颜色,若未制定,取默认颜色
         List<Calendar.Scheme> schemes = calendar.getSchemes();
        // calendar.getLunar()
         if (schemes == null || schemes.isEmpty()) {
             canvas.drawText(String.valueOf(calendar.getDay()), cx , mTextBaseLine + top,
             getDefaultTextPaint());
         } else {
             Calendar.Scheme scheme = schemes.get(0);
             canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
             getColorPaint(scheme.getShcemeColor()));
         }
      } 
       Map<Integer,Paint> catchPaint = new HashMap<>();
       private Paint getColorPaint(int shcemeColor) {
       Paint paint = catchPaint.get(shcemeColor);
       if (paint != null){
           return paint;
       }else {
           paint = new Paint();
           paint.setColor(shcemeColor);
           paint.setTextSize(AppUtils.dip2Px(getContext(),textFount));
           catchPaint.put(shcemeColor,paint);
           return paint;
         }
     } 
    Paint defaultPaint ;
         private Paint getDefaultTextPaint(){
             if (defaultPaint != null){
                 return defaultPaint;
             }else {
                 defaultPaint = new Paint();
                 defaultPaint.setColor(-0x666666);
                 defaultPaint.setTextSize(AppUtils.dip2Px(getContext(),textFount));
                 return defaultPaint;
             }
         }
}

1.背景自定义

自定义背景在此方法中

protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {}

这里涉及了Path、Paint的几个重要方法和属性

//起点移动到指定位置 path.moveTo(leftX + radius, topY); //绘制横线,起点为上次的重点,这里的参数只需指定终点即可 path.lineTo(rightX - radius, topY); //绘制贝塞尔曲线,前两个参数为控制点,后两个参数为终点 path.quadTo(rightX, topY, rightX, topY + radius);` //封闭子图形 path.close();

paint设置为

mSchemePaint.setAntiAlias(true);
mSchemePaint.setStyle(Paint.Style.FILL);
mSchemePaint.setStrokeWidth(2);

绘制区域,封闭区域内都会被覆盖指定颜色

canvas.drawPath(path, mSchemePaint);

2.文字自定义

绘制文字为此方法

protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {}

这里的CalendarView的设计,在绘制背景的时候,会有参数指定背景的颜色值,背景的形状自己去定义;然而在绘制文字的时候,却是使用预定义的三种文字颜色。

这种设计可以满足大多数情况的要求,一般来说,我们对背景的样式会有更多的要求,而文字一般会根据背景是否选中情况展示黑白两种颜色以增强对比度。

而我们的设计要求是,选中的样式都是一致的,然而在选中的样式中,还有一些受关注的选中状态,这种区别我们期望通过文字的方式凸显出来。虽然CalendarView控件本身没提供便捷的方式进行设置,然而它却通过设置Scheme的方式保留了这种开放性。

private fun getSchemeCalendar(
 year: Int,
 month: Int,
 day: Int,
 type: Int
): Calendar {
 val calendar = Calendar()
 calendar.year = year
 calendar.month = month
 calendar.day = day
 calendar.schemeColor = -0x001c1d //背景颜色,CalendarView实现中已经将其设置给了画笔
 val schemes: MutableList<Scheme> = ArrayList()
 val scheme = Scheme()
 scheme.scheme = "test"
 scheme.type = type
 if (type ==2){
 scheme.shcemeColor = -0x27B8BA//指定schema的颜色,这个需要在自定义的view中取出使用
 }else{
 scheme.shcemeColor = -0xCCCCCC
 }
 schemes.add(scheme)
 calendar.schemes = schemes
 return calendar
}

scheme约束使用

3.点击事件

calendarView.setOnCalendarSelectListener(object :
 CalendarView.OnCalendarSelectListener {
 override fun onCalendarOutOfRange(calendar: Calendar?) {
 Log.v("vhawk","onCalendarOutOfRange calendar = ${calendar} ")
 }

 override fun onCalendarSelect(calendar: Calendar?, isClick: Boolean) {
 Log.v("vhawk","onCalendarSelect calendar = ${calendar} ${isClick}")
 }
})

后继

进一步了解CalendarView的细节,学习其中的设计思路

上一篇下一篇

猜你喜欢

热点阅读