安卓中的日历控件源码_日历软件源

hacker|
103

文章目录:

Android开源日历,materialcalendarview的选中背景如何缩小

因为项目需要,上github找了不少日历控件,最终敲定了MaterialCalendarView。

首先昵,要说下开源控件使用的好处,我感觉大致有以下几个方面:

1).网上有现成的为啥不去用,你觉得你自己写的比别人牛逼吗?

2).涉及年月日日期处理,滚动事件,相互交错,没有紧密的逻辑思维去构架,肯定漏洞百出,想想数不尽的bug,不寒而栗。

3).最关键的是,我懒,我懒,我懒!自己写费时费力,牛逼的日历组件都可以做一个app了,再说我只是想要一个选择日期功能。

说了一堆废话,现在我们来分析源码了。。。。。

老外写的东西层次感还是很分明的,我大致给它分为三个部分:日期的格式化,自定义的span效果,以及日历控件的实现。不用说日历实现是最重要的一部分了,我们由简入繁,从日期分析开始。

1)format,顾名思义,格式化,达到我们想要的日期展示样式。

format包中有八个java文件,其中有三个接口,五个实现类。

三个接口:

DayFormatter 通过自定义的CalendarDay对象,得到一个日期的字符串标签。其实现类是DateFormatDayFormatter。

TitleFormatter 通过自定义的CalendarDay对象,得到一个包含年月的字符串标签,作为MaterialCalendarView的标签。其实现类为DateFormatTitleFormatter和MonthArrayTitleFormatter。

WeekDayFormatter 将一个日期中Calendar.DAY_OF_YEAR对应的值转换成一个字符串标签。其实现类是ArrayWeekDayFormatter。

这三个接口都只有一个方法,有的提供了一个公有的默认实现类。其功能就是将日期的数值转换成本地化的可读字符串。在这里我可以想到的是,因为使用了接口,我们可以很灵活的替换其实现类,而不用更改日历控件中的代码,实现定制化的需求。

2)span

spans包中只有一个类DotSpan,实现了在文字下方画一个小圆点的效果。这是一个示例,我们可以模仿它来实现自己想要的效果。比如,如果想在日期的下方用一行小字显示,用span是很方便的一种实现方式。

3)MaterialCalendarView

这个包中有16个Java文件,是此开源控件主要的代码所在。其中,组合成最终控件的四个最重要的类是DayView,WeekDayView,MonthView和MaterialCalendarView。

DayView 继承自CheckedTextView。之所以用CheckedTextView而不是TextView,是为了使用android.R.attr.state_checked状态,在日期被选中时显示不同的背景图片。

WeekDayView 继承自TextView,用于在日历的第一排显示星期的标签。

MonthView 继承自ViewGroup,它包含7个WeekDayView和42个DayView,即一个7*7的矩形,其中每一个矩形称为一个tile。

MaterialCalendarView 继承自ViewGroup,包含上方的title和下方的ViewPager。这个控件的宽度如果不能被7整除,那么它会自动缩小其内容,并居中。

老外实现MaterialCalendarView层次感非常强烈,注释清楚,本人愚钝啊,时刻不丢粗心的毛病,改造日历期间很多功能点找不到,修改日历的disable事件,点击效果,日历字体大小。。。。。等等。好了,废话不多说,先来一份改造好的日历图,压压惊!左边是我改造的,右边是我们伟大开源作者的。(提倡开源,一直很欣赏这些懂的分享的人,只有弱者才会害怕自己的东西被人拿去)

左边的日历我针对自己项目进行了定制设计,调节了日历大小,之前的dayview是宽高等比大小,宽度是平分屏幕,所以这样导致高度很高,相互之间间隔比较大,我通过monthview的onMeasure方法,将高度修改为

int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(

(int)(measureTileSize*0.65),

MeasureSpec.EXACTLY

);

这样长宽就3/2了,这个时候只是第一步,仅仅只有monthview大小变了,整体的view大小还没有变,所以我们还要处理下MaterialCalendarView的onMeasure 方法,对整体高度进行修改

日历安卓源代码导入android studio

Eclipse迁移到Android studio步骤如下:

一、从Eclipse中导出:

1、将ADT插件版本升级到22.0以上。

2、在Eclipse中,选择File--Export。

3、在弹出的导出窗口中,打开Android的文件夹,选择“Generate Gradle Build Files”。

4、选中想要导入到Android Studio中的项目,Finish。

注意:导出的项目将会和原来的项目在同一目录,覆盖原来的同时,会新增一个叫build.gradle的文件,导入Android Studio时将首先读取这个文件。

二、导入到Android Studio:

1、在Android Studio 中,首先关掉当前的打开的项目。

2、在欢迎界面,点击Import Project(注:也是可以直接在菜单选择Import project的)。

3、选中Eclipse中导出的项目,展开目录,点击build.gradle文件,然后OK。

4、在之后的弹出对话框中,会要求选择Gradle的配置,选中Use gradle wrapper.(注:也可以自定义本机装的Gradle)。

注意:如果没有Grade build文件,也是可以将普通的安卓项目导入到Android Studio中,它会用现有的Ant build.但为了更好地使用之后的功能和充分使用构建变量,还是强烈地建议先从ADT插件中生成Gradle文件再导入Android Studio。

安卓日历整体布局是怎么实现的

自定义日历控件,支持旧历、节气、日期标注、点击操作 (参考网络上的日历控件改写)

注:将下面的四张资源图片拷贝到所建包的下一个image目录中,如Calendar.java 所在包为

cc.util.android.view,则需要再创建一个包cc.util.android.view.image 然后将图片拷贝进去

/****************从此出开始将代码拷贝到一个文件中*******************/

package cc.util.android.view;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Calendar;

import java.util.Date;

import java.util.List;

import java.util.Locale;

import android.annotation.SuppressLint;

import android.content.Context;

import android.graphics.BitmapFactory;

import android.graphics.Color;

import android.graphics.drawable.BitmapDrawable;

import android.graphics.drawable.Drawable;

import android.graphics.drawable.StateListDrawable;

import android.text.TextUtils.TruncateAt;

import android.util.AttributeSet;

import android.view.GestureDetector;

import android.view.GestureDetector.OnGestureListener;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.View.OnTouchListener;

import android.view.animation.Animation;

import android.view.animation.Animation.AnimationListener;

import android.view.animation.TranslateAnimation;

import android.widget.BaseAdapter;

import android.widget.GridView;

import android.widget.ImageButton;

import android.widget.LinearLayout;

import android.widget.RelativeLayout;

import android.widget.TextView;

import android.widget.ViewFlipper;

import android.widget.AbsListView.LayoutParams;

/**

* 日历控件,支持旧历、节气、日期标注、点击操作 (参考网络上的日历控件改写)

*

* @author wangcccong

* @version 1.406 create at: Mon, 03 Sep. 2014

* brupdate at: Mon, 23 Sep. 2014

* 新增日期标注和点击操作

*/

public class CalendarView extends LinearLayout implements OnTouchListener,

AnimationListener, OnGestureListener {

/**

* 点击日历

*/

public interface OnCalendarViewListener {

void onCalendarItemClick(CalendarView view, Date date);

}

/** 顶部控件所占高度 */

private final static int TOP_HEIGHT = 40;

/** 日历item中默认id从0xff0000开始 */

private final static int DEFAULT_ID = 0xff0000;

// 判断手势用

private static final int SWIPE_MIN_DISTANCE = 120;

private static final int SWIPE_MAX_OFF_PATH = 250;

private static final int SWIPE_THRESHOLD_VELOCITY = 200;

// 屏幕宽度和高度

private int screenWidth;

// 动画

private Animation slideLeftIn;

private Animation slideLeftOut;

private Animation slideRightIn;

private Animation slideRightOut;

private ViewFlipper viewFlipper;

private GestureDetector mGesture = null;

/** 上一月 */

private GridView gView1;

/** 当月 */

private GridView gView2;

/** 下一月 */

private GridView gView3;

boolean bIsSelection = false;// 是否是选择事件发生

private Calendar calStartDate = Calendar.getInstance();// 当前显示的日历

private Calendar calSelected = Calendar.getInstance(); // 选择的日历

private CalendarGridViewAdapter gAdapter;

private CalendarGridViewAdapter gAdapter1;

private CalendarGridViewAdapter gAdapter3;

private LinearLayout mMainLayout;

private TextView mTitle; // 显示年月

private int iMonthViewCurrentMonth = 0; // 当前视图月

private int iMonthViewCurrentYear = 0; // 当前视图年

private static final int caltitleLayoutID = 66; // title布局ID

private static final int calLayoutID = 55; // 日历布局ID

private Context mContext;

/** 标注日期 */

private final ListDate markDates;

private OnCalendarViewListener mListener;

public CalendarView(Context context) {

this(context, null);

}

public CalendarView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

mContext = context;

markDates = new ArrayListDate();

init();

}

