当前位置: 首页 > news >正文

android gridview控件使用详解_Android精美日历控件CalendarView自定义使用完全解析

a6a912c5d4b9892022bd644d8ae4504c.png

秦子帅 明确目标,每天进步一点点..... e5402ff35a27135dc77d04e676fe9c8a.png

作者 |  黄海彬

地址 | https://juejin.im/post/5a6743836fb9a01caa20aefc

详解

此框架采用组合的方式,各个模块互相独立,可自由采用各种提供的控件组合,完全自定义自己需要的UI,周视图和月视图可通过简单自定义任意自由绘制,不怕美工提需求!下面教程将介绍如何实现3个API,自定义Canvas绘制日历

CalendarView的优势:

1、热插拔设计,根据不同的UI需求完全自定义UI,简单几步即可实现,自定义事件日历标记、颜色、农历等

2、完全Canvas绘制,性能和速度都很不错,相比大多数基于GridView或RecyclerView实现的占用内存更低,启动速度更快

3、支持收缩、展开、快速年月份选择等

4、简洁易懂的源码,易学习。

Gradle

compile 'com.haibin:calendarview:3.2.9'

<dependency><groupId>com.haibingroupId><artifactId>calendarviewartifactId><version>3.2.9version><type>pomtype>dependency>

混淆proguard-rules

-keepclasseswithmembers class * {public (android.content.Context);
}

国际惯例,先上一个自定义效果图,结尾还有几个其它效果图,可自己自定义

09eb84b490ae302563b68e0a38552af0.png

4b149a14e7eb30ceccd70365d465ef38.png

各个类功能介绍

CalendarLayout

这是个辅助类,负责CalendarView的收缩控制功能,如果不需要收缩功能,无需使用它,一般使用教程如下

<com.haibin.calendarview.CalendarLayout
        android:id="@+id/calendarLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#fff"
        app:only_week_view="false"
        app:default_status="shrink"
        app:calendar_content_view_id="@+id/recyclerView">
        <com.haibin.calendarview.CalendarView
            android:id="@+id/calendarView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fff"
            app:current_month_text_color="#333333"
            app:current_month_lunar_text_color="#CFCFCF"
            app:min_year="2004"
            app:max_year="2020"
            app:other_month_text_color="#e1e1e1"
            app:other_month_lunar_text_color="#e1e1e1"
            app:scheme_text="假"
            app:week_start_with="mon"
            app:scheme_text_color="#333"
            app:scheme_theme_color="#128c4b"
            app:selected_lunar_text_color="#CFCFCF"
            app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"
            app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"
            app:selected_text_color="#333"
            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:month_view_show_mode="mode_only_current"
            app:year_view_scheme_color="#f17706"/>
        <com.haibin.calendarviewproject.group.GroupRecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/content_background" />com.haibin.calendarview.CalendarLayout>

CalendarLayout api

public void expand(); //展开public void shrink(); //收缩public boolean isExpand();//是否已经展开

<attr name="calendar_show_mode"><enum name="both_month_week_view" value="0" /><enum name="only_week_view" value="1" /><enum name="only_month_view" value="2" />attr><attr name="default_status"><enum name="expand" value="0" /> <enum name="shrink" value="1" />attr><attr name="calendar_content_view_id" format="integer" />

CalendarView

真正的日历类,可以自行通过attr配置

<com.haibin.calendarview.CalendarView
            android:id="@+id/calendarView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fff"
            app:current_month_text_color="#333333"
            app:current_month_lunar_text_color="#CFCFCF"
            app:min_year="2004"
            app:max_year="2020"
            app:other_month_text_color="#e1e1e1"
            app:other_month_lunar_text_color="#e1e1e1"
            app:scheme_text="假"
            app:scheme_text_color="#333"
            app:scheme_theme_color="#128c4b"
            app:selected_lunar_text_color="#CFCFCF"
            app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"
            app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"
            app:selected_text_color="#333"
            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"/>

完整attr

