自定义日历控件-CalendarView

转载请注明出处: http://blog.csdn.net/forwardyzk/article/details/43056675

我们在开发中会遇到使用到日历控件,下面就介绍一个自定义日历控件。

思路:

1.自定义类CalendarView继承LinearLayout,使用布局文件,显示布局。

2.使用ViewFlipper,里面添加GridView,当月的日期。

3.使用手势GestureDetector,控制ViewFlipper的滑动。

calen_calendar.xml

<span style="font-family:SimSun;font-size:18px;"><?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="wrap_content"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/prevMonth"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:src="@drawable/prev_month" />

        <TextView
            android:id="@+id/currentMonth"
            android:layout_width="0dp"
            android:layout_height="35dp"
            android:layout_weight="3"
            android:gravity="center"
            android:text="2014年6月"
            android:textColor="#177ed6"
            android:textSize="18dp" />

        <ImageView
            android:id="@+id/nextMonth"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:src="@drawable/next_month" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="#ffffffff" >

        <TextView
            style="@style/weekName"
            android:text="日"
            android:textColor="#177ed6" />

        <TextView
            style="@style/weekName"
            android:text="一" />

        <TextView
            style="@style/weekName"
            android:text="二" />

        <TextView
            style="@style/weekName"
            android:text="三" />

        <TextView
            style="@style/weekName"
            android:text="四" />

        <TextView
            style="@style/weekName"
            android:text="五" />

        <TextView
            style="@style/weekName"
            android:text="六"
            android:textColor="#177ed6" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#ff8091a8" />

    <ViewFlipper
        android:id="@+id/flipper"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout></span>
