上一篇 自定义完成一个日历(一)写了一个简单的日历。只是简单的展示了日历和标识出当天。今天把上个日历控件优化一下。
优化点:
(1)添加滑动功能,可根据滑动来切换月份
(2)增加点击事件和点击效果
(3)增加跳到今天
(4)增加按周切换的风格
效果图:
步骤:
(1)将切换增加滑动切换功能,思路简单只需将以前显示日历的recycleview使用viewpager包起来就好啦。使用viewpager切换视图。
有一个问题就是设置viewpager的无限滑动 ,设置无限滑动也很简单
(1)设置viewpager的adapter的getCount()返回整数的最大值Integer.MAX_VALUE
(2)然后准备一个size为3的ArrayList calendars; 每次加载viewpager的item通过RecyclerView recyclerView = calendars.get(position%calendars.size());加载
(3)最后将viewpager的当前item设置到中间mViewPager.setCurrentItem(Integer.MAX_VALUE / 2);这样就实现了无限循环
当然这是个伪无限循环因为基本不会有人能翻这么多下的看起来就跟无限循环一样了。
(2)添加点击事件就是给recycleview设置setOnItemClickListener啦,自定义一个接口搞定。
(3)跳到今天:因为我们的切换都是通过改变recycleview的数据来实现的。所以跳到今天就很简单了,吧mCalendar重新初始化一下就然后重新组装数据刷新控件就OK啦,这里注意mCalendar全局使用一个
(4)按周切换。数据切换都是通过改变recycleview的数据实现,那么我们只需把每次的数据只给7条就好了切换的时候也就按7天切换。
最终代码变成了:
package com.chs.mycalender;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* 作者:chs on 2017-06-20 09:59
* 邮箱:657083984@qq.com
*/
public class MyCalendar extends LinearLayout {
private TextView tv_last;
private TextView tv_current_date;
private TextView tv_next;
private ViewPager mViewPager;
public static Calendar mCalendar = Calendar.getInstance();//全局的mCalendar 改变的时候所有地方都改变
private Context mContext;
private List<Cell> cells = new ArrayList<>();
private ArrayList<RecyclerView> calendars;
private CalendarAdapter mCalendarAdapter;
private int currentPosition;//viewpager 当前的position
public static int styleType = 1;//1是月类型的 2是星期类型的
private OnCellClickListener mOnCellClickListener;
public void setOnCellClickListener(OnCellClickListener onCellClickListener) {
mOnCellClickListener = onCellClickListener;
}
interface OnCellClickListener{
void onCellClick(int position,Cell cell);
}
public MyCalendar(Context context) {
super(context);
init(context);
}
public MyCalendar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyCalendar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mContext = context;
initView(context);
initEvent();
renderView();
}
public void setType(int type) {
this.styleType = type;
if(type==1){
tv_last.setText("上个月");
tv_next.setText("下个月");
}else {
tv_last.setText("上星期");
tv_next.setText("下星期");
}
renderView();
if(calendars.get(currentPosition % calendars.size()) != null){
calendars.get(currentPosition % calendars.size()).getAdapter().notifyDataSetChanged();
}
}
public int getType() {
return styleType;
}
public void jumpToToday(){
mCalendar = Calendar.getInstance();
renderView();
if(calendars.get(currentPosition % calendars.size()) != null){
calendars.get(currentPosition % calendars.size()).getAdapter().notifyDataSetChanged();
}
}
private void initView(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.calendar_view,null);
tv_last = (TextView) view.findViewById(R.id.tv_last);
tv_current_date = (TextView) view.findViewById(R.id.tv_current_date);
tv_next = (TextView) view.findViewById(R.id.tv_next);
mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
mCalendarAdapter = new CalendarAdapter();
mViewPager.setAdapter(mCalendarAdapter);
mViewPager.setCurrentItem(Integer.MAX_VALUE / 2);
currentPosition = Integer.MAX_VALUE / 2;
mViewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
@Override
public void transformPage(View page, float position) {
position = (float) Math.sqrt(1 - Math.abs(position));
page.setAlpha(position);
}
});
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(position<currentPosition){//左滑
if(styleType==1){
mCalendar.add(Calendar.MONTH, -1);
}else {
mCalendar.add(Calendar.DAY_OF_MONTH, -7);
}
}else {//右滑
if(styleType==1){
mCalendar.add(Calendar.MONTH, 1);
}else {
mCalendar.add(Calendar.DAY_OF_MONTH, 7);
}
}
renderView();
currentPosition = position;
if(calendars.get(position % calendars.size()) != null){
calendars.get(position % calendars.size()).getAdapter().notifyDataSetChanged();
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
addView(view);
}
private void initEvent() {
tv_last.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mViewPager.setCurrentItem(currentPosition-1);
}
});
tv_next.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mViewPager.setCurrentItem(currentPosition+1);
}
});
}
//渲染recycleview
private void renderView() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM");
tv_current_date.setText(dateFormat.format(mCalendar.getTime()));
Calendar calendar = (Calendar) mCalendar.clone();
int maxCount;
if(styleType==1){
//月类型的一个日历最多6行7列
maxCount = 6*7;
//置为当月的第一天
calendar.set(Calendar.DAY_OF_MONTH,1);
}else {
//星期类型的就7个
maxCount = 7;
}
//前面几天 不属于这个月的天数
int previousDays = calendar.get(Calendar.DAY_OF_WEEK)-1;
calendar.add(Calendar.DAY_OF_MONTH,-previousDays);
cells.clear();
while (cells.size()<maxCount){
cells.add(new Cell(calendar.get(Calendar.DAY_OF_MONTH),calendar.get(Calendar.MONTH)+1,calendar.get(Calendar.YEAR)));
calendar.add(Calendar.DAY_OF_MONTH,1);
}
calendars = mCalendarAdapter.getCalendars();
}
private class CalendarAdapter extends PagerAdapter {
private ArrayList<RecyclerView> calendars = new ArrayList<>();
CalendarAdapter() {
calendars.clear();
//new 3个RecyclerView实现viewpager的无限循环
for (int i = 0; i < 3; i++) {
RecyclerView rv = new RecyclerView(mContext);
GridLayoutManager manager = new GridLayoutManager(mContext,7);
rv.setLayoutManager(manager);
rv.setHasFixedSize(true);
calendars.add(rv);
}
}
ArrayList<RecyclerView> getCalendars(){
return calendars;
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (container.getChildCount() == calendars.size()) {
container.removeView(calendars.get(position % 3));
}
RecyclerView recyclerView = calendars.get(position%calendars.size());
MyAdapter myAdapter = new MyAdapter(mContext, cells);
myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClicked(int position) {
if(mOnCellClickListener!=null){
mOnCellClickListener.onCellClick(position,cells.get(position));
}
}
});
recyclerView.setAdapter(myAdapter);
container.addView(recyclerView, 0);
return recyclerView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(container);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((View) object);
}
}
}
adapter抽出了
package com.chs.mycalender;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.Calendar;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
private List<Cell> mCells;
private Context mContext;
private OnItemClickListener mOnItemClickListener;
private Paint mPaint;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
interface OnItemClickListener {
void onItemClicked(int position);
}
MyAdapter(Context context, List<Cell> cells) {
mCells = cells;
mContext = context;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(ContextCompat.getColor(context,R.color.colorAccent));
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.calendar_content, parent, false);
return new MyHolder(view);
}
@Override
public void onBindViewHolder(final MyHolder holder, final int position) {
final Cell cell = mCells.get(position);
holder.tv_content.setText(String.valueOf(cell.getDay()));
if(cell.isClicked()){
holder.tv_content.setBackground(new BitmapDrawable(null,createBitmap()));
}else {
holder.tv_content.setBackgroundColor(ContextCompat.getColor(mContext,R.color.white));
}
Calendar calendar = Calendar.getInstance();
int currentDay = calendar.get(Calendar.DAY_OF_MONTH);
int currentMonth = calendar.get(Calendar.MONTH) + 1;
int currentYear = calendar.get(Calendar.YEAR);
int month = MyCalendar.mCalendar.get(Calendar.MONTH) + 1;
//月份不一样的变灰
if (MyCalendar.styleType == 1) {
if (cell.getMonth() != month) {
holder.tv_content.setTextColor(ContextCompat.getColor(mContext, R.color.gray));
} else {
holder.tv_content.setTextColor(ContextCompat.getColor(mContext, R.color.black));
}
} else {
holder.tv_content.setTextColor(ContextCompat.getColor(mContext, R.color.black));
}
//年月日都相等才是同一天圈红
if (currentDay == cell.getDay() && currentMonth == cell.getMonth() && currentYear == cell.getYear()) {
holder.tv_content.setDrawCircle(true);
if(cell.isClicked()){
holder.tv_content.setTextColor(ContextCompat.getColor(mContext, R.color.white));
}else {
holder.tv_content.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
}
}else {
holder.tv_content.setDrawCircle(false);
}
holder.tv_content.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i < mCells.size(); i++) {
mCells.get(i).setClicked(i==position);
}
notifyDataSetChanged();
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClicked(position);
}
}
});
}
@Override
public int getItemCount() {
return mCells.size();
}
static class MyHolder extends RecyclerView.ViewHolder {
private MyTextView tv_content;
public MyHolder(View itemView) {
super(itemView);
tv_content = (MyTextView) itemView.findViewById(R.id.tv_content);
}
}
private Bitmap createBitmap(){
int width = dip2px(mContext,30);
//创建一个画布,宽为width,高为height
Bitmap tmpBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
//创建一个工具,这个工具的操作,都是在这个画布上进行的
Canvas canvas = new Canvas(tmpBitmap);
canvas.translate(width/2,width/2);
canvas.drawCircle(0,0,width/2,mPaint);
return tmpBitmap;
}
public int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}