横向滑动的日历控件的实现

来源:互联网 发布:微信企业宣传软件 编辑:程序博客网 时间:2024/05/21 14:03

横向滑动的日历控件实现
实现横向滑动的日历控件可以作为签到的日历控件

看见MaterialCalendarView 仿照它大致的思路自己实现一个CanlendarView,
给一个ClaendarPagerView extends viewgroup添加四十二个TextView,用来显示一个月的天数,
然后在ViewPagerAdapter 中填充CalendarPagerView,给viewPager填充adpater,就可以实现横向滑动的日历控件了。其中比较麻烦的就是日期的处理,还有一些小的细节.

首先实现单独天数的控件继承CheckedTextView
public class DayView extends CheckedTextView {
//这一天的日期类
private CalendarDay day;

//构造函数给个Visible参数 决定日期是否可见public DayView(Context context,Calendar day,int visible) {    super(context);    setGravity(Gravity.CENTER);    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){        setTextAlignment(TEXT_ALIGNMENT_CENTER);    }    this.day = CalendarDay.from(day);    setVisibility(visible);    setText(CalendarUtils.getDay(day)+"");}//返回这个日期是几号public String getLabel(){    return CalendarUtils.getDay(day.getCalendar())+"";}//返回真实日期 Calendar类的月份是从0开始的public CalendarDay getDate(){    CalendarDay tempDay = CalendarDay.from(day.getYear(),day.getMonth()+1,day.getDay());    return tempDay;}//返回CalendarDay对象 CalendarDay类是对Calendar的封装类public  CalendarDay getDay(){    CalendarDay tempDay = CalendarDay.from(day.getYear(),day.getMonth(),day.getDay());    return tempDay;}//设置选择背景private Drawable customBackground;//设置背景图片public void setCustomBackground(Drawable drawable){    if(drawable == null){        this.customBackground = null;    }else{        this.customBackground = drawable.getConstantState().newDrawable(getResources());    }    invalidate();}//自定义了一个TextSpan 给需要的日期集合设置这个样式 扩展日期控件的内容// int mode mode 的不同设置不同的样式//visible 决定日期显示不显示 ,如果是当前页面的日期就为true 不是当前页面的月份就不显示public  void applyTextSpan(int mode,boolean visible){    setVisibility(visible ? View.VISIBLE : View.INVISIBLE);    if(mode == 0 || mode == 1){        String label = getLabel();        SpannableString formattedLabel = new SpannableString(getLabel());        formattedLabel.setSpan(new TextSpan(mode), 0, label.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);        setText(formattedLabel);    }else{        setText(getLabel());    }   // invalidate();}//清空DayView的背景,public void setUnselected(){    customBackground = null;    invalidate();}//设置DayVIew 点击日期后的背景public void setSelected(){    customBackground = generateCircleDrawable(Color.GRAY);    invalidate();}private final Rect tempRect = new Rect();@Overrideprotected void onDraw(Canvas canvas) {    if(customBackground != null){        canvas.getClipBounds(tempRect);        customBackground.setBounds(tempRect);        customBackground.setState(getDrawableState());        customBackground.draw(canvas);    }    super.onDraw(canvas);}//生成圆的的drawableprivate static Drawable generateCircleDrawable(final int color){    ShapeDrawable drawable = new ShapeDrawable(new OvalShape());    drawable.setShaderFactory(new ShapeDrawable.ShaderFactory() {        @Override        public Shader resize(int width, int height) {            return new LinearGradient(0, 0, 0, 0, color, color, Shader.TileMode.REPEAT);        }    });    return drawable;}

}

