心血来潮想开发个小玩意练练手,于是就有了上面标题的创意,自己一直想用下郭霖大神的开源数据库项目LitePal,再加之想要每天进行推送,于是跟日历结合起来有了下面的构想,项目简单点,对于我这个菜鸟而言就不会半途而废
,希望能够顺利写完。打算用三个篇幅来写,分别是
1。自定义日历控件部分(一),
2。极光推送集成以及富媒体消息推送部分(二),
3。LitePal数据库集成部分(三)。
初步的构想大概类似这样的功能
下面就想从自定义日历开始。自定义日历的教程参考慕课网《自定义实现日历件》http://www.imooc.com/learn/775
先看下我做出来的效果
好了,开始撸代码,日历的实现不是纯自定义的View , 而是借助系统的控件组合而成的,贴出XML文件大家就一目了然了,这是日历组合布局文件canlendar_view.xml
<?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">
<!--头部布局-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<ImageView
android:id="@+id/pre_month_btn"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_media_previous" />
<TextView
android:id="@+id/cal_title_tv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="May 2017"
android:textSize="20sp" />
<ImageView
android:id="@+id/next_month_btn"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_media_next" />
</LinearLayout>
<LinearLayout
android:id="@+id/week_title_layout"
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期日"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期一"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期二"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期三"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期四"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期五"
android:textSize="16sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="星期六"
android:textSize="16sp" />
</LinearLayout>
<!--日历布局-->
<GridView
android:id="@+id/days_grid_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:numColumns="7" />
</LinearLayout>
还是比较简单的,一个头部LinearLayout和一个GridView组合就好了,主要看下实现类的写法,业务逻辑都在实现类中完成的。对应的业务实现类MyCalendarView.java
public class MyCalendarView extends LinearLayout{
private ImageView mPreBtn , mNextBtn ;
private TextView mCalendarTitle ;
private GridView mDaysGridView ;
public OnCalendarItemClickListener listener ;
public void setOnCalendarItemClickListener(OnCalendarItemClickListener listener) {
this.listener = listener;
}
private Calendar cruDate = Calendar.getInstance() ; // 全局日历
public MyCalendarView(Context context) {
this(context,null);
}
public MyCalendarView(Context context, AttributeSet attrs) {
this(context, attrs,0);
bindView(context);
}
public MyCalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
bindView(context);
}
private void bindView(Context context){
View v = LayoutInflater.from(context).inflate(R.layout.canlendar_view , this , true);
mPreBtn = (ImageView) v.findViewById(R.id.pre_month_btn);
mNextBtn = (ImageView) v.findViewById(R.id.next_month_btn);
mCalendarTitle = (TextView) v.findViewById(R.id.cal_title_tv);
mDaysGridView = (GridView) v.findViewById(R.id.days_grid_view);
renderCalendar();
// 前一月
mPreBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
cruDate.add(Calendar.MONTH , -1);
renderCalendar();
}
});
// 后一月
mNextBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
cruDate.add(Calendar.MONTH , 1);
renderCalendar();
}
});
}
/**
* 核心的逻辑业务处理部分
*/
private void renderCalendar(){
// 设置标题栏
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
mCalendarTitle.setText(sdf.format(cruDate.getTime()));
// 准备要显示的数据
ArrayList<Date> cells = new ArrayList<>();
Calendar calendar = (Calendar) cruDate.clone();
calendar.set(Calendar.DAY_OF_MONTH,1);
int preDays = calendar.get(Calendar.DAY_OF_WEEK ) - 1 ;
calendar.add(Calendar.DAY_OF_MONTH,-preDays);
int maxDays = 6 * 7 ; // 一个月最多需要6行显示完全,每行7天
while (cells.size() < maxDays){ // 填充数据
cells.add(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH,1);
}
// 为GridView设置适配器
mDaysGridView.setAdapter(new CalArrayAdapter(getContext(),cells));
// 设置单个日期点击的接口
mDaysGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(listener == null){
return;
}else{
listener.onCalendarItemClickListener((Date) parent.getItemAtPosition(position));
}
}
});
}
/**
* 日历显示数据的GridView的适配器
*/
private class CalArrayAdapter extends ArrayAdapter<Date>{
LayoutInflater inflater ;
public CalArrayAdapter(Context context, ArrayList<Date> days) {
super(context, R.layout.calendar_day_text , days);
inflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Date date = getItem(position);
if(convertView == null){
convertView = inflater.inflate(R.layout.calendar_day_text, parent, false);
}
int day = date.getDate();
((TodayTextView)convertView).setText(String.valueOf(day));
Date now = new Date();
// 当月
if(date.getMonth() == now.getMonth()){
((TodayTextView)convertView).setTextColor(Color.BLACK);
}else{
((TodayTextView)convertView).setTextColor(Color.GRAY);
}
// 当天
if(date.getYear() == now.getYear()
&& date.getMonth() == now.getMonth()
&& date.getDate() == now.getDate()){
((TodayTextView)convertView).setTextColor(Color.RED); // 当天标红
((TodayTextView)convertView).isToday = true;
}
return convertView;
}
}
/**
* 自定义日历单个日期点击的接口
*/
public interface OnCalendarItemClickListener{
// 传入选中的日期
void onCalendarItemClickListener(Date day);
}
}
多的我就不再啰嗦了,代码中的注释还是比较多的,如果有什么不清楚的,完全可以拷贝然后试着运行下,相信你能更加理解我说的意思了,上述代码中有一个自定义的
TodayTextView.java
public class TodayTextView extends TextView {
private Paint mPaint = new Paint();
public boolean isToday = false ; // 确认是否是当天
public TodayTextView(Context context) {
super(context);
}
public TodayTextView(Context context, AttributeSet attrs) {
this(context, attrs , 0);
}
public TodayTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 设置画笔
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(3);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(getWidth()/2 , getHeight()/2); // 移动到中心位置
if(isToday){
canvas.drawCircle(0 , 0 , getWidth()/2 - 3 ,mPaint); // 画圈
}
}
}
这个自定义的View主要用来显示区分当天,这里做的主要工作就是把当前天用红色圆圈圈出来,当然你也可以做更多的事情,比如把某个选中的View换个颜色显示。
还有多一个布局文件,就是上面Adapter中渲染的一个Layout布局文件calendar_day_text.xml
<?xml version="1.0" encoding="utf-8"?>
<com.cjt.customcalendar.view.TodayTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cal_day_txt_tv"
android:layout_width="36dp"
android:layout_height="36dp"
android:gravity="center"
android:textSize="20sp">
</com.cjt.customcalendar.view.TodayTextView>
简单的引用了自定义的布局文件。MianActivity 和对应的activity_main.xml任然灰常简单
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.cjt.customcalendar.MainActivity">
<com.cjt.customcalendar.view.MyCalendarView
android:id="@+id/MyCalendarView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
public class MainActivity extends AppCompatActivity
implements MyCalendarView.OnCalendarItemClickListener {
private MyCalendarView mCalendarView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCalendarView = (MyCalendarView) this.findViewById(R.id.MyCalendarView);
mCalendarView.setOnCalendarItemClickListener(this);
}
@Override
public void onCalendarItemClickListener(Date day) {
Toast.makeText(this,"Date---"+day.toString(),Toast.LENGTH_SHORT).show();
}
}
注意:MainActivity实现了自定义View中的那个接口,所以才能弹出效果图中的Toast提示,当然,你也可以直接使用GridView.setOnclickListener来实现。
第一部分的效果:完成了自定义日历控件,能够响应日历的点击事件,为后面的数据查询做准备,第一部分就到此为止。