自定义CalendarView,可以以周视图或者月视图显示

来源:互联网 发布:ds18b20怎么接单片机 编辑:程序博客网 时间:2024/06/02 07:30

转载请注明转自,谢谢:http://blog.csdn.net/wmlove_hqy/article/details/46716951

首先分析一下功能。

1.能够左右滑动,这里选择通过ViewPager实现。

2.能够点击、选中日期,说明每一天是一个单独的View,选中的状态的变化改变,这里用StateDrawbleList实现。

3.通过Calendar提供的方法实现数据填充。

我们先来看看效果。

这里写图片描述

好,让我们开始吧!
我首先在这里定义一个DayView.

public class DayView extends TextView{        private int backgroupColor = Color.GREEN;        private Date date;        private int day;        private int month;        public DayView(Context context) {            super(context);            setTextAlignment(TEXT_ALIGNMENT_CENTER);            setBackgroupColor();            setTextSize(20);            setHeight(150);            setWidth(150);            setTextColor(Color.BLACK);            setGravity(Gravity.CENTER);        }        //提供更改选中之后背景颜色        public void setSelectColor(int color){            this.backgroupColor = color;            setBackgroupColor();            postInvalidate();        }        private void setBackgroupColor(){            //设置点击时改变背景色            StateListDrawable drawable = new StateListDrawable();            ShapeDrawable shape = new ShapeDrawable(new OvalShape());            shape.setShaderFactory(new ShapeDrawable.ShaderFactory() {                @Override                public Shader resize(int i, int i1) {                    return new LinearGradient(0,0,0,0,backgroupColor,backgroupColor, Shader.TileMode.REPEAT);                }            });            drawable.addState(new int[]{android.R.attr.state_selected}, shape);            setBackground(drawable);        }        //设置具体的日期        public void setDay(boolean showotherdays,boolean inrange){            //判断是否显示除了这个月份之外的日期。            //默认不显示            //当视图为周视图时,默认为真            if(!showotherdays){                String text = inrange ? day+"" : "";                boolean enable = inrange ? true : false;                setEnabled(enable);                setText(text);                return;            }            setText(String.valueOf(day));        }        //供外部调用,接受具体日期        public void setTimeRange(Calendar calendar) {            this.day = calendar.get(Calendar.DAY_OF_MONTH);            this.month = calendar.get(Calendar.MONTH);            this.date = calendar.getTime();        }        public String getTime(){            String time;            SimpleDateFormat format = new SimpleDateFormat("dd MMMM", Locale.ENGLISH);            time = format.format(date);            return time;        }        public Date getDate(){            return this.date;        }    }

这就表示每一天的日期,只需要实例化出来并且设置他的日期。

每一天有了,现在需要一个容器把他放进去,可以是一个月,或者是一周。
所以我定义了一个TimeView来放这些Day.

public class TimeView extends RelativeLayout implements View.OnClickListener{    //每个星期有的天数    private static final int DEFAULT_DAY_IN_WEEK = 7;    //一个月有几个星期,为月视图的时候默认是 6个星期,周视图为 1个星期。    private int WEEK_IN_MONTH;    //用来表示周视图或者月视图的flag    private int timeflag;    private boolean showOtherDay;    private List<DayView> dayViewList;    private Calendar mCalendarCurrent = null;    //当Day被选中时候的回调    private OnDaySelectListener mDaySelectCallBack;    //当Day选中状态切换的时候的回调    private OnDaySelectChangeListener mOnDaySelectChangeListener;    public void setOnDaySelectListener(OnDaySelectListener mDaySelectCallBack) {        this.mDaySelectCallBack = mDaySelectCallBack;    }    public void setOnDaySelectChangeListener(OnDaySelectChangeListener onDaySelectChangeListener){        this.mOnDaySelectChangeListener = onDaySelectChangeListener;    }    public TimeView(Context context,Calendar calendarCurrent,int timeflag) {        super(context);        mCalendarCurrent = CalendarUtils.getCalenar();        CalendarUtils.copyTo(calendarCurrent,mCalendarCurrent);        showOtherDay = false;        timeflag = Calendar.MONTH;        dayViewList = new ArrayList<>()        WEEK_IN_MONTH = (timeflag==Calendar.MONTH) ? 6 : 1;        showOtherDay = (timeflag==Calendar.WEEK_OF_YEAR) ? true : false;        setUpView();        setDayView(timeflag);    }    //画出每一行,填充后用来显示一周    private LinearLayout makeRow(){        LinearLayout row = new LinearLayout(getContext());        row.setOrientation(LinearLayout.HORIZONTAL);        LinearLayout.LayoutParams params = new     LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,0,1f);        row.setLayoutParams(params);        return row;    }    //把周视图或者月视图画出来    private void setUpView() {        LinearLayout root = new LinearLayout(getContext());        root.setOrientation(LinearLayout.VERTICAL);        LinearLayout row;        for(int i=0;i<WEEK_IN_MONTH;i++){            row = makeRow();            for(int x=0;x<DEFAULT_DAY_IN_WEEK;x++){                DayView day = new DayView(getContext());                day.setOnClickListener(this);                row.addView(day, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f));                dayViewList.add(day);            }            root.addView(row);        }        addView(root, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));    }    //把每一个DayView设置日期    private void setDayView(int timeflag){        Calendar calendar = getWorkingCalendar();        for(DayView dayView : dayViewList){            dayView.setTimeRange(calendar);            dayView.setDay(showOtherDay, calendar.get(timeflag) == mCalendarCurrent.get(timeflag));            calendar.add(Calendar.DATE,1);        }    }    //把Calendar设置为每个月或者每个星期的第一天    private Calendar getWorkingCalendar(){        Calendar calendar = CalendarUtils.getCalenar();        CalendarUtils.copyTo(mCalendarCurrent, calendar);        if(timeflag==Calendar.MONTH){CalendarUtils.setToFirstDayInMonth(calendar);}        CalendarUtils.setToFirstDayInWeek(calendar);        return calendar;    }    public Calendar getTimeCalendar(){        Log.i("TAG",mCalendarCurrent.getTime()+"Timecurrent");        return this.mCalendarCurrent;    }    public Date getDate(){        return this.mCalendarCurrent.getTime();    }    public void setSelectColor(int color){        for(DayView dayView : dayViewList){            dayView.setSelectColor(color);        }    }    public void setTimeFlag(int timeflag){        this.timeflag = timeflag;    }    //处理点击事件    @Override    public void onClick(View view) {        String time = null;        Date date = null;        if(view instanceof DayView){            clearSelected();            DayView dayView = (DayView) view;            dayView.setSelected(true);            Toast.makeText(getContext(),dayView.getText(),Toast.LENGTH_SHORT).show();            time = dayView.getTime();            date = dayView.getDate();            postInvalidate();        }        mDaySelectCallBack.OnDaySelect(time,date);        mOnDaySelectChangeListener.SelectChangeCallBack();    }    //用于清除其他TimeView的选中状态    public void clearSelected() {        for(DayView other : dayViewList){            other.setSelected(false);        }    }}

这就表示一个月或者一个星期的View,其实也就是ViewPager中的一个Item。
OnDaySelectListener 和OnDaySelectChangeListener 是定义用来回调的接口。
CalendarUtils是一个工具类。

那么有了Item,接下来就是添加到ViewPager中了。
而ViewPager也是放在一个容器之中,构成了这整个CalendarView。

public class CalendarView extends RelativeLayout {    private ViewPager mViewPager;    private CalendarViewAdapter mCalendarViewAdapter;    private DaySelectChanegListener mDaySelectChanegListener = new DaySelectChanegListener();    //默认是显示月视图的    private boolean inweek = false;    private int TimeFlag ;    private List<TimeView> timeViewList = new ArrayList<>();    private List<DaySelectChanegListener> OnTimeChangeListenerList = new ArrayList<>();    private Calendar mCalendarMax = null;    private Calendar mCalendarMin = null;    private Calendar mCalendarCurrent = null;    private OnTimeChangeListener mOnTimeChangeListener = null;    public int getTimeFlag(boolean inweek) {        return inweek ? Calendar.WEEK_OF_YEAR : Calendar.MONTH;    }    //把除了选中的Day所在的TimeView之外的day全部设置为非选中状态    private class DaySelectChanegListener implements OnDaySelectChangeListener {        @Override        public void SelectChangeCallBack() {            TimeView current = timeViewList.get(mViewPager.getCurrentItem());            for (TimeView other : timeViewList) {                if (other!=current){other.clearSelected();}            }        }    }    public CalendarView(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray t = context.obtainStyledAttributes(attrs,R.styleable.CalendarView);        inweek = t.getBoolean(R.styleable.CalendarView_viewinview,false);        t.recycle();        TimeFlag = getTimeFlag(inweek);        LinearLayout root = new LinearLayout(context);        root.setOrientation(LinearLayout.VERTICAL);        addTimeView();        LinearLayout title = new LinearLayout(context);        title.setOrientation(LinearLayout.HORIZONTAL);        Calendar calendar = CalendarUtils.getCalenar();        CalendarUtils.setToFirstDayInWeek(calendar);        SimpleDateFormat format = new SimpleDateFormat("EEE", Locale.ENGLISH);        for (int i = 0; i < 7; i++) {            TextView textView = new TextView(context);            textView.setWidth(150);            textView.setHeight(150);            textView.setGravity(Gravity.CENTER);            textView.setTextAlignment(TEXT_ALIGNMENT_CENTER);            textView.setTextColor(Color.BLACK);            textView.setText(format.format(calendar.getTime()));            Log.i("TAG", format.format(calendar.getTime()));            calendar.add(Calendar.DATE, 1);            title.addView(textView);        }        Log.i("TAG", title.getChildCount() + "childcount");        root.addView(title);        mViewPager = new ViewPager(context);        mCalendarViewAdapter = new CalendarViewAdapter();        mViewPager.setAdapter(mCalendarViewAdapter);        mViewPager.setCurrentItem(getIndex());        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}            @Override            public void onPageSelected(int position) {                TimeView timeView = timeViewList.get(position);                Date date = timeView.getDate();                mOnTimeChangeListener.OnTimeChange(date);            }            @Override            public void onPageScrollStateChanged(int state) {}        });        root.addView(mViewPager, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));        addView(root);    }    //当前的ViewPager中的TimeView因为滑动而改变时的回调。    public void setOnTimeChangeListener(OnTimeChangeListener listener){        if(listener!=null){            this.mOnTimeChangeListener = listener;        }        else throw new NullPointerException("OnTimeChangeListener can not be null!");    }    public void setOnDaySelectListener(OnDaySelectListener listener){        if(listener!=null){            for(TimeView timeView : timeViewList){                timeView.setOnDaySelectListener(listener);            }        }        else throw new NullPointerException("OnDaySelectListener can not be null!");    }    //设置可以显示的最大日期    public void setMaxDate(Calendar calendarMax){        this.mCalendarMax = calendarMax;        postInvalidate();    }    //设置可以显示的最小日期    public void setMinDate(Calendar calendarMin){        this.mCalendarMin = calendarMin;        postInvalidate();    }    public void setSelectColor(int color){        for(TimeView timeView : timeViewList){            timeView.setSelectColor(color);        }    }    //设置当前的日期    public void setCurrentCalendar(Calendar currentCalendar){        this.mCalendarCurrent = currentCalendar;        postInvalidate();    }    //得到可以显示的最小Calendar    private Calendar getMinCalendarDay(){        if(mCalendarMin==null){            int mindate = -2;            Calendar min = CalendarUtils.getCalenar();            min.add(Calendar.YEAR, mindate);            return min;        }        return mCalendarMin;    }    //得到可以显示的最大Calendar    private Calendar getMaxCalendarDay(){        if(mCalendarMax==null){            int maxdate = 2;            Calendar max = CalendarUtils.getCalenar();            max.add(Calendar.YEAR,maxdate);            return max;        }        return mCalendarMax;    }    //把符合条件的TimeView添加到集合当中    private void addTimeView(){        Calendar minCalendar = getMinCalendarDay();        Calendar maxCalendar = getMaxCalendarDay();        if(mCalendarCurrent==null){            mCalendarCurrent = CalendarUtils.getCalenar();        }        CalendarUtils.copyTo(minCalendar,mCalendarCurrent);        Log.i("TAG",minCalendar.getTime()+"minCalendar"+maxCalendar.getTime()+"maxCalendar"+mCalendarCurrent.getTime()+"mCalendarCurrent");        while (CalendarUtils.isBefore(mCalendarCurrent, maxCalendar)){            TimeView timeView = new TimeView(getContext(),mCalendarCurrent,TimeFlag);            timeView.setOnDaySelectChangeListener(mDaySelectChanegListener);            timeViewList.add(timeView);            mCalendarCurrent.add(TimeFlag, 1);        }    }    //得到当前日期的Index    private int getIndex(){        Calendar c = CalendarUtils.getCalenar();        for(int i=0;i<timeViewList.size();i++){            TimeView timeView = timeViewList.get(i);            Calendar other = timeView.getTimeCalendar();            if(c.get(Calendar.YEAR)==other.get(Calendar.YEAR)                    &&c.get(Calendar.MONTH)==other.get(Calendar.MONTH)){                        if(TimeFlag==Calendar.WEEK_OF_YEAR){                       if(c.get(Calendar.WEEK_OF_YEAR)==other.get(Calendar.WEEK_OF_YEAR)){return i;}                        }                return i;            }        }        return 0;    }    //ViewPager的适配器    private class CalendarViewAdapter extends PagerAdapter{        @Override        public int getCount() {            return timeViewList.size();        }        @Override        public boolean isViewFromObject(View view, Object o) {            return view == o;        }        @Override        public Object instantiateItem(ViewGroup container, int position) {            TimeView timeView = timeViewList.get(position);            Log.i("TAG",timeViewList.size()+"size");            container.addView(timeView);            return timeViewList.get(position);        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView(timeViewList.get(position));        }    }}

到此就完成了这一个自定义的CalendarView,很简单吧。
总结一下。
主要是ViewPager中Item数据的填充,通过Calendar提供的一些方法就可以轻松的把你需要的日期筛选出来。然后就是把这些日期通过简单的逻辑判断填充到每一个所需要的View中,再就当做Item显示出来。还有一些基本的功能,如选中某一天能够回调这一天的日期,当前显示的月或者周是第几周或者哪一个月,再就是能够设置显示的最大日期和最小日期,选中某一天时的背景。最后是我主要想实现的,能够通过在布局文件中设置CalendarView是显示月视图还是周视图。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:wmlove="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"    android:layout_height="match_parent" tools:context=".MainActivity">    <wmlove.library.CalendarView        wmlove:viewinview="false"        android:id="@+id/calendarview"        android:layout_width="wrap_content"        android:layout_height="wrap_content">    </wmlove.library.CalendarView></RelativeLayout>

如果有考虑不周到的地方还提出,一同探讨,谢谢。
也可以去我的GitHubh上给我Pull Requests,或者提issues
https://github.com/t154191277/CalendarView-Android

源代码下载地址:http://download.csdn.net/detail/wmlove_hqy/8859825

0 0
原创粉丝点击