CalendarPagerView 中填充DayView控件
public class CalendarPagerView extends ViewGroup implements View.OnClickListener{
//当前月的页面中的 当前月
private int currentMonth;
//存储四十二天的日期
private List dayViews = new ArrayList<>();

//用来传递日期点击事件private CalendarViewGAC calendarView;public CalendarPagerView(Context context,CalendarDay firstDayCurrentMonth,CalendarViewGAC calendarView) {    super(context);    currentMonth = firstDayCurrentMonth.getMonth()+1;    this.calendarView = calendarView;    buildWeekViews();    buildayViews(firstDayCurrentMonth);}public int getCurrentMonth(){    return currentMonth;}public void clearSelction(){    for(int i = 0; i < dayViews.size();i++){        dayViews.get(i).setUnselected();    }}//建立周日到周一的标题栏private void buildWeekViews(){    TextView tv1 = new TextView(getContext());    tv1.setText("星期日");    TextView tv2 = new TextView(getContext());    tv2.setText("星期一");    TextView tv3 = new TextView(getContext());    tv3.setText("星期二");    TextView tv4 = new TextView(getContext());    tv4.setText("星期三");    TextView tv5 = new TextView(getContext());    tv5.setText("星期四");    TextView tv6 = new TextView(getContext());    tv6.setText("星期五");    TextView tv7 = new TextView(getContext());    tv7.setText("星期六");    addView(tv1);    addView(tv2);    addView(tv3);    addView(tv4);    addView(tv5);    addView(tv6);    addView(tv7);}//根据当前月份生成是四十二天的日期private void buildayViews(CalendarDay firstDayCurrentMonth){    dayViews.clear();    Log.e("gac","firstDayCurrentMonth:"+firstDayCurrentMonth.toString());    Calendar calendar = firstDayCurrentMonth.getCalendar();    Log.e("gac","month:"+calendar.get(Calendar.MONTH));    calendar.setFirstDayOfWeek(Calendar.SUNDAY);    int delta = CalendarUtils.getDayOfWeek(calendar);    Log.e("gac","delta:"+delta);    if(delta > 0){        delta = Calendar.SUNDAY - delta;        calendar.add(Calendar.DATE,delta);    }else{    }    for(int i = 0; i <  42;i++){        DayView day = null;        if(currentMonth != (calendar.get(Calendar.MONTH)+1)){            day = new DayView(getContext(),calendar,View.INVISIBLE);        }else{            day = new DayView(getContext(),calendar,View.VISIBLE);        }        if(currentMonth != day.getDate().getMonth()){            day.setVisibility(INVISIBLE);        }        calendar.add(Calendar.DATE, 1);        day.setOnClickListener(this);        dayViews.add(day);        addView(day);    }}//给CalendarPagerView 应用设置好的TextSpan//TextDecorator 得到传递的日期集合 并且判断该日期需要设置的控件内容类型public void applayDecorator(TextDecorator decorator){    for(int i = 0; i < dayViews.size();i++){        DayView dayView = dayViews.get(i);        int mode = decorator.shouldDecorateGAC(dayView.getDay());        Log.e("gac","date:"+dayView.getDate()+" mode:"+mode);        dayView.applyTextSpan(mode,currentMonth==dayView.getDate().getMonth());    }}//给四十九个控件 进行排列@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {    int count = getChildCount();    final int parentLeft = 0;    int childTop = 0;    int childLeft = parentLeft;    for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        final int width = child.getMeasuredWidth();        final int height = child.getMeasuredHeight();        child.layout(childLeft, childTop, childLeft + width, childTop + height);        childLeft += width;        //We should warp every so many children        if (i % 7 == 6) {            childLeft = parentLeft;            childTop += height;        }    }}//测量布局文件 对布局进行测量@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);    final int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);    final int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);    final int specHeightMode = MeasureSpec.getMode(heightMeasureSpec);    if (specHeightMode == MeasureSpec.UNSPECIFIED || specWidthMode == MeasureSpec.UNSPECIFIED) {        throw new IllegalStateException("CalendarPagerView should never be left to decide it's size");    }    //The spec width should be a correct multiple    final int measureTileSize = specWidthSize / 7;    //Just use the spec sizes    setMeasuredDimension(specWidthSize, specHeightSize);    int count = getChildCount();    for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(                measureTileSize,                MeasureSpec.EXACTLY        );        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(                measureTileSize,                MeasureSpec.EXACTLY        );        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);    }}//将日期的点击事件传给CalendarViewGAC @Overridepublic void onClick(View v) {    DayView d = (DayView)v;    calendarView.onDateClicked(d);}

}

接下来实现CalendarPagerAdapter 主要为了填充CalendarPagerView 最后将adpater设置进ViewPager中去实现日历的滑动效果:

