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

主要步骤

  1. 编写布局
  2. 继承LinearLayout设置子控件
  3. 设置数据
  4. 继承TextView实现有圆圈背景的TextView
  5. 添加Attribute
  6. 添加长按事件

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

  1. 添加attrs文件

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <declare-styleable name="CalendarView">
    <attr name="dateFormat" format="string" />
    </declare-styleable>
    </resources>
  2. 将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();
    }
    }
  3. 在布局中加入命名控件引入

    <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.添加长按事件

  1. 定义长按接口

    public interface NewViewListener {
    void onItemLongPress(Date day);
    }
  2. 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的使用

    1. 定义attrs文件
    2. 注意命名空间。自定义View不能使用app:,而要使用xmlns:自定义一个命名空间
    3. TypedArray放入try{}finaly{}中,要在finally中释放TypedArray typedArray.recycle()
  • 通过继承布局实现自定义View时,加载布局

    需要LayoutInflater.from(context).inflate(R.layout.new_view, this);不能LayoutInflater.from(context).inflate(R.layout.new_view, this,false);

Android自定义日历控件(继承系统控件实现)的更多相关文章

  1. Android 自定义View 三板斧之一——继承现有控件

    通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文重点讨论继承现有 ...

  2. android 自定义日历控件

    日历控件View: /** * 日历控件 功能:获得点选的日期区间 * */ public class CalendarView extends View implements View.OnTouc ...

  3. Android调用相册拍照控件实现系统控件缩放切割图片

    android 下如果做处理图片的软件 可以调用系统的控件 实现缩放切割图片 非常好的效果 今天写了一个demo分享给大家 package cn.m15.test; import java.io.By ...

  4. Android自定义垂直滚动自动选择日期控件

    ------------------本博客如未明正声明转载,皆为原创,转载请注明出处!------------------ 项目中需要一个日期选择控件,该日期选择控件是垂直滚动,停止滚动时需要校正日期 ...

  5. 【读书笔记《Android游戏编程之从零开始》】8.Android 游戏开发常用的系统控件(系统控件常见问题)

    Android 中常用的计量单位Android有时候需要一些计量单位,比如在布局Layout文件中可能需要指定具体单位等.常用的计量单位有:px.dip(dp).sp,以及一些不常用的pt.in.mm ...

  6. Android 自定义日历

    好久没来写博客了,这半年多发生了好多的事情,废话不多说,今天在公司里比较闲在,写一篇最近写的公司用到的控件——日历控件. 控件的功能比较少,根据需求只有选择开始时间和结束时间并返回时间段. 效果图如下 ...

  7. Android自定义日历,可以点击、标注日期、节气、旧历等

    1. [图片] 9A59974C-47D4-47E3-8136-3F873EB9BBDC.jpg 2. [图片] left_arrow_pre.png 3. [图片] left_arrow.png 4 ...

  8. Android 一个日历控件的实现代码

    转载  2017-05-19   作者:Othershe   我要评论 本篇文章主要介绍了Android 一个日历控件的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看 ...

  9. PyQt5复杂控件(树控件、选项卡控件(滚动条控件、多文档控件、停靠控件)

    1.树控件的基本使用方法QTreeWidget'''QTreeWidget树控件的使用方法添加图标,添加表格,添加复选框等'''from PyQt5.QtWidgets import *from Py ...

随机推荐

  1. JS 蓝球弹起的高度 100 米 第几次高度小于1米

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. 路飞学城Python-Day150

    最近由于在忙别的事情,所以路飞的课程就往后延期了,感觉很难受,不过我还是依然坚持学下去,必须的 最近在忙的事情 1.进入了数据分析行业,需要学习更多的知识 2.开始对数据收集负责,写各种爬虫 3.对数 ...

  3. Day 14 匿名函数

    递归之二分法 def sc_func(num,lis): lis_len=int(len(lis)/2) binary_num=lis[lis_len] # print(binary_num) if ...

  4. 算法8-----Different Ways to Add Parentheses(不同括号结果)

    题目: Given a string of numbers and operators, return all possible results from computing all the diff ...

  5. IDEA热部署配置

    一.IDEA热加载的作用: 热加载的作用就是当你保存修改,新增,删除代码或者文件后,不需要重新启动项目,直接就能运行. 二.IDEA热记载的配置方法 1.配置pom文件,加载依赖 Maven. < ...

  6. 51nod-活动安排问题之二

    有若干个活动,第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,要把活动都安排完,至少需要几个教室? 分析:能否按照之一问题的解法,每个教室安排尽可能多的活动,即按结束时间排序,再贪心选择不 ...

  7. 处理问题:windows server 2016由于没有远程桌面授权服务器可以提供许可证,远程会话被中断。请跟服务器管理员联系

    windows server可以多用户同时登陆,默认最大远程登录数量为2,如果有更多人需要同时远程登录,则需要安装远程桌面授权服务,第一次安装后,免费期为120天,超过则无法正常远程登录. 解决办法如 ...

  8. Ubuntu启动流程

    网上很多Linux的启动流程图,也有Ubuntu早期版本的启动流程介绍,却少有近期版本的启动流程介绍(16.04).这里作出总结归纳. Linux系统采用的是RedHat启动方式,启动流程如下: Ub ...

  9. 【Educational Codeforces Round 48 (Rated for Div. 2) C】 Vasya And The Mushrooms

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 显然在没有一直往右走然后走到头再往上走一格再往左走到头之前. 肯定是一直在蛇形走位.. 这个蛇形走位的答案贡献可以预处理出来.很容易 ...

  10. Redis-Cluster集群原理

    一.redis-cluster 官方推荐的 redis 集群解决方案,优点在于去中心化, 去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态.每个 ...