Android自定义日历控件(继承系统控件实现)
Android自定义日历控件(继承系统控件实现)

主要步骤
- 编写布局
- 继承LinearLayout设置子控件
- 设置数据
- 继承TextView实现有圆圈背景的TextView
- 添加Attribute
- 添加长按事件
1.编写布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="30dp">
<ImageView
android:id="@+id/btn_pre"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/btn_next"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/txtData"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/app_name" />
</RelativeLayout>
<LinearLayout
android:id="@+id/week_header"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="1" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="2" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="3" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="4" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="5" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="6" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="7" />
</LinearLayout>
<GridView
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="7" />
</LinearLayout>
2.继承LinearLayout设置子控件
public class CalendarView extends LinearLayout {
private ImageView btnPre;
private ImageView btnNext;
private TextView txtData;
private GridView gridView;
private Calendar calendar = Calendar.getInstance();
private String displayFormat;
public NewViewListener viewListener;
public void setViewListener(NewViewListener viewListener) {
this.viewListener = viewListener;
}
public CalendarView(Context context) {
super(context);
}
public CalendarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initControl(context, attrs);
}
public CalendarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initControl(context, attrs);
}
private void initControl(Context context, AttributeSet attributeSet) {
bindControl(context);
bindControlEvent();
setAttribute(attributeSet);
renderCalender();
}
private void bindControl(Context context) {
LayoutInflater.from(context).inflate(R.layout.new_view, this);
btnNext = (ImageView) findViewById(R.id.btn_next);
btnPre = (ImageView) findViewById(R.id.btn_pre);
txtData = (TextView) findViewById(R.id.txtData);
gridView = (GridView) findViewById(R.id.grid);
}
private void bindControlEvent() {
btnNext.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
calendar.add(Calendar.MONTH, +1);
renderCalender();
}
});
btnPre.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
calendar.add(Calendar.MONTH, -1);
renderCalender();
}
});
}
}
3.设置数据
private void renderCalender() {
//返回"月+日"格式的数据
SimpleDateFormat sdf = new SimpleDateFormat(displayFormat, Locale.CHINA);
txtData.setText(sdf.format(calendar.getTime()));
ArrayList<Date> cells = new ArrayList<>();
Calendar calendar2 = (Calendar) this.calendar.clone();
//设置月的第一天为1
calendar2.set(Calendar.DAY_OF_MONTH, 1);
//获取当前周数的前一天
int prevDays = calendar2.get(Calendar.DAY_OF_WEEK) - 1;
//运算日历加上加前一周
calendar2.add(Calendar.DAY_OF_MONTH, -prevDays);
int maxCellCount = 6 * 7;
//将日历里的日期数据添加到ArrayList
while (cells.size() < maxCellCount) {
cells.add(calendar2.getTime());
calendar2.add(Calendar.DAY_OF_MONTH, 1);
}
gridView.setAdapter(new MyAdapter(getContext(), cells));
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (viewListener == null) {
return false;
} else {
viewListener.onItemLongPress((Date) parent.getItemAtPosition(position));
return true;
}
}
});
}
private class MyAdapter extends ArrayAdapter<Date> {
LayoutInflater layoutInflater;
MyAdapter(@NonNull Context context, ArrayList<Date> dates) {
super(context, R.layout.calendar_text_day, dates);
layoutInflater = LayoutInflater.from(context);
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Date date = getItem(position);
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.calendar_text_day, parent, false);
}
int day = date.getDate();
((CalendarTextView) convertView).setText(String.valueOf(day));
Date now = new Date();
boolean isSameMonth = false;
if (date.getMonth() == now.getMonth()) {
isSameMonth = true;
}
if (isSameMonth) {
((CalendarTextView) convertView).setTextColor(Color.DKGRAY);
}
if (now.getDate() == date.getDate() && now.getMonth() == date.getMonth() && now.getYear() == date.getYear()) {
((CalendarTextView) convertView).setNow(true);
}
return convertView;
}
}
4. 圆圈背景TextView
public class CalendarTextView extends AppCompatTextView {
private Paint paint;
private boolean isNow = false;
public void setNow(boolean now) {
isNow = now;
}
public CalendarTextView(Context context) {
super(context);
}
public CalendarTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initControl();
}
public CalendarTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initControl();
}
private void initControl() {
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isNow) {
canvas.translate(getWidth() / 2, getHeight() / 2);
canvas.drawCircle(0, 0, getWidth() / 2, paint);
setTextColor(Color.RED);
}
}
}
5.添加Attribute
添加attrs文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CalendarView">
<attr name="dateFormat" format="string" />
</declare-styleable>
</resources>
将Arrtibute参数设置到控件
private void setAttribute(AttributeSet attributeSet) {
TypedArray ta = getContext().obtainStyledAttributes(attributeSet, R.styleable.CalendarView);
try {
displayFormat = ta.getString(R.styleable.CalendarView_dateFormat);
if (displayFormat == null) {
displayFormat = "MMM yyy";
}
} finally {
ta.recycle();
}
}
在布局中加入命名控件引入
<com.example.jiyang.newview.CalendarView xmlns:CalendarView="http://schemas.android.com/apk/res/com.example.jiyang.newview"
android:id="@+id/newView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
CalendarView:dateFormat="MMMM yyyy" />
6.添加长按事件
定义长按接口
public interface NewViewListener {
void onItemLongPress(Date day);
}
CalenderView中调用
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (viewListener == null) {
return false;
} else {
viewListener.onItemLongPress((Date) parent.getItemAtPosition(position));
return true;
}
}
});
3. Activity中实现接口方法
@Override
public void onItemLongPress(Date day) {
DateFormat df = SimpleDateFormat.getDateInstance();
Toast.makeText(this, df.format(day), Toast.LENGTH_SHORT).show();
}
```
总结
Attribute的使用
- 定义attrs文件
- 注意命名空间。自定义View不能使用
app:,而要使用xmlns:自定义一个命名空间 - TypedArray放入
try{}finaly{}中,要在finally中释放TypedArraytypedArray.recycle()
通过继承布局实现自定义View时,加载布局
需要LayoutInflater.from(context).inflate(R.layout.new_view, this);不能LayoutInflater.from(context).inflate(R.layout.new_view, this,false);
Android自定义日历控件(继承系统控件实现)的更多相关文章
- Android 自定义View 三板斧之一——继承现有控件
通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文重点讨论继承现有 ...
- android 自定义日历控件
日历控件View: /** * 日历控件 功能:获得点选的日期区间 * */ public class CalendarView extends View implements View.OnTouc ...
- Android调用相册拍照控件实现系统控件缩放切割图片
android 下如果做处理图片的软件 可以调用系统的控件 实现缩放切割图片 非常好的效果 今天写了一个demo分享给大家 package cn.m15.test; import java.io.By ...
- Android自定义垂直滚动自动选择日期控件
------------------本博客如未明正声明转载,皆为原创,转载请注明出处!------------------ 项目中需要一个日期选择控件,该日期选择控件是垂直滚动,停止滚动时需要校正日期 ...
- 【读书笔记《Android游戏编程之从零开始》】8.Android 游戏开发常用的系统控件(系统控件常见问题)
Android 中常用的计量单位Android有时候需要一些计量单位,比如在布局Layout文件中可能需要指定具体单位等.常用的计量单位有:px.dip(dp).sp,以及一些不常用的pt.in.mm ...
- Android 自定义日历
好久没来写博客了,这半年多发生了好多的事情,废话不多说,今天在公司里比较闲在,写一篇最近写的公司用到的控件——日历控件. 控件的功能比较少,根据需求只有选择开始时间和结束时间并返回时间段. 效果图如下 ...
- Android自定义日历,可以点击、标注日期、节气、旧历等
1. [图片] 9A59974C-47D4-47E3-8136-3F873EB9BBDC.jpg 2. [图片] left_arrow_pre.png 3. [图片] left_arrow.png 4 ...
- Android 一个日历控件的实现代码
转载 2017-05-19 作者:Othershe 我要评论 本篇文章主要介绍了Android 一个日历控件的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看 ...
- PyQt5复杂控件(树控件、选项卡控件(滚动条控件、多文档控件、停靠控件)
1.树控件的基本使用方法QTreeWidget'''QTreeWidget树控件的使用方法添加图标,添加表格,添加复选框等'''from PyQt5.QtWidgets import *from Py ...
随机推荐
- Ubuntu安装配置Python.pyDev
一:安装ECLipse Eclipse官网下载软件tar包: 使用解压命令: sudo tar xzvf xxxxx.tar.gz -c /opt/ 创建快捷方式到桌面. 二:安装python-Num ...
- 关于XML学习
XML为知识构架存储语言: http://www.w3school.com.cn/xml/xml_tree.asp 语义网:为计算机构建一个系统的概念网络模型是计算机理解概念和机间信息交流的途径:XM ...
- Python Django中QQ邮箱授权码问题
Python Django中QQ邮箱授权码问题 系统及软件版本如下: Ubuntu Kylin 16.04 Python 3.5.1 Django 1.9.7 PyCharm Community Ed ...
- 创建一个dynamics CRM workflow (一) - Introduction to Custom Workflows
Workflow: Use this process to model and automate real world business processes. These processes can ...
- Flex简易教程
常见的前端布局模型涵盖浮动.定位和弹性盒等 CSS 技术,其中浮动和定位技术往往在制作自适应布局页面时显得不够优雅--对于浮动布局,前后端分离时代很多时候我们并不知道每行会遍历显示多少个元素,每个 ...
- 分类IP地址
分类IP地址是将IP地址划分为若干个固定类. IP地址由网络标识字段(netID)和主机标识字段(hostID)组成.IP地址可以标识为: IP地址:: = { <网络标识>,<主机 ...
- 【SPOJ 104】HIGH - Highways (高斯消元)
题目描述 In some countries building highways takes a lot of time- Maybe that's because there are many po ...
- 2019-04-03 SQL Group By某列,预先对该列进行一个预处理,提炼出共有的信息,即关键字case when 列名什么条件 then 赋值 else 赋值 end as 新列名
select sum(发行金额) from( select PoolNameFormat,count(cast(ItemValue as decimal(19,4))) as 发行笔数,sum(cas ...
- 前端框架Bootstrap简单介绍
下载: 解压之后: 把这些文件拷贝到项目中 页面使用时 只需要引入: 然后我们就可以参考官网来设计需要的前端页面了 设计一个按钮:button 只需要标明css样式中使用的类 下面就是现实效果:
- MyBatis中动态SQL元素的使用
掌握MyBatis中动态SQL元素的使用 if choose(when,otherwise) trim where set foreach <SQL>和<include> 在应 ...