自定义view---带标签的CalendarView

2023-12-21 00:18

本文主要是介绍自定义view---带标签的CalendarView,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

人老了,就容易暴躁。直接上图,暴躁如我。
这里写图片描述

功能:1.当天会有一个蓝色半弧标志2.如果某一天 签到了,会显示“小爪子”图片3.如果点击了某一天,则会显示灰色圆形选中状态4.每一天的底下可以有不同的小颜色点,表示当天的出勤状态(让服务器哥们算好,别弄叉了数据)

这是一个简单的自定义控件,总的来说,没什么技术含量(虽然我搞了两天才弄出来),不过还是希望能分享下,要不然,搞了两天的东西不拿来强行装b,简直是浪费。

废话不多说,暴躁如我,走起。

先说下思路:第一步:准备好Paint(分割线画笔【mPaintLine】,文字画笔【mPaintTv】,小圆点画笔【mPaintPoint】,背景图画笔【mPaintBg】)第二步:分析需要的数据bean,然后OnDraw绘制第三步:处理点击事件。第四步:优化(布局最大高度[OnMeasure])。

第一步就不说了,不懂的请从自定义view的基础看起吧。
这里只说一点,mPaintTv这个画笔,一定要将设置绘制点为中心点mPaintTv.setTextAlign(Paint.Align.CENTER);

第二步,分析:
六种状态自然是需要的:

public String earlyStatus;     //是否早退(0:未早退1:早退)
public String singleStatus;           //是否缺卡(0:未缺卡1:缺卡)
public String workStatus;         //是否旷工(0:未旷工1:旷工)
public String approvingStatus;         //是否请假(0:未请假1:请假)
public String lateStatus;           //是否迟到(0:未迟到1:迟到)
public String outStatus;        //是否外勤(0:未出外勤1:已出外勤)

当然还有签到状态 public String status; //是否签到(0:未签到1:已签到)

这里为了方便,再加上一个天份日期 public String day; //日期

然后就直接开始绘制了(这里是重点):

  • 绘制顶部横线
canvasWidth = getWidth();
canvas.drawLine(0,0, canvasWidth,0,mPaintLine);
  • 绘制星期文字
for (int i = 0; i < weekStr.length; i++) {canvas.drawText(weekStr[i], viewMargin + mPaintTv.measureText("11")/2 +i * (canvasWidth - viewMargin*2 - mPaintTv.measureText("11")) / 6, posweekStrY, mPaintTv);}