// 初始化相关工作

protected void init() {

// 得到屏幕的宽度

screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;

// 滑动的动画

slideLeftIn = new TranslateAnimation(screenWidth, 0, 0, 0);

slideLeftIn.setDuration(400);

slideLeftIn.setAnimationListener(this);

slideLeftOut = new TranslateAnimation(0, -screenWidth, 0, 0);

slideLeftOut.setDuration(400);

slideLeftOut.setAnimationListener(this);

slideRightIn = new TranslateAnimation

android日历控件

1.DatePicker

在Android中,DatePicker用来实现日期输入设置,日期的设置范围为1900年1月1日至2100年12月31日。

1.1常用xml属性

DatePicker的常用xml属性如图1所示:

图1 DatePicker常用xml属性

其中,android:calendarViewShown[boolean]用于设置是否显示calendar view;android:endYear[int]用于设置截至日期;android:maxDate[int]用于设置最大的日期;android:minDate[int]用于设置最小的日期;android:spinnersShown[boolean]用于设置是否显示spinners;android:startYear[int]用于设置起始日期。

1.2常用方法

DatePicker的常用方法有以下一些:

(1)public CalendarView getCalendarView(); //获取CalendarView

(2)public boolean getCalendarViewShown();   //获取CalendarView是否显示

(3)public int getDayOfMonth(); //获取当前日期的日

(4)public long getMaxDate(); //获取最大日期

(5)public long getMinDate(); //获取最小日期

(6)public int getMonth();   //获取当前日期的月

(7)public boolean getSpinnersShown(); //获取Spinners是否显示

(8)public int getYear(); //获取当前日期的年

(9)public void init(int year,int monthOfYear,int dayOfMonth,

DatePicker.OnDateChangedListener onDateChangedListener); //初始化日期

(10)public void setCalendarViewShown(boolean shown);//设置是否显示CalendarView

(11)public void setMaxDate(long maxDate); //设置最大日期

(12)public void setMinDate(long minDate); //设置最小日期

(13)public void setSpinnersShown(boolean shown); //设置是否显示Spinners

(14)public void updateDate(int year,int month,int dayOfMonth);   //更新当前日期

2.TimePicker

在Android中,TimePicker用来实现时间输入设置,可以选择12或24小时模式。TimePicker的常用方法有以下一些:

(1)public Integer getCurrentHour(); //获取当前时间的小时

(2)public Integer getCurrentMinute(); //获取当前时间的分钟

(3)public boolean is24HourView(); //获取是否为24小时模式

(4)public void setCurrentHour(Integer currentHour); //设置当前时间的小时

(5)public void setCurrentMinute(Integer currentMinute); //设置当前时间的分钟

(6)public void setIs24HourView(Boolean is24HourView); //设置24小时模式

3.DatePickerDialog

在Android中,DatePickerDialog用来显示日期对话框。DatePickerDialog的常用方法有以下一些:

(1)public DatePicker getDatePicker(); //获取DatePicker中的日期值

(2)public void onClick(DialogInterface dialog,int which); //响应对话框中的点击事件

(3)public void onDateChanged(DatePicker view,int year,int month,int day); //响应日期改变事件

(4)public void updateDate(int year,int monthOfYear,int dayOfMonth); //更新当前日期

4.TimePickerDialog

在Android中,TimePickerDialog用来显示时间对话框。TimePickerDialog的常用方法有以下一些:

(1)public void onClick(DialogInterface dialog,int which); //响应对话框中的点击事件

(2)public void onTimeChanged(TimePicker view,int hourOfDay,int minute); //响应时间改变事件

(3)public void updateTime(int hourOfDay,int minuteOfHour); //更新当前时间

5.AnalogClock

在Android中,AnalogClock用于显示指针式时钟,该时钟仅有时钟和分钟两个指针。

6.DigitalClock

在Android中,DigitalClock用来显示数字式时钟,显示格式为HH:MM:SS AM/PM。

android studio 日历控件怎么简单些

每个安卓系统自带的日历都不尽相同,而且有些日历为了节省内存过于精简,是没有这种功能的。如果可以做到的一般会有个新建的按钮,新建日程提醒。在更多按钮可以设置提醒的方式。首先你要自定义一个控件,一般采用继承原有控件的方式,然后在布局文件使用你要用的自定义控件,需要包含包名,再就是在activity中写控件的控制代码。可以看看安卓巴士教程:

java swing 日历控件怎么实现 最好是源码

源代码:

//DatePicker.java

package com.kxsoft.component;

import java.awt.*;

import java.awt.event.*;

import java.util.GregorianCalendar;

import java.util.Date;

import java.util.Calendar;

import java.text.DateFormat;

import java.text.FieldPosition;

import javax.swing.*;

import javax.swing.plaf.BorderUIResource;

public final class DatePicker extends JPanel {

private static final long serialVersionUID = 1L;

private static final int startX = 10;

private static final int startY = 60;

private static final Font smallFont = new Font("Dialog", Font.PLAIN, 10);

private static final Font largeFont = new Font("Dialog", Font.PLAIN, 12);

private static final Insets insets = new Insets(2, 2, 2, 2);

private static final Color highlight = new Color(255, 255, 204);

private static final Color white = new Color(255, 255, 255);

private static final Color gray = new Color(204, 204, 204);

private Component selectedDay = null;

private GregorianCalendar selectedDate = null;

private GregorianCalendar originalDate = null;

private boolean hideOnSelect = true;

private final JButton backButton = new JButton();

private final JLabel monthAndYear = new JLabel();

private final JButton forwardButton = new JButton();

private final JLabel[] dayHeadings = new JLabel[]{

new JLabel("日"),

new JLabel("一"),

new JLabel("二"),

new JLabel("三"),

new JLabel("四"),

new JLabel("五"),

new JLabel("六")};

private final JLabel[][] daysInMonth = new JLabel[][]{

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()},

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()},

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()},

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()},

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()},