<span style="font-family:SimSun;font-size:18px;">public class CalendarView extends LinearLayout implements OnClickListener {

	private final String TAG = CalendarView.class.getSimpleName();
	private int year_c = 0;// 今天的年份
	private int month_c = 0;// 今天的月份
	private int day_c = 0;// 今天的日期
	private String currentDate = "";
	private Context mContext;
	private TextView currentMonth;// 显示日期
	private ImageView prevMonth;// 去上一个月
	private ImageView nextMonth;// 去下一个月
	private int gvFlag = 0;
	private GestureDetector gestureDetector = null;
	private CalendarAdapter calV = null;
	private ViewFlipper flipper = null;
	private GridView gridView = null;
	private static int jumpMonth = 0; // 每次滑动,增加或减去一个月,默认为0(即显示当前月)
	private static int jumpYear = 0; // 滑动跨越一年,则增加或者减去一年,默认为0(即当前年)
	private ClickDataListener clickDataListener;

	public CalendarView(Context context) {
		this(context, null);
	}

	public CalendarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		initView();
	}

	private void initView() {
		View view = View.inflate(mContext, R.layout.calen_calendar, this);
		currentMonth = (TextView) view.findViewById(R.id.currentMonth);
		prevMonth = (ImageView) view.findViewById(R.id.prevMonth);
		nextMonth = (ImageView) view.findViewById(R.id.nextMonth);
		setListener();
		setCurrentDay();
		gestureDetector = new GestureDetector(mContext, new MyGestureListener());
		flipper = (ViewFlipper) findViewById(R.id.flipper);
		flipper.removeAllViews();
		calV = new CalendarAdapter(mContext, getResources(), jumpMonth,
				jumpYear, year_c, month_c, day_c);
		addGridView();
		gridView.setAdapter(calV);
		flipper.addView(gridView, 0);
		addTextToTopTextView(currentMonth);
	}

	private void setListener() {
		prevMonth.setOnClickListener(this);
		nextMonth.setOnClickListener(this);

	}

	public void setClickDataListener(ClickDataListener clickDataListener) {
		this.clickDataListener = clickDataListener;
	}

	private void setCurrentDay() {
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd");
		currentDate = sdf.format(date); // 当期日期
		year_c = Integer.parseInt(currentDate.split("-")[0]);
		month_c = Integer.parseInt(currentDate.split("-")[1]);
		day_c = Integer.parseInt(currentDate.split("-")[2]);
	}

	/**
	 * 移动到下一个月
	 *
	 * @param gvFlag
	 */
	private void enterNextMonth(int gvFlag) {
		addGridView(); // 添加一个gridView
		jumpMonth++; // 下一个月
		calV = new CalendarAdapter(mContext, this.getResources(), jumpMonth,
				jumpYear, year_c, month_c, day_c);
		gridView.setAdapter(calV);
		addTextToTopTextView(currentMonth); // 移动到下一月后,将当月显示在头标题中
		gvFlag++;
		flipper.addView(gridView, gvFlag);
		flipper.setInAnimation(AnimationUtils.loadAnimation(mContext,
				R.anim.push_left_in));
		flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext,
				R.anim.push_left_out));
		flipper.showNext();
		flipper.removeViewAt(0);
	}

	/**
	 * 移动到上一个月
	 *
	 * @param gvFlag
	 */
	private void enterPrevMonth(int gvFlag) {
		addGridView(); // 添加一个gridView
		jumpMonth--; // 上一个月

		calV = new CalendarAdapter(mContext, this.getResources(), jumpMonth,
				jumpYear, year_c, month_c, day_c);
		gridView.setAdapter(calV);
		gvFlag++;
		addTextToTopTextView(currentMonth); // 移动到上一月后,将当月显示在头标题中
		flipper.addView(gridView, gvFlag);

		flipper.setInAnimation(AnimationUtils.loadAnimation(mContext,
				R.anim.push_right_in));
		flipper.setOutAnimation(AnimationUtils.loadAnimation(mContext,
				R.anim.push_right_out));
		flipper.showPrevious();
		flipper.removeViewAt(0);
	}

	/**
	 * 添加头部的年份 闰哪月等信息
	 *
	 * @param view
	 */
	private void addTextToTopTextView(TextView view) {
		StringBuffer textDate = new StringBuffer();
		// draw = getResources().getDrawable(R.drawable.top_day);
		// view.setBackgroundDrawable(draw);
		textDate.append(calV.getShowYear()).append("年")
				.append(calV.getShowMonth()).append("月").append("\t");
		view.setText(textDate);
	}

	private void addGridView() {
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
		// 取得屏幕的宽度和高度
		WindowManager windowManager = ((Activity) mContext).getWindowManager();
		Display display = windowManager.getDefaultDisplay();
		int Width = display.getWidth();
		int Height = display.getHeight();

		gridView = new GridView(mContext);
		gridView.setNumColumns(7);
		gridView.setColumnWidth(40);
		// gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
		if (Width == 720 && Height == 1280) {
			gridView.setColumnWidth(40);
		}
		gridView.setGravity(Gravity.CENTER_VERTICAL);
		gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));
		// 去除gridView边框
		gridView.setVerticalSpacing(0);
		gridView.setHorizontalSpacing(0);
		gridView.setOnTouchListener(new OnTouchListener() {
			// 将gridview中的触摸事件回传给gestureDetector

			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				return gestureDetector.onTouchEvent(event);
			}
		});

		gridView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1,
					int position, long arg3) {
				// TODO Auto-generated method stub
				// 点击任何一个item,得到这个item的日期(排除点击的是周日到周六(点击不响应))
				int startPosition = calV.getStartPositon();
				int endPosition = calV.getEndPosition();
				if (startPosition <= position + 7
						&& position <= endPosition - 7) {
					String scheduleDay = calV.getDateByClickItem(position)
							.split("\\.")[0]; // 这一天的阳历
					String scheduleYear = calV.getShowYear();
					String scheduleMonth = calV.getShowMonth();
					((CalendarAdapter) arg0.getAdapter())
							.setColorDataPosition(position);
					if (clickDataListener != null) {
						clickDataListener.clickData(scheduleYear,
								scheduleMonth, scheduleDay);
					}
				}
			}
		});
		gridView.setLayoutParams(params);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.nextMonth: // 下一个月
			enterNextMonth(gvFlag);
			Log.d(TAG, "gvFlag=" + gvFlag);
			break;
		case R.id.prevMonth: // 上一个月
			enterPrevMonth(gvFlag);
			break;

		}

	}

	class MyGestureListener extends SimpleOnGestureListener {
		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			int gvFlag = 0; // 每次添加gridview到viewflipper中时给的标记
			if (e1.getX() - e2.getX() > 120) {
				// 像左滑动
				enterNextMonth(gvFlag);
				return true;
			} else if (e1.getX() - e2.getX() < -120) {
				// 向右滑动
				enterPrevMonth(gvFlag);
				return true;
			}
			return false;
		}
	}
}</span>