public class CalendarPagerAdapter extends PagerAdapter{

private  CalendarViewGAC view;private int currentPosition = -1;private Context context;CalendarPagerView pager;//当前这个月的日历页面private CalendarViewGAC calendarViewGAC;//将CalendarViewGAC传递给CalendarPagerView 为了传递日期点击事件private List<CalendarPagerView> pagers = new ArrayList<>();//存储缓存的日历页面的集合private TextDecorator decorator;//设置DayView控件的扩展界面的日期集合public CalendarPagerAdapter(Context c,CalendarViewGAC calendarViewGAC){    context = c;    this.calendarViewGAC = calendarViewGAC;}//通过此方法得到一个CalendarVIewPager页面 根据position位置去获得当前日期@Overridepublic Object instantiateItem(ViewGroup container, int position) {    //Log.e("gac","instaniateItem........");    pager =  createViewByPosition(position);//new CalendarPagerView(view.getContext());    pagers.add(pager);    container.addView(pager);    //invalidateDecorators();    invalidateDecorators();    return pager;}public void setDecorator(TextDecorator decorator){    this.decorator = decorator;    invalidateDecorators();}private void invalidateDecorators(){    Log.e("gac","size:"+pagers.size());    for(int i = 0;i < pagers.size(); i++){        Log.e("gac","pager current month:"+pagers.get(i).getCurrentMonth());        pagers.get(i).applayDecorator(decorator);    }}private CalendarPagerView createViewByPosition(int position){    if(currentPosition == -1 || position == 0){        currentPosition = DateAndPostion.getPosition(CalendarDay.today());    }   // Log.e("gac","create ************************View By position!!!!!!!");   // Log.e("gac","position:"+position);    CalendarDay day =  DateAndPostion.getCalendarDay(position);   // Log.e("gac","day:"+day.toString());    return  new CalendarPagerView(context,day,calendarViewGAC);}@Overridepublic int getCount() {    return 50000;}

// @Override
// public int getItemPosition(Object object) {
// Log.e(“gac”,”getItemPosition”);
// int index = 0;
// if(object instanceof CalendarPagerView){
// index = currentPosition;
// }
// Log.e(“gac”,”index;”+index);
// return index;
// }

//清除所有选中的日期背景 然后重新设置点击背景public void clearSelections(){    for(int i = 0; i < pagers.size();i++){        pagers.get(i).clearSelction();    }}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {    ((ViewPager) container).removeView((CalendarPagerView) object);    pagers.remove((CalendarPagerView)object);}@Overridepublic boolean isViewFromObject(View view, Object object) {    return view == object;}//这个类用于日期和ViewPager当前位置的转换类 可以将当前位置转换为日期,也可以将日期转换为当前位置public static class DateAndPostion{    public static int getPosition(CalendarDay c){        int year = c.getYear();        int month = c.getMonth();        return (year-1)*12+month;    }    public static  CalendarDay getCalendarDay(int position){        int year = position/12;        int month = position-(year*12);        return CalendarDay.from(year+1, month, 1);    }}

}

最后是CalendarViewGAC类,这个类继承LinearLayout集合,设置了一个标题显示 年月份的TextView,标题下面就是一个ViewPager类,这个类填充CalendarViewPagerAdapter类,最后就可以实现滑动的日历控件了.
package com.gac.calendarviewgac;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.text.SimpleDateFormat;