{new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel(),

new JLabel()}

};

private final JButton todayButton = new JButton();

private final JButton cancelButton = new JButton();

public DatePicker() {

super();

selectedDate = getToday();

init();

}

public DatePicker(final Date initialDate) {

super();

if (null == initialDate)

selectedDate = getToday();

else

(selectedDate = new GregorianCalendar()).setTime(initialDate);

originalDate = new GregorianCalendar(

selectedDate.get(Calendar.YEAR),

selectedDate.get(Calendar.MONTH),

selectedDate.get(Calendar.DATE));

init();

}

public boolean isHideOnSelect() {

return hideOnSelect;

}

public void setHideOnSelect(final boolean hideOnSelect) {

if (this.hideOnSelect != hideOnSelect) {

this.hideOnSelect = hideOnSelect;

initButtons(false);

}

}

public Date getDate() {

if (null != selectedDate)

return selectedDate.getTime();

return null;

}

private void init() {

setLayout(new AbsoluteLayout());

this.setMinimumSize(new Dimension(161, 226));

this.setMaximumSize(getMinimumSize());

this.setPreferredSize(getMinimumSize());

this.setBorder(new BorderUIResource.EtchedBorderUIResource());

backButton.setFont(smallFont);

backButton.setText("");

backButton.setMargin(insets);

backButton.setDefaultCapable(false);

backButton.addActionListener(new ActionListener() {

public void actionPerformed(final ActionEvent evt) {

onBackClicked(evt);

}

});

add(backButton, new AbsoluteConstraints(10, 10, 20, 20));

monthAndYear.setFont(largeFont);

monthAndYear.setHorizontalAlignment(JTextField.CENTER);

monthAndYear.setText(formatDateText(selectedDate.getTime()));

add(monthAndYear, new AbsoluteConstraints(30, 10, 100, 20));

forwardButton.setFont(smallFont);

forwardButton.setText("");

forwardButton.setMargin(insets);

forwardButton.setDefaultCapable(false);

forwardButton.addActionListener(new ActionListener() {

public void actionPerformed(final ActionEvent evt) {

onForwardClicked(evt);

}

});

add(forwardButton, new AbsoluteConstraints(130, 10, 20, 20));

int x = startX;

for (int ii = 0; ii  dayHeadings.length; ii++) {

dayHeadings[ii].setOpaque(true);

dayHeadings[ii].setBackground(Color.LIGHT_GRAY);

dayHeadings[ii].setForeground(Color.WHITE);

dayHeadings[ii].setHorizontalAlignment(JLabel.CENTER);

add(dayHeadings[ii], new AbsoluteConstraints(x, 40, 21, 21));

x += 20;

}

x = startX;

int y = startY;

for (int ii = 0; ii  daysInMonth.length; ii++) {

for (int jj = 0; jj  daysInMonth[ii].length; jj++) {

daysInMonth[ii][jj].setOpaque(true);

daysInMonth[ii][jj].setBackground(white);

daysInMonth[ii][jj].setFont(smallFont);

daysInMonth[ii][jj].setHorizontalAlignment(JLabel.CENTER);

daysInMonth[ii][jj].setText("");

daysInMonth[ii][jj].addMouseListener(new MouseAdapter() {

public void mouseClicked(final MouseEvent evt) {

onDayClicked(evt);

}

});

add(daysInMonth[ii][jj], new AbsoluteConstraints(x, y, 21, 21));

x += 20;

}

x = startX;

y += 20;

}

initButtons(true);

calculateCalendar();

}