横坐标:
因为mPaintTv绘制点在文字的正中心,所以,“日”字的绘制的x坐标为,“日”字长度的二分之一,加上字体距离边界的viewMargin,而后其他星期的字的绘制横坐标怎么算:
剩下的距离平分成六份
(控件总宽度-左右的viewMargin-(“日”字的二分之一的距离 + “六”字的二分之一的距离))/ 6
这里写图片描述
纵坐标:
纵坐标的绘制,如果不知道textview的绘制原理的话,很容一迷糊,所以:走你,传送门—-textview的绘制坐标原理
(如图:textview的paint绘制,并不是以最底的线为基准,而是以baseline为基准,也就是说,
canvas.drawText(“text”,x,y,paintTv);中的y,指的是baseline所在的y轴坐标。

同时,通过mPaintTv.getFontMetrics()可以获取到 leading,ascent,descent 三个值,但是这里要注意的是,leading和ascent的值是负数,因为是以baseline为横轴,baseline之上就是负值。
这里写图片描述
纵坐标就等于:
posweekStrY = lineTextDest - (mPaintTv.getFontMetrics().ascent + mPaintTv.getFontMetrics().leading);

  • 绘制月份天数文字
    首先,确定当月第一天是星期几(代表第一天前有几个地方不需要绘制),总共要绘制dayNums+ firstDayOfWeek个,firstDayOfweek之前都不drawText

计算纵坐标:

posMonthDayY = poslineBottomY + lineTextDest - (mPaintTv.getFontMetrics().ascent + mPaintTv.getFontMetrics().leading)+ (j/7) * (mPaintTv.getTextSize() + lineTextDest + 2 * pointRadius + pointMarginTop);

计算横坐标:

posMonthDayX = viewMargin + mPaintTv.measureText("11") / 2+ (j%7) * (canvasWidth - viewMargin * 2 - mPaintTv.measureText("11")) / 6;

绘制文字:

         canvas.drawText(calendarBeanList.get(j - firstDayOfWeek).day,posMonthDayX, posMonthDayY, mPaintTv);
  • 绘制背景图
    计算绘制的区域:
    -6和+6 是为了让图片能比文字的绘制区域稍微大一点,显得好看(本人很注重审美的)。
RectF rect = new RectF((float) (posMonthDayX - mPaintTv.measureText("11") / 2)-6,(float) (posMonthDayY - (-mPaintTv.getFontMetrics().ascent - mPaintTv.getFontMetrics().leading))-6,(float) (posMonthDayX + mPaintTv.measureText("11") / 2)+6,(float) (posMonthDayY + mPaintTv.getFontMetrics().descent)+6);
  • 绘制圆点
int paintCount = calendarBeanList.get(j-firstDayOfWeek).getPaintColors().size();
//绘制圆点
for (int i = 0; i < paintCount; i++) {mPaintPoint.setColor(Color.parseColor(calendarBeanList.get(j-firstDayOfWeek).getPaintColors().get(i)));if (paintCount%2 == 0){canvas.drawCircle(posMonthDayX -(2*i-1)*(dotMargin/2+pointRadius), posMonthDayY +pointRadius+pointMarginTop,pointRadius,mPaintPoint);}else {canvas.drawCircle(posMonthDayX -((int)Math.pow(-1,i+1)*(i+1)/2)*(dotMargin+2*pointRadius), posMonthDayY +pointRadius+pointMarginTop,pointRadius,mPaintPoint);}
}

这里写图片描述
分为两种:
奇数个小点:先绘制圆点坐标的小点,接着是圆点左边的第一个小点,接着是圆点右边的第一个小点,然后是,圆点左边第二个小点,再绘制圆点右边第二个小点。。。(Math.pow(-1,i+1)来控制圆点左边是负数,右边是正数)
偶数个小点:先绘制左边在绘制右边,在绘制左二,依次进行。

  • 点击事件判断
    @Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN://判断 点击的是哪一天for (int j = 0; j < dayNums+ firstDayOfWeek; j++) {if (j >= firstDayOfWeek){float posMonthDayY = poslineBottomY + lineTextDest - (mPaintTv.getFontMetrics().ascent + mPaintTv.getFontMetrics().leading)+ (j/7) * (mPaintTv.getTextSize() + lineTextDest + 2 * pointRadius + pointMarginTop);float posMonthDayX = viewMargin + mPaintTv.measureText("11") / 2+ (j%7) * (canvasWidth - viewMargin * 2 - mPaintTv.measureText("11")) / 6;if (x > posMonthDayX - mPaintTv.measureText("11") / 2-6 &&x < posMonthDayX + mPaintTv.measureText("11") / 2+6 &&y > posMonthDayY - (-mPaintTv.getFontMetrics().ascent - mPaintTv.getFontMetrics().leading)-6 &&y < posMonthDayY + mPaintTv.getFontMetrics().descent+6){//只有小于当前日期的才能点击if (currentYear>chooseYear ||(currentYear == chooseYear && currentMonth>chooseMonth) ||(currentYear == chooseYear && currentMonth == chooseMonth && currentDay >= j - firstDayOfWeek + 1)) {setChooseYMD(chooseYear, chooseMonth, j - firstDayOfWeek + 1);if (iOnClickDateListener != null){iOnClickDateListener.onClickDate(chooseYear,chooseMonth,j - firstDayOfWeek + 1);}else {new RuntimeException("iOnClickDateListener == null");}}}}}break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:break;}return true;}

很简单,自行体会吧

代码已经提交git 和csdn,需要的自行下载,如果有什么问题,请一定要告诉我。

GitHub地址:https://github.com/SuperChandler/CustomCalendarView
csdn地址:http://download.csdn.net/detail/sinat_26710701/9853760

这篇关于自定义view---带标签的CalendarView的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/518043

相关文章

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)

1、MVC MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用: 1. Model(模型)

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d