<declare-styleable name="CalendarView"><attr name="week_background" format="color" /><attr name="week_line_background" format="color" /><attr name="week_text_color" format="color" /><attr name="week_bar_view" format="string" /><attr name="month_view" format="string" /><attr name="week_view" format="string" /><attr name="scheme_text" format="string" /><attr name="day_text_size" format="dimension" /><attr name="lunar_text_size" format="dimension" /><attr name="calendar_height" format="dimension" /><attr name="scheme_text_color" format="color" /><attr name="scheme_month_text_color" format="color" /><attr name="scheme_lunar_text_color" format="color" /><attr name="scheme_theme_color" format="color" /><attr name="selected_theme_color" format="color" /><attr name="selected_text_color" format="color" /><attr name="selected_lunar_text_color" format="color" /><attr name="current_day_text_color" format="color" /><attr name="current_day_lunar_text_color" format="color" /><attr name="current_month_text_color" format="color" /><attr name="other_month_text_color" format="color" /><attr name="current_month_lunar_text_color" format="color" /><attr name="other_month_lunar_text_color" format="color" /><attr name="year_view_month_text_size" format="dimension" /><attr name="year_view_day_text_size" format="dimension" /><attr name="year_view_month_text_color" format="color" /><attr name="year_view_day_text_color" format="color" /><attr name="year_view_scheme_color" format="color" /><attr name="year_view_background" format="color" /><attr name="min_year" format="integer" /><attr name="max_year" format="integer" /><attr name="min_year_month" format="integer" /><attr name="max_year_month" format="integer" /><attr name="month_view_show_mode"><enum name="mode_all" value="0" /> <enum name="mode_only_current" value="1" /> <enum name="mode_fix" value="2" /> attr><attr name="week_start_with"><enum name="sun" value="1" /><enum name="mon" value="2" /><enum name="sat" value="7" />attr>declare-styleable>

CalendarView api

public int getCurDay(); //今天public int getCurMonth(); //当前的月份public int getCurYear(); //今年public void showSelectLayout(final int year); //快速弹出年份选择月份public void closeSelectLayout(final int position); //关闭选择年份并跳转日期/**
* 设置日期范围
*
* @param minYear 最小年份
* @param minYearMonth 最小年份对应月份
* @param maxYear 最大月份
* @param maxYearMonth 最大月份对应月份
*/public void setRange(int minYear, int minYearMonth,int maxYear, int maxYearMonth) public void setOnYearChangeListener(OnYearChangeListener listener);//年份切换事件public void setOnDateSelectedListener(OnDateSelectedListener listener);//日期选择事件public void setSchemeDate(List mSchemeDate);//标记日期public void update();//动态更新public Calendar getSelectedCalendar(); //获取选择的日期public void scrollToPre();//滚动到上一个月public void scrollToNext();//滚动到下一个月public void scrollToCalendar(int year, int month, int day);//滚动到指定日期/**
  * 设置背景色
  *
  * @param monthLayoutBackground 月份卡片的背景色
  * @param weekBackground 星期栏背景色
  * @param lineBg 线的颜色
 */public void setBackground(int monthLayoutBackground, int weekBackground, int lineBg)/**
  * 设置文本颜色
  *
  * @param curMonthTextColor 当前月份字体颜色
  * @param otherMonthColor 其它月份字体颜色
  * @param lunarTextColor 农历字体颜色
 */public void setTextColor(int curMonthTextColor,int otherMonthColor,int lunarTextColor)/**
  * 设置选择的效果
  *
  * @param style 选中的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
  * @param selectedThemeColor 选中的标记颜色
  * @param selectedTextColor 选中的字体颜色
 */public void setSelectedColor(int style, int selectedThemeColor, int selectedTextColor)/**
  * 设置标记的色
  *
  * @param style 标记的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
  * @param schemeColor 标记背景色
  * @param schemeTextColor 标记字体颜色
 */public void setSchemeColor(int style, int schemeColor, int schemeTextColor)/**
 * 设置背景色
 *
 * @param yearViewBackground 年份卡片的背景色
 * @param weekBackground 星期栏背景色
 * @param lineBg 线的颜色
*/public void setBackground(int yearViewBackground, int weekBackground, int lineBg)

