横向滑动的日历控件的实现
来源:互联网 发布:微信企业宣传软件 编辑:程序博客网 时间: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); }}
}
源码下载地址:
有什么不明白的欢迎交流!!!!
- 横向滑动的日历控件的实现
- 单行横向滑动的日历calendar控件
- Android中单行横向滑动的日历
- 横向滑动加载更多的控件的实现
- ios 横向日历控件的使用
- 【实训】自动横向循环滑动图片控件的实现
- DateScroller自定义控件横向滑动日历选择器
- UITableView 的横向滑动实现
- 安卓可滑动的自定义日历控件的实现
- android自定义控件--横向滑动的ListView
- 安卓自定义日历滑动的日历控件
- Android 自定义横向滑动菜单的实现
- android 单行gridview横向滑动的实现
- Android多行gridview横向滑动的实现
- 可以纵向横向滑动的表格实现
- Android实现横向滑动的GridView
- Android导航菜单横向左右滑动并和下方的控件实现联动
- Android导航菜单横向左右滑动并和下方的控件实现联动
- 226. Invert Binary Tree
- 动态分页管理的淘汰算法
- PHP中htmlentities跟htmlspecialchars的区别
- 数学技巧类问题
- UIView上添加了一个按钮和一个单击手势的事件相应,互相不影响的处理方法。。
- 横向滑动的日历控件的实现
- 开通博客,这是我奋斗的第一步
- 网络认证
- 寒假安排
- JTable删除所有数据
- JTable动态刷新内容
- eclipse中import中的引用都显示错…
- Linux学习笔记(一)-基础篇
- JAVA线程引起的CPU满负载