在initView中调用addGridView()。初始化显示日期的View,然后设置其适配器,然后添加到flipper.addView(gridView, 0);中

addTextToTopTextView()更改标题显示的年和月

enterNextMonth()显示下一个月日历,首先是将下个月的GridView添加到ViewFlipper中,显示下个月的信息,并且移除上个月的GridView。

enterPrevMonth():显示上一个月的日历,首先将上个月的GridView添加到ViewFlipper中,显示下个月的信息,并且移除当前月的GridView。

在MyGestureListener类中,判断是否显示上个月或者下一月信息的情况,向左滑动,显示上一个月信息,向右滑动,显示上月日历。

在gridView的setOnItemClickListener,如果点击日期,差通过接口传递出去,并且通知适配器,当前日期的颜色背景需要改变(当月的日期)。

适配器

<span style="font-family:SimSun;font-size:18px;">public CalendarAdapter(Context context, Resources rs, int jumpMonth,
			int jumpYear, int year_c, int month_c, int day_c) {
		this();
		this.context = context;
		sc = new SpecialCalendar();
		lc = new LunarCalendar();
		this.res = rs;

		int stepYear = year_c + jumpYear;
		int stepMonth = month_c + jumpMonth;
		if (stepMonth > 0) {
			// 往下一个月滑动
			if (stepMonth % 12 == 0) {
				stepYear = year_c + stepMonth / 12 - 1;
				stepMonth = 12;
			} else {
				stepYear = year_c + stepMonth / 12;
				stepMonth = stepMonth % 12;
			}
		} else {
			// 往上一个月滑动
			stepYear = year_c - 1 + stepMonth / 12;
			stepMonth = stepMonth % 12 + 12;
			if (stepMonth % 12 == 0) {

			}
		}

		currentYear = String.valueOf(stepYear); // 得到当前的年份
		currentMonth = String.valueOf(stepMonth); // 得到本月
													// (jumpMonth为滑动的次数,每滑动一次就增加一月或减一月)
		currentDay = String.valueOf(day_c); // 得到当前日期是哪天

		getCalendar(Integer.parseInt(currentYear),
				Integer.parseInt(currentMonth));

	}
</span>

在这里做将显示日历信息。根绝传入的stepMonth,表示点击间距,和系统的日期比较,系统时间的月表示0,如果显示下一个月信息,stepMonth++;如果显示上一个信息,stepMonth--;

通过stepMonth+系统显示的月,就可以知道要使显示yyyy年mm月了。

<span style="font-family:SimSun;font-size:18px;">private void getweek(int year, int month) {
		int j = 1;
		String lunarDay = "";
		// 得到当前月的所有日程日期(这些日期需要标记)
		for (int i = 0; i < dayNumber.length; i++) {
			if (i < dayOfWeek) { // 前一个月
				int temp = lastDaysOfMonth - dayOfWeek + 1;
				lunarDay = lc.getLunarDate(year, month - 1, temp + i, false);
				dayNumber[i] = (temp + i) + "." + lunarDay;

			} else if (i < daysOfMonth + dayOfWeek) { // 本月
				String day = String.valueOf(i - dayOfWeek + 1); // 得到的日期
				lunarDay = lc.getLunarDate(year, month, i - dayOfWeek + 1,
						false);
				dayNumber[i] = i - dayOfWeek + 1 + "." + lunarDay;
				// 对于当前月才去标记当前日期
				if (sys_year.equals(String.valueOf(year))
						&& sys_month.equals(String.valueOf(month))
						&& sys_day.equals(day)) {
					// 标记当前日期
					colorDataPosition = i;
				}
				setShowYear(String.valueOf(year));
				setShowMonth(String.valueOf(month));
				setAnimalsYear(lc.animalsYear(year));
				setLeapMonth(lc.leapMonth == 0 ? "" : String
						.valueOf(lc.leapMonth));
				setCyclical(lc.cyclical(year));
			} else { // 下一个月
				lunarDay = lc.getLunarDate(year, month + 1, j, false);
				dayNumber[i] = j + "." + lunarDay;
				j++;
			}
		}

		String abc = "";
		for (int i = 0; i < dayNumber.length; i++) {
			abc = abc + dayNumber[i] + ":";
		}
		Log.d("DAYNUMBER", abc);

	}</span>