这个控件的特别之处就是它的UI是可以交给客户端自由绘制的,因此可以自由发挥想象力,绘制你需要的日历效果UI

接下来介绍如何完全自定义日历,自定义日历需要同时自定义月视图和周视图,代码几乎一样,需要实现三个回调函数即可,如下:

onDrawSelectedonDrawSchemeonDrawText

/**
 * 首先继承月视图,假如我们想实现高仿魅族的日历
 */public class MeiZuMonthView extends MonthView {    /**
     * 自定义魅族标记的文本画笔
     */    private Paint mTextPaint = new Paint();    /**
     * 自定义魅族标记的圆形背景
     */    private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeiZuMonthView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }    /**
     * 绘制选中的日子
     * @param canvas canvas
     * @param calendar 日历日历calendar
     * @param x 日历Card x起点坐标
     * @param y 日历Card y起点坐标
     * @param hasScheme hasScheme 非标记的日期
     * @return 返回true 则会继续绘制onDrawScheme,因为这里背景色不是是互斥的,所以返回true,返回false,则点击scheme标记的日子,则不继续绘制onDrawScheme,自行选择即可
     */    @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);        return true;    }    /**
     * 绘制标记的事件日子
     * @param canvas canvas
     * @param calendar 日历calendar
     * @param x 日历Card x起点坐标
     * @param y 日历Card y起点坐标
     */    @Override    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, y + mPadding + mSchemeBaseLine, mTextPaint);    }    /**
     * 绘制文本
     * @param canvas canvas
     * @param calendar 日历calendar
     * @param x 日历Card x起点坐标
     * @param y 日历Card y起点坐标
     * @param hasScheme 是否是标记的日期
     * @param isSelected 是否选中
     */    @Override    protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {        int cx = x + mItemWidth / 2;        int top = y - mItemHeight / 6;        if (isSelected) {//优先绘制选择的            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    mSelectTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);        } else if (hasScheme) {//否则绘制具有标记的            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);        } else {//最好绘制普通文本            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentDay() ? mCurDayTextPaint :                            calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,                    calendar.isCurrentDay() ? mCurDayLunarTextPaint :                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);        }    }    /**
     * dp转px
     *
     * @param context context
     * @param dpValue dp
     * @return px
     */    private static int dipToPx(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}

实现自定义周视图,周视图除了三个回调函数少了一个y参数,其它一样,因为周视图只有一行,所以可直接copy MonthView的代码,令y=0即可,如下

public class MeizuWeekView extends WeekView {    private Paint mTextPaint = new Paint();    private Paint mSchemeBasicPaint = new Paint();    private float mRadio;    private int mPadding;    private float mSchemeBaseLine;    public MeizuWeekView(Context context) {        super(context);        mTextPaint.setTextSize(dipToPx(context, 8));        mTextPaint.setColor(0xffffffff);        mTextPaint.setAntiAlias(true);        mTextPaint.setFakeBoldText(true);        mSchemeBasicPaint.setAntiAlias(true);        mSchemeBasicPaint.setStyle(Paint.Style.FILL);        mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);        mSchemeBasicPaint.setColor(0xffed5353);        mSchemeBasicPaint.setFakeBoldText(true);        mRadio = dipToPx(getContext(), 7);        mPadding = dipToPx(getContext(), 4);        Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();        mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);    }    /**
     *
     * @param canvas canvas
     * @param calendar 日历日历calendar
     * @param x 日历Card x起点坐标
     * @param hasScheme hasScheme 非标记的日期
     * @return true 则绘制onDrawScheme,因为这里背景色不是是互斥的
     */    @Override    protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {        mSelectedPaint.setStyle(Paint.Style.FILL);        mSelectedPaint.setColor(0x80cfcfcf);        canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);        return true;    }    @Override    protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {        mSchemeBasicPaint.setColor(calendar.getSchemeColor());        canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, mPadding + mRadio, mRadio, mSchemeBasicPaint);        canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mRadio, mPadding + mSchemeBaseLine, mTextPaint);    }    @Override    protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {        int cx = x + mItemWidth / 2;        int top = -mItemHeight / 6;        if (isSelected) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    mSelectTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);        } else if (hasScheme) {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mCurMonthLunarTextPaint);        } else {            canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,                    calendar.isCurrentDay() ? mCurDayTextPaint :                            calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);            canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,                    calendar.isCurrentDay() ? mCurDayLunarTextPaint :                            calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);        }    }    /**
     * dp转px
     *
     * @param context context
     * @param dpValue dp
     * @return px
     */    private static int dipToPx(Context context, float dpValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dpValue * scale + 0.5f);    }}

