android 日历开发附源码(附源码)
16lz
2021-01-23
这里主要记录一下在编写日历apk过程中一些主要的点:先看下效果图
一、主要功能
- 1、支持农历、节气、常用节假日
- 2、使用数据库,设置计划
二、基本结构
我们要实现的日历控件采用GestureDetector构造器,使用OnGestureListener监听滑动。目前我们设定日历左右滑动为月份切换的操作,每一个月份显示通过GridView实现,里面的数据是通过构造CalendarView,将其绑定到GridView。每次左右滑动,都会刷新CalendarView。布局上,会在GridView上显示当前日期农历时间。
三、主要代码及解析
CalendarActivity.java
/** * 日历显示activity * * @author 孔乙己大叔 */public class CalendarActivity extends Activity implements OnGestureListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); gestureDetector = new GestureDetector(this, this); flipper = (ViewFlipper) findViewById(R.id.flipper); flipper.removeAllViews(); calV = new CalendarView(this, getResources(), jumpMonth, jumpYear, year_c, month_c, day_c); addGridView(); gridView.setAdapter(calV); flipper.addView(gridView, 0); topText = (BorderText) findViewById(R.id.toptext); addTextToTopTextView(topText); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int gvFlag = 0; //每次添加gridview到viewflipper中时给的标记 if (e1.getX() - e2.getX() > 120) { //像左滑动 addGridView(); //添加一个gridView jumpMonth++; //下一个月 calV = new CalendarView(this, getResources(), jumpMonth, jumpYear, year_c, month_c, day_c); gridView.setAdapter(calV); addTextToTopTextView(topText); gvFlag++; flipper.addView(gridView, gvFlag); this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out)); this.flipper.showNext(); flipper.removeViewAt(0); return true; } else if (e1.getX() - e2.getX() < -120) { //向右滑动 addGridView(); //添加一个gridView jumpMonth--; //上一个月 calV = new CalendarView(this, getResources(), jumpMonth, jumpYear, year_c, month_c, day_c); gridView.setAdapter(calV); gvFlag++; addTextToTopTextView(topText); //flipper.addView(gridView); flipper.addView(gridView, gvFlag); this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out)); this.flipper.showPrevious(); flipper.removeViewAt(0); return true; } return false; } /** * 创建菜单 */ @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, menu.FIRST, menu.FIRST, "今天"); menu.add(0, menu.FIRST + 1, menu.FIRST + 1, "跳转"); menu.add(0, menu.FIRST + 2, menu.FIRST + 2, "日程"); menu.add(0, menu.FIRST + 3, menu.FIRST + 3, "日期转换"); return super.onCreateOptionsMenu(menu); } /** * 选择菜单 */ @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { switch (item.getItemId()) { case Menu.FIRST: //跳转到今天 int xMonth = jumpMonth; int xYear = jumpYear; int gvFlag = 0; jumpMonth = 0; jumpYear = 0; addGridView(); //添加一个gridView year_c = Integer.parseInt(currentDate.split("-")[0]); month_c = Integer.parseInt(currentDate.split("-")[1]); day_c = Integer.parseInt(currentDate.split("-")[2]); calV = new CalendarView(this, getResources(), jumpMonth, jumpYear, year_c, month_c, day_c); gridView.setAdapter(calV); addTextToTopTextView(topText); gvFlag++; flipper.addView(gridView, gvFlag); if (xMonth == 0 && xYear == 0) { //nothing to do } else if ((xYear == 0 && xMonth > 0) || xYear > 0) { this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out)); this.flipper.showNext(); } else { this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in)); this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out)); this.flipper.showPrevious(); } flipper.removeViewAt(0); break; case Menu.FIRST + 1: new DatePickerDialog(this, new OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { //1901-1-1 ----> 2049-12-31 if (year < 1901 || year > 2049) { //不在查询范围内 new AlertDialog.Builder(CalendarActivity.this).setTitle("错误日期").setMessage("跳转日期范围(1901/1/1-2049/12/31)").setPositiveButton("确认", null).show(); } else { int gvFlag = 0; addGridView(); //添加一个gridView calV = new CalendarView(CalendarActivity.this, CalendarActivity.this.getResources(), year, monthOfYear + 1, dayOfMonth); gridView.setAdapter(calV); addTextToTopTextView(topText); gvFlag++; flipper.addView(gridView, gvFlag); if (year == year_c && monthOfYear + 1 == month_c) { //nothing to do } if ((year == year_c && monthOfYear + 1 > month_c) || year > year_c) { CalendarActivity.this.flipper.setInAnimation(AnimationUtils.loadAnimation(CalendarActivity.this, R.anim.push_left_in)); CalendarActivity.this.flipper.setOutAnimation(AnimationUtils.loadAnimation(CalendarActivity.this, R.anim.push_left_out)); CalendarActivity.this.flipper.showNext(); } else { CalendarActivity.this.flipper.setInAnimation(AnimationUtils.loadAnimation(CalendarActivity.this, R.anim.push_right_in)); CalendarActivity.this.flipper.setOutAnimation(AnimationUtils.loadAnimation(CalendarActivity.this, R.anim.push_right_out)); CalendarActivity.this.flipper.showPrevious(); } flipper.removeViewAt(0); //跳转之后将跳转之后的日期设置为当期日期 year_c = year; month_c = monthOfYear + 1; day_c = dayOfMonth; jumpMonth = 0; jumpYear = 0; } } }, year_c, month_c - 1, day_c).show(); break; case Menu.FIRST + 2: Intent intent = new Intent(); intent.setClass(CalendarActivity.this, ScheduleAll.class); startActivity(intent); break; case Menu.FIRST + 3: Intent intent1 = new Intent(); intent1.setClass(CalendarActivity.this, CalendarConvert.class); intent1.putExtra("date", new int[]{year_c, month_c, day_c}); startActivity(intent1); break; } return super.onMenuItemSelected(featureId, item); } //添加头部的年份 闰哪月等信息 public void addTextToTopTextView(TextView view) { StringBuffer textDate = new StringBuffer(); view.setBackgroundResource(R.drawable.top_day); view.setBackground(getResources().getDrawable(R.drawable.top_day)); textDate.append(calV.getShowYear()).append("年").append(calV.getShowMonth()).append("月").append("\t"); if (!calV.getLeapMonth().equals("") && calV.getLeapMonth() != null) { textDate.append("闰").append(calV.getLeapMonth()).append("月").append("\t"); } textDate.append(calV.getAnimalsYear()).append("年").append("(").append(calV.getCyclical()).append("年)"); view.setText(textDate); view.setTextColor(Color.BLACK); view.setTypeface(Typeface.DEFAULT_BOLD); } //添加gridview private void addGridView() { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int Width = displayMetrics.widthPixels; int Height = displayMetrics.heightPixels; gridView = new GridView(this); gridView.setNumColumns(7); gridView.setColumnWidth(46); if (Width == 480 && Height == 800) { gridView.setColumnWidth(69); } gridView.setGravity(Gravity.CENTER_VERTICAL); gridView.setSelector(new ColorDrawable(Color.TRANSPARENT)); // 去除gridView边框 gridView.setVerticalSpacing(1); gridView.setHorizontalSpacing(1); gridView.setBackgroundResource(R.drawable.gridview_bk); gridView.setOnTouchListener(new OnTouchListener() { //将gridview中的触摸事件回传给gestureDetector @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return CalendarActivity.this.gestureDetector .onTouchEvent(event); } }); gridView.setOnItemClickListener(new OnItemClickListener() { //gridView中的每一个item的点击事件 @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { //点击任何一个item,得到这个item的日期(排除点击的是周日到周六(点击不响应)) int startPosition = calV.getStartPositon(); int endPosition = calV.getEndPosition(); if (startPosition <= position && position <= endPosition) { String scheduleDay = calV.getDateByClickItem(position).split("\\.")[0]; //这一天的阳历 String scheduleYear = calV.getShowYear(); String scheduleMonth = calV.getShowMonth(); String week = ""; //通过日期查询这一天是否被标记,如果标记了日程就查询出这天的所有日程信息 String[] scheduleIDs = dao.getScheduleByTagDate(Integer.parseInt(scheduleYear), Integer.parseInt(scheduleMonth), Integer.parseInt(scheduleDay)); if (scheduleIDs != null && scheduleIDs.length > 0) { //跳转到显示这一天的所有日程信息界面 Intent intent = new Intent(); intent.setClass(CalendarActivity.this, ScheduleInfoView.class); intent.putExtra("scheduleID", scheduleIDs); startActivity(intent); } else { //直接跳转到需要添加日程的界面 //得到这一天是星期几 switch (position % 7) { case 0: week = "星期日"; break; case 1: week = "星期一"; break; case 2: week = "星期二"; break; case 3: week = "星期三"; break; case 4: week = "星期四"; break; case 5: week = "星期五"; break; case 6: week = "星期六"; break; } ArrayList scheduleDate = new ArrayList(); scheduleDate.add(scheduleYear); scheduleDate.add(scheduleMonth); scheduleDate.add(scheduleDay); scheduleDate.add(week); //scheduleDate.add(scheduleLunarDay); Intent intent = new Intent(); intent.putStringArrayListExtra("scheduleDate", scheduleDate); intent.setClass(CalendarActivity.this, ScheduleView.class); startActivity(intent); } } } }); gridView.setLayoutParams(params); }}
自定义view实现:
/** * 日历gridview中的每一个item显示的textview * * @author 孔乙己大叔 */public class CalendarView extends BaseAdapter { public CalendarView(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)); } public CalendarView(Context context, Resources rs, int year, int month, int day) { this(); this.context = context; sc = new SpecialCalendar(); lc = new LunarCalendar(); this.res = rs; currentYear = String.valueOf(year); ; //得到跳转到的年份 currentMonth = String.valueOf(month); //得到跳转到的月份 currentDay = String.valueOf(day); //得到跳转到的天 getCalendar(Integer.parseInt(currentYear), Integer.parseInt(currentMonth)); } @Override public int getCount() { // TODO Auto-generated method stub return dayNumber.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.calendar, null); } TextView textView = (TextView) convertView.findViewById(R.id.tvtext); String d = dayNumber[position].split("\\.")[0]; String dv = dayNumber[position].split("\\.")[1]; //Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Helvetica.ttf"); //textView.setTypeface(typeface); 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); } //sp.setSpan(new ForegroundColorSpan(Color.MAGENTA), 14, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) textView.setText(sp); textView.setTextColor(Color.GRAY); if (position < 7) { //设置周 textView.setTextColor(Color.BLACK); textView.setBackgroundResource(R.drawable.week_top); } if (position < daysOfMonth + dayOfWeek + 7 && position >= dayOfWeek + 7) { // 当前月信息显示 textView.setTextColor(Color.BLACK);// 当月字体设黑 drawable = res.getDrawable(R.drawable.item); //textView.setBackgroundDrawable(drawable); //textView.setBackgroundColor(Color.WHITE); } if (schDateTagFlag != null && schDateTagFlag.length > 0) { for (int i = 0; i < schDateTagFlag.length; i++) { if (schDateTagFlag[i] == position) { //设置日程标记背景 textView.setBackgroundResource(R.drawable.mark); } } } if (currentFlag == position) { //设置当天的背景 textView.setBackgroundResource(R.drawable.current_day_bgc); textView.setTextColor(Color.WHITE); } return convertView; } //得到某年的某月的天数且这月的第一天是星期几 public void getCalendar(int year, int month) { isLeapyear = sc.isLeapYear(year); //是否为闰年 daysOfMonth = sc.getDaysOfMonth(isLeapyear, month); //某月的总天数 dayOfWeek = sc.getWeekdayOfMonth(year, month); //某月第一天为星期几 lastDaysOfMonth = sc.getDaysOfMonth(isLeapyear, month - 1); //上一个月的总天数 Log.d("DAY", isLeapyear + " ====== " + daysOfMonth + " ============ " + dayOfWeek + " ========= " + lastDaysOfMonth); getweek(year, month); } //将一个月中的每一天的值添加入数组dayNuber中 private void getweek(int year, int month) { int j = 1; int flag = 0; String lunarDay = ""; //得到当前月的所有日程日期(这些日期需要标记) dao = new ScheduleDAO(context); ArrayList dateTagList = dao.getTagDate(year, month); if (dateTagList != null && dateTagList.size() > 0) { schDateTagFlag = new int[dateTagList.size()]; } for (int i = 0; i < dayNumber.length; i++) { // 周一 if (i < 7) { dayNumber[i] = week[i] + "." + " "; } else if (i < dayOfWeek + 7) { //前一个月 int temp = lastDaysOfMonth - dayOfWeek + 1 - 7; lunarDay = lc.getLunarDate(year, month - 1, temp + i, false); dayNumber[i] = (temp + i) + "." + lunarDay; } else if (i < daysOfMonth + dayOfWeek + 7) { //本月 String day = String.valueOf(i - dayOfWeek + 1 - 7); //得到的日期 lunarDay = lc.getLunarDate(year, month, i - dayOfWeek + 1 - 7, false); dayNumber[i] = i - dayOfWeek + 1 - 7 + "." + lunarDay; //对于当前月才去标记当前日期 if (sys_year.equals(String.valueOf(year)) && sys_month.equals(String.valueOf(month)) && sys_day.equals(day)) { //笔记当前日期 currentFlag = i; } //标记日程日期 if (dateTagList != null && dateTagList.size() > 0) { for (int m = 0; m < dateTagList.size(); m++) { ScheduleDateTag dateTag = dateTagList.get(m); int matchYear = dateTag.getYear(); int matchMonth = dateTag.getMonth(); int matchDay = dateTag.getDay(); if (matchYear == year && matchMonth == month && matchDay == Integer.parseInt(day)) { schDateTagFlag[flag] = i; flag++; } } } 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); } }
判断是否为闰年,当月多少天数,当天是星期几代码实现:
// 判断是否为闰年 public boolean isLeapYear(int year) { if (year % 100 == 0 && year % 400 == 0) { return true; } else if (year % 100 != 0 && year % 4 == 0) { return true; } return false; } //得到某月有多少天数 public int getDaysOfMonth(boolean isLeapyear, int month) { switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: daysOfMonth = 31; break; case 4: case 6: case 9: case 11: daysOfMonth = 30; break; case 2: if (isLeapyear) { daysOfMonth = 29; } else { daysOfMonth = 28; } } return daysOfMonth; } //指定某年中的某月的第一天是星期几 public int getWeekdayOfMonth(int year, int month) { Calendar cal = Calendar.getInstance(); cal.set(year, month - 1, 1); dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1; return dayOfWeek; }
四、小结
这里我们只介绍了日历的基本实现原理,和一些关键的点,其实这种实现方式相对还是比较简单的,容易理解,当然难免有不足的地方,后边根据需要再逐步完善和扩展吧。数据库操作暂时没进行解析,后面会单独用demo说明。
源码下载地址:https://download.csdn.net/download/Ctrl_qun/12436629
更多相关文章
- Android中关于日期时间与时区的使用总结
- android 日期按钮实现
- android datepicker只显示年和日期
- 【Android】对话框之日期和时间对话框
- Android下常用的正则表达式判断工具类代码(手机,电话,Email,日期等待
- Android 获取时间戳 和时间戳转日期
- Android自带的时间空间和日期控件
- Android学习07-----事件处理(3)监听日期与时间的改变_焦点事件_
- Android随笔之——Android时间、日期相关类和方法