/**
* Created by Administrator on 2016/3/22.
*/
public class CalendarViewGAC extends LinearLayout {
private CalendarPager pager;//继承ViewPager 为了装载月份页面的视图
private CalendarPagerAdapter adapter;
private OnDateSelectedListener listener;//单独日期点击事件的监听器
private TextView title;//显示年月的标题
public interface OnDateSelectedListener{
void onDateSelected(DayView view);
}
public CalendarViewGAC(Context context) {
this(context, null);
}

public CalendarViewGAC(Context context, AttributeSet attrs) {    this(context, attrs, 0);}

public CalendarViewGAC(Context context,AttributeSet attrs,int def){
super(context, attrs, def);
setOrientation(VERTICAL);
initTopBar(context);
init(context);
//addView(new CalendarPagerView(context));
}
public void setOnDateSelectedLintener(OnDateSelectedListener lintener){
this.listener = lintener;
}
//初始化标题栏
private void initTopBar(Context context){
title = new TextView(context);
title.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
title.setText(“title”);
title.setTextSize(20);
title.setGravity(Gravity.CENTER);
addView(title,new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
//初始化CalendarPager 并且填充Adapter
private void init(Context context){
pager = new CalendarPager(context);
adapter = new CalendarPagerAdapter(context,this);
pager.setAdapter(adapter);
SimpleDateFormat format = new SimpleDateFormat(“MM 月 yyyy 年”);
String date = format.format((CalendarDay.today().getDate()));
title.setText(date);
//设置当前日期为显示时间
pager.setCurrentItem(CalendarPagerAdapter.DateAndPostion.getPosition(CalendarDay.today()));
//给pager添加滑动监听器
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }        @Override        public void onPageSelected(int position) {            CalendarDay day = CalendarPagerAdapter.DateAndPostion.getCalendarDay(position);          // date = DateUtils.getDateStr(day.getDate());            SimpleDateFormat format = new SimpleDateFormat("MM 月 yyyy 年");            String date =  format.format(day.getDate());            title.setText(date);        }        @Override        public void onPageScrollStateChanged(int state) {        }    });    addView(pager,new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));}@Overridepublic void onInitializeAccessibilityEvent(AccessibilityEvent event) {    super.onInitializeAccessibilityEvent(event);    event.setClassName(CalendarViewGAC.class.getName());}@Overridepublic void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {    super.onInitializeAccessibilityNodeInfo(info);    info.setClassName(CalendarViewGAC.class.getName());}@Overridepublic boolean onTouchEvent(MotionEvent event) {    return pager.dispatchTouchEvent(event);}@Overrideprotected void onLayout(boolean changed, int left, int t, int right, int b) {    final int count = getChildCount();    Log.e("gac","count:count:"+count);    final int parentLeft = getPaddingLeft();    final int parentWidth = right - left - parentLeft - getPaddingRight();    int childTop = getPaddingTop();    for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        final int width = child.getMeasuredWidth();        final int height = child.getMeasuredHeight();        int delta = (parentWidth - width) / 2;        int childLeft = parentLeft + delta;        child.layout(childLeft, childTop, childLeft + width, childTop + height);        childTop += height;    }}private static int clampSize(int size, int spec) {    int specMode = MeasureSpec.getMode(spec);    int specSize = MeasureSpec.getSize(spec);    switch (specMode) {        case MeasureSpec.EXACTLY: {            return specSize;        }        case MeasureSpec.AT_MOST: {            return Math.min(size, specSize);        }        case MeasureSpec.UNSPECIFIED:        default: {            return size;        }    }}protected void onDateClicked(DayView dayView){    adapter.clearSelections();    listener.onDateSelected(dayView);}

public void setDecorator(TextDecorator decorator){
adapter.setDecorator(decorator);
}

class CalendarPager extends ViewPager {    private boolean pagingEnabled = true;    public CalendarPager(Context context) {        super(context);    }    CalendarPager(Context context,AttributeSet attrs){        super(context,attrs);    }    public void setChildrenDrawingOrderEnabledCompat(boolean enable) {        setChildrenDrawingOrderEnabled(enable);    }    /**     * enable disable viewpager scroll     *     * @param pagingEnabled false to disable paging, true for paging (default)     */    public void setPagingEnabled(boolean pagingEnabled) {        this.pagingEnabled = pagingEnabled;    }    /**     * @return is this viewpager allowed to page     */    public boolean isPagingEnabled() {        return pagingEnabled;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return pagingEnabled && super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        return pagingEnabled && super.onTouchEvent(ev);    }    @Override    public boolean canScrollVertically(int direction) {        /**         * disables scrolling vertically when paging disabled, fixes scrolling         * for nested {@link android.support.v4.view.ViewPager}         */        return pagingEnabled && super.canScrollVertically(direction);    }    @Override    public boolean canScrollHorizontally(int direction) {        /**         * disables scrolling horizontally when paging disabled, fixes scrolling         * for nested {@link android.support.v4.view.ViewPager}         */        return pagingEnabled && super.canScrollHorizontally(direction);    }}

}

源码下载地址:

有什么不明白的欢迎交流!!!!

1 0
原创粉丝点击