在此方法中,是要获取要展示的42天的信息,通过LunarCalendar中的getLunarDate()获取阴历的日期。

通过SpecialCalendar中的getWeekdayOfMonth获取当月第一天为星期几(dayOfWeek),

显示位置:position<dayOfWeek表示前一个月的日期

dayOfWeek<=position<daysOfMonth + dayOfWeek 表示当前要显示月日期

position>=daysOfMonth + dayOfWeek 表示显示下一个月日期

<span style="font-family:SimSun;font-size:18px;">public View getView(int position, View convertView, ViewGroup parent) {

		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(
					R.layout.calen_calendar_item, null);
		}
		TextView textView = (TextView) convertView.findViewById(R.id.tvtext);
		String d = dayNumber[position].split("\\.")[0];
		String dv = dayNumber[position].split("\\.")[1];

		SpannableString sp = new SpannableString(d + "\n" + dv);
		sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0,
				d.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		sp.setSpan(new RelativeSizeSpan(1.2f), 0, d.length(),
				Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		if (dv != null || dv != "") {
			sp.setSpan(new RelativeSizeSpan(0.75f), d.length() + 1,
					dayNumber[position].length(),
					Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		textView.setText(sp);
		textView.setTextColor(Color.GRAY);

		if (position < daysOfMonth + dayOfWeek && position >= dayOfWeek) {
			// 当前月信息显示
			textView.setTextColor(Color.BLACK);// 当月字体设黑
			// drawable = new ColorDrawable(Color.rgb(23, 126, 214));
			if (position % 7 == 0 || position % 7 == 6) {
				// 当前月信息显示
				textView.setTextColor(Color.rgb(23, 126, 214));// 当月字体设黑
			}
		}

		if (colorDataPosition == position) {
			// 设置当天的背景
			textView.setTextColor(Color.WHITE);

			textView.setBackgroundResource(R.drawable.bg_circle);
		} else {
			textView.setBackgroundColor(res
					.getColor(android.R.color.transparent));
		}
		return convertView;
	}</span>

在getView中,设置要显示的日期的信息,通过颜色区分出当月和上个月、下月。

有一个点击日期的标记,改变点击日期的背景颜色,但是有一个条件,只可以点击当月的日期,默认是系统的日期。

<span style="font-family:SimSun;font-size:18px;">public void setColorDataPosition(int position) {
		if (position >= dayOfWeek && position < daysOfMonth + dayOfWeek) {
			colorDataPosition = position;
			notifyDataSetChanged();
		}
	}</span>

使用步骤:

activity_main.xml

<span style="font-family:SimSun;font-size:18px;"><?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" >

    <com.example.clander.view.CalendarView
        android:id="@+id/calendarview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </com.example.clander.view.CalendarView>

</LinearLayout></span>

CalendarActivity.java

<span style="font-family:SimSun;font-size:18px;">public class CalendarActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		CalendarView calendarview = (CalendarView) findViewById(R.id.calendarview);
		//设置点击日期的事件监听
		calendarview.setClickDataListener(new ClickDataListener() {

			@Override
			public void clickData(String year, String month, String day) {
				Toast.makeText(getApplicationContext(),
						year + "-" + month + "-" + day, 0).show();

			}
		});
	}

}</span>

源码下载:  http://download.csdn.net/detail/forwardyzk/8390217

效果图:

时间: 2024-10-10 06:45:58

自定义日历控件-CalendarView的相关文章

javascript实例学习之六—自定义日历控件

基于之前上篇博客轻量级jquery,tool.js和base.js.自定义开发的base_datePicker插件,效果类似于jquery_ui的datePicker插件 //基于Base.js以及tool.js做的日历插件 $().extend('datePicker', function() { //生成日历插件 var $yearSpan; var $monthSpan; var tds; var $prevBtn; var $nextBtn; var $lastTr; var $date

安卓自定义日历控件