private void initButtons(final boolean firstTime) {

if (firstTime) {

final Dimension buttonSize = new Dimension(68, 24);

todayButton.setText("今天");

todayButton.setMargin(insets);

todayButton.setMaximumSize(buttonSize);

todayButton.setMinimumSize(buttonSize);

todayButton.setPreferredSize(buttonSize);

todayButton.setDefaultCapable(true);

todayButton.setSelected(true);

todayButton.addActionListener(new ActionListener() {

public void actionPerformed(final ActionEvent evt) {

onToday(evt);

}

});

cancelButton.setText("取消");

cancelButton.setMargin(insets);

cancelButton.setMaximumSize(buttonSize);

cancelButton.setMinimumSize(buttonSize);

cancelButton.setPreferredSize(buttonSize);

cancelButton.addActionListener(new ActionListener() {

public void actionPerformed(final ActionEvent evt) {

onCancel(evt);

}

});

} else {

this.remove(todayButton);

this.remove(cancelButton);

}

4条大神的评论

  • avatar
    访客 2022-07-08 下午 02:16:50

    l()}};private final JButton todayButton = new JButton();private final JButton cancelButton = new JButton();public DatePicker() {super();selectedDate =

  • avatar
    访客 2022-07-08 下午 06:45:38

    private static final int SWIPE_MIN_DISTANCE = 120; private static final int SWIPE_MAX_OFF_

  • avatar
    访客 2022-07-08 下午 02:49:19

    本机装的Gradle)。注意:如果没有Grade build文件,也是可以将普通的安卓项目导入到Android Studio中,它会用现有的Ant build.但为了更好地使用之后的功能和充分使用构建变量,还是强烈地建议先从ADT插件中生成Gr

  • avatar
    访客 2022-07-08 下午 05:29:17

    ndarView的标签。其实现类为DateFormatTitleFormatter和MonthArrayTitleFormatter。WeekDayFormatter 将一个日期中Calendar.DAY_OF_YEAR对应的值转换成一个字符串标签。其实现类是ArrayWeekDayFormat

发表评论