最后通过CalendarView两个attr配置class路径即可,是不是很像自定义Behavior?

app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView"

最后各种自定义UI效果自由欣赏,源码都在demo

52559aa45c945a852d6539cf482a2f4e.png

53b5da52740e19435596e23f514f6032.png

f8e1c20699679f475aa6e2d0f5f5ecff.png

daeb3ca35585d77de6065b32125d4a50.png

baaa6b29a176d88c6d0bdeddb1da8f4a.png

09eb84b490ae302563b68e0a38552af0.png

里面作者实现了几种类型的风格,可以参考实现

项目开源地址,一点贡献

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

---END---

78550a327859f6307f2143aca1d6c518.png

 创作不易,点个“ 在看 29dc9b1ad8221c73e942e372bb5adcbe.png

相关文章:

  • postgresql immutable_PostgreSQL 之函数索引
  • recyclerview放不同的布局_RecyclerView 性能优化
  • mq3.8.9版本有什么不同_【SEACMS 8.9版本】从变量覆盖到变量覆盖的SQL注入漏洞
  • matlab中k-means算法_OpenCV图像处理-KMeans 图像处理
  • python中的转义字符是什么意思_python 转义字符、运算符、列表。。。。
  • python发微信公众号消息_个人微信公众号搭建Python实现 -接收和发送消息-基本说明与实现(14.2.1)...
  • python爬虫代写价格_python爬取京东价格
  • lua get reused time_利用redis-lua+python实现接口限流
  • server2008网卡驱动包_网卡工作原理详解
  • svpwm的原理及法则推导和控制算法详解_电机控制要点解疑:SPWM,SVPWM和矢量控制...
  • python删除文件指定字符串,从Python中的字符串中删除特定字符
  • python基础读后感_《python基础教程 》第一章 读书笔记
  • 二叉树的字符图形显示程序_(CSPJ)入门级C++语言试题A卷答案解析阅读程序
  • 服务器显示地址正在使用_用Windows Storage Server 2008做iSCSI存储服务器
  • 权限设计表结构超详细_超详细!!五金模具组件及工程结构设计
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • 2019.2.20 c++ 知识梳理
  • Angular 2 DI - IoC DI - 1
  • CentOS7简单部署NFS
  • django开发-定时任务的使用
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Just for fun——迅速写完快速排序
  • PAT A1017 优先队列
  • PHP那些事儿
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • Vue.js源码(2):初探List Rendering
  • 从零开始学习部署
  • 对象引论
  • 两列自适应布局方案整理
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 云大使推广中的常见热门问题
  • Hibernate主键生成策略及选择
  • ​Spring Boot 分片上传文件
  • #### go map 底层结构 ####
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (1)虚拟机的安装与使用,linux系统安装
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (翻译)terry crowley: 写给程序员
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)scrum常见工具列表
  • (转)setTimeout 和 setInterval 的区别
  • (转)四层和七层负载均衡的区别
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .gitignore文件---让git自动忽略指定文件
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET/C# 使窗口永不获得焦点
  • .NET成年了,然后呢?
  • .NET上SQLite的连接