尊重作者劳动成果,转载请注明出处:http://blog.csdn.net/baiyuliang2013/article/details/37732149 最近,因工作需要,需要实现自定义日历控件功能,主要应用于软件中的酒店入住时间选择功能,进入日历后,可选择入住时间,及离开时间,选择完成后,再次进入日历时,会显示上次选中的结果,默认选择日期是在距当前日期三个月内,三个月以外的均以灰色显示,且不可点击.本篇实现的效果是高仿某软件的界面效果: 某软件界面效果: 本篇实现的效果: 另外,对于日期选择

【无私分享】干货!!!一个炫酷的自定义日历控件,摆脱日历时间选择烦恼,纯福利~

最近公司项目中有一个按日期查看信息的功能,楼主本想用之前用的wheelView将就使用的,不过产品经理有个新要求,就是点击按钮弹出的日期选择对话框必须显示农历节假日,周几什么的.这可就难为人了,倘若使用之前的滚动时间选择器,无疑是难以实现的,楼主辗转反侧,冥思苦想,却不得正果. 好吧,去网上下了几个OA系统一用就有了idea,突然想到手机自带的日历~~,oh,year,日历就有这功能,瞧瞧,我靠,这个东西,咋做. 仔细一瞧,似乎用GridView可以实现,额,二话不说就开干.折腾了半天都没弄好,

IOS自定义日历控件的简单实现(附思想及过程)

因为程序要求要插入一个日历控件,该空间的要求是从当天开始及以后的六个月内的日历,上网查资料基本上都说只要获取两个条件(当月第一天周几和本月一共有多少天)就可以实现一个简单的日历,剩下的靠自己的简单逻辑就OK了,下面开始自己从开始到完成的整个过程 1,首先做NSDate类目,扩展一些方法让日期之间转换更加方便 #import <Foundation/Foundation.h> @interface NSDate (LYWCalendar) #pragma mark - 获取日 - (NSInte

android 自定义日历控件

日历控件View: [java] view plaincopyprint? /** * 日历控件 功能:获得点选的日期区间 * */ public class CalendarView extends View implements View.OnTouchListener { private final static String TAG = "anCalendar"; private Date selectedStartDate; private Date selectedEndD

HTML5 自定义日历控件

ys_datetime_selector.css .ys-datetime-selector{     position:fixed;     left:0;     right:0;     top:0;     bottom:0;     background-color:rgba(0,0,0,0.3);     z-index: 999; } .ys-datetime-selector.display-hide{     transform: translate3d(100%,0,0);

Android自定义组件之日历控件-精美日历实现(内容、样式可扩展)

需求 我们知道,Android系统本身有自带的日历控件,网络上也有很多开源的日历控件资源,但是这些日历控件往往样式较单一,API较多,不易于在实际项目中扩展并实现出符合具体样式风格的,内容可定制的效果.本文通过自定义日历控件,实现了在内容和样式上可高度扩展的精美日历demo,有需要的Android应用开发人员可迅速移植并按需扩展实现. 在某个应用中,需要查询用户的历史考勤记录,根据实际考勤数据在日历中标记出不同的状态(如正常出勤.请假.迟到等),并在页面中显示相应的说明文字. 效果 实现的效果如

Android开发中几种有用的的日历控件实现

我们大家都知道,在Android平台3.0中才新增了日历视图控件,可以显示网格状的日历内容,那么对于3.0以下的版本要使用日历控件只能借助第三方,目前用的最多的是CalendarView. 先简单介绍下CalendarView日历控件的使用. android.widget.CalendarView是从android.widget.FrameLayout中继承. CalendarView 类提供了基本的日历设置方法: long getDate() 获取从1970年,1月1日,0点0分0秒到现在的毫

开源日历控件DatePicker源码解析

在一些项目开发中,会使用日历去标识事务,所以根据美工出的效果图,我们可以采用不同的方法去实现.比如通过GridView扣扣你敢.自定义View实现日历控件,这些都是我们解决问题的手段,我也实现过一个自定义日历控件(Android自定义控件之日历控件55993)),由于我只是粗糙的进行实现,并没有进行过多的在控件的可扩展性上进行打磨设计,所以在本篇文章中,我秉着学习的态度分析下爱哥的鼎力巨作DatePicker-DatePicker. DatePicker开源项目地址:[https://githu