Android实现可滑动的自定义日历控件

最近用到的一个日历控件,记录下,效果如图

代码下载地址:点击打开链接

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:visibility="visible">

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@color/bg_gray"
 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="2016年9月"
  android:textColor="@color/black"
  android:textSize="18sp" />

 <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="@color/bg_gray">

 <TextView
  style="@style/weekName"
  android:text="周日"
  android:textColor="@color/green" />

 <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="@color/green" />
 </LinearLayout>

 <View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="@color/line" />

 <ViewFlipper
 android:id="@+id/flipper"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:background="@color/line"
 android:padding="1dp" />

 <View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="@color/line" />

</LinearLayout>

日历PopCalendar.class的代码

public class PopCalendar extends PopupWindow implements View.OnClickListener {
 private View contentView;
 private Context mContext;
 private WindowManager windowManager;
 private GestureDetector gestureDetector = null;
 private CalendarAdapter calV = null;
 private ViewFlipper flipper = null;
 private GridView gvCalendar = null;
 private static int jumpMonth = 0; // 每次滑动,增加或减去一个月,默认为0(即显示当前月)
 private static int jumpYear = 0; // 滑动跨越一年,则增加或者减去一年,默认为0(即当前年)
 private int yearC = 0;
 private int monthC = 0;
 private int dayC = 0;
 private String currentDate = "";
 //当前年月,显示在日历顶端
 private TextView currentMonthTv;
 //上个月,下个月的图标
 private ImageView prevMonthIv;
 private ImageView nextMonthIv;

 public PopCalendar(final Activity context) {
 this.mContext = context;
 this.windowManager = context.getWindowManager();;
 Date date = new Date();
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
 currentDate = sdf.format(date); // 当期日期
 yearC = Integer.parseInt(currentDate.split("-")[0]);
 monthC = Integer.parseInt(currentDate.split("-")[1]);
 dayC = Integer.parseInt(currentDate.split("-")[2]);
 jumpMonth = 0;
 jumpYear = 0;

 //设置PopWindow的属性
 LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 contentView = inflater.inflate(R.layout.pop_calendar, null);
 this.setContentView(contentView);
 this.setWidth(WindowManager.LayoutParams.FILL_PARENT);
 this.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
 this.setFocusable(true);
 this.setOutsideTouchable(true);
 this.update();
 ColorDrawable dw = new ColorDrawable(0000000000);
 this.setBackgroundDrawable(dw);

 currentMonthTv = (TextView) contentView.findViewById(R.id.currentMonth);
 prevMonthIv = (ImageView) contentView.findViewById(R.id.prevMonth);
 nextMonthIv = (ImageView) contentView.findViewById(R.id.nextMonth);
 setListener();

 gestureDetector = new GestureDetector(mContext, new MyGestureListener());
 flipper = (ViewFlipper) contentView.findViewById(R.id.flipper);
 flipper.removeAllViews();
 calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
 addGridView();
 gvCalendar.setAdapter(calV);
 flipper.addView(gvCalendar, 0);
 addTextToTopTextView(currentMonthTv);
 }

 private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  if (e1.getX() - e2.getX() > 120) {
  // 像左滑动
  enterNextMonth();
  return true;
  } else if (e1.getX() - e2.getX() < -120) {
  // 向右滑动
  enterPrevMonth();
  return true;
  }
  return false;
 }
 }

 /**
 * 移动到下一个月
 *
 */
 private void enterNextMonth() {
 addGridView(); // 添加一个gridView
 jumpMonth++; // 下一个月

 calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
 gvCalendar.setAdapter(calV);
 addTextToTopTextView(currentMonthTv); // 移动到下一月后,将当月显示在头标题中
 flipper.addView(gvCalendar, 1);
 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);
 }

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

 calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
 gvCalendar.setAdapter(calV);
 addTextToTopTextView(currentMonthTv); // 移动到上一月后,将当月显示在头标题中
 flipper.addView(gvCalendar, 1);

 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
 */
 public void addTextToTopTextView(TextView view) {
 StringBuffer textDate = new StringBuffer();
 textDate.append(calV.getShowYear()).append("年").append(calV.getShowMonth()).append("月").append("\t");
 view.setText(textDate);
 }

 private void addGridView() {
 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
 // 取得屏幕的宽度和高度
 Display display = windowManager.getDefaultDisplay();
 int Width = display.getWidth();
 int Height = display.getHeight();
 gvCalendar = new GridView(mContext);
 gvCalendar.setNumColumns(7);
 gvCalendar.setColumnWidth(40);
 // gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
 if (Width == 720 && Height == 1280) {
  gvCalendar.setColumnWidth(40);
 }
 gvCalendar.setGravity(Gravity.CENTER_VERTICAL);
 gvCalendar.setSelector(new ColorDrawable(Color.TRANSPARENT));
 // 去除gridView边框
 gvCalendar.setVerticalSpacing(2);
 gvCalendar.setHorizontalSpacing(2);
 gvCalendar.setOnTouchListener(new View.OnTouchListener() {
  // 将gridView中的触摸事件回传给gestureDetector
  public boolean onTouch(View v, MotionEvent event) {
  // TODO Auto-generated method stub
  return PopCalendar.this.gestureDetector.onTouchEvent(event);
  }
 });

 gvCalendar.setOnItemClickListener(new AdapterView.OnItemClickListener() {

  @Override
  public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
  // TODO Auto-generated method stub
  // 点击任何一个item,得到这个item的日期(排除点击的是周日到周六(点击不响应))
  int startPosition = calV.getStartPosition();
  int endPosition = calV.getEndPosition();
  if (startPosition <= position + 7 && position <= endPosition - 7) {
   String scheduleDay = calV.getDateByClickItem(position); // 这一天的阳历
   String scheduleYear = calV.getShowYear();
   String scheduleMonth = calV.getShowMonth();
   Toast.makeText(mContext, scheduleYear + "-" + scheduleMonth + "-" + scheduleDay, Toast.LENGTH_SHORT).show();
  }
  }
 });
 gvCalendar.setLayoutParams(params);
 }

 private void setListener() {
 prevMonthIv.setOnClickListener(this);
 nextMonthIv.setOnClickListener(this);
 }

 @Override
 public void onClick(View v) {
 // TODO Auto-generated method stub
 switch (v.getId()) {
  case R.id.nextMonth: // 下一个月
  enterNextMonth();
  break;
  case R.id.prevMonth: // 上一个月
  enterPrevMonth();
  break;
  default:
  break;
 }
 }

 /**
 * 显示popWindow
 */
 public void showPopupWindow(View parent) {
 if (!this.isShowing()) {
  // 以下拉方式显示popupwindow
  this.showAsDropDown(parent);
 } else {
  this.dismiss();
 }
 }
}

日历的内容是一个GridView,可以自定义类似签到效果的图标

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@color/bg_gray" >

 <TextView
 android:id="@+id/tv_text"
 android:layout_width="fill_parent"
 android:layout_height="30dp"
 android:gravity="center" />

 <ImageView
 android:layout_width="15dp"
 android:layout_height="15dp"
 android:visibility="invisible"
 android:layout_alignParentBottom="true"
 android:background="@drawable/pen"
 android:layout_alignParentEnd="true"
 android:id="@+id/iv_pen" />

</RelativeLayout>

日历的adapter

public class CalendarAdapter extends BaseAdapter {
 private boolean isLeapYear = false; // 是否为闰年
 private int daysOfMonth = 0; // 某月的天数
 private int dayOfWeek = 0; // 具体某一天是星期几
 private int lastDaysOfMonth = 0; // 上一个月的总天数
 private Context context;
 private String[] dayNumber = new String[42]; // 一个gridview中的日期存入此数组中
 private SpecialCalendar sc = null;
 private Resources res = null;

 private String currentYear = "";
 private String currentMonth = "";

 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
 private int currentFlag = -1; // 用于标记当天

 private String showYear = ""; // 用于在头部显示的年份
 private String showMonth = ""; // 用于在头部显示的月份

 // 系统当前时间
 private String sysDate = "";
 private String sys_year = "";
 private String sys_month = "";
 private String sys_day = "";
 public CalendarAdapter() {
 Date date = new Date();
 sysDate = sdf.format(date); // 当期日期
 sys_year = sysDate.split("-")[0];
 sys_month = sysDate.split("-")[1];
 sys_day = sysDate.split("-")[2];
 }

 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();
 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为滑动的次数,每滑动一次就增加一月或减一月)

 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_item, null);
 }
 TextView textView = (TextView) convertView.findViewById(R.id.tv_text);
 ImageView ivPen = (ImageView) convertView.findViewById(R.id.iv_pen);
 String d = dayNumber[position];

 SpannableString sp = new SpannableString(d);
 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);

 textView.setText(sp);
 textView.setTextColor(Color.BLACK);// 字体设黑
 if (position % 7 == 0 || position % 7 == 6) {
  // 当前月信息显示
  textView.setTextColor(res.getColor(R.color.green));// 周末字体设绿色
 }

 if (position >= dayOfWeek && position < daysOfMonth + dayOfWeek
  && (Integer.parseInt(sys_month) >= Integer.parseInt(currentMonth)&&Integer.parseInt(sys_year)==Integer.parseInt(currentYear)
  ||Integer.parseInt(sys_year)> Integer.parseInt(currentYear))) {
  // 当前月信息显示
  int a[] = {2, 6, 29};//每个月不标记的天数
  for (int i = 0; i < a.length; i++) {
  if (position == a[i]+dayOfWeek-1) {
   textView.setBackgroundColor(res.getColor(R.color.yellow));//为写日记日期填充黄色
   ivPen.setVisibility(View.INVISIBLE);
   break;
  } else {
   ivPen.setVisibility(View.VISIBLE);
  }
  }
 } else if (position < dayOfWeek || position >= daysOfMonth + dayOfWeek) {
  textView.setTextColor(res.getColor(R.color.bg_gray));
 }

 if (Integer.parseInt(sys_year)==Integer.parseInt(currentYear)
  &&Integer.parseInt(sys_month) == Integer.parseInt(currentMonth)&& currentFlag < position) {
  // 设置本月当天之后的背景
  textView.setBackgroundColor(res.getColor(R.color.bg_gray));//全部填充灰色
  ivPen.setVisibility(View.INVISIBLE);
 }

 if (currentFlag == position) {
  //设置当天的背景
  textView.setBackgroundColor(res.getColor(R.color.blue));
  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); // 上一个月的总天数
 getWeek(year, month);
 }

 // 将一个月中的每一天的值添加入数组dayNuber中
 private void getWeek(int year, int month) {
 int j = 1;
 // 得到当前月的所有日程日期(这些日期需要标记)
 for (int i = 0; i < dayNumber.length; i++) {
  if (i < dayOfWeek) { // 前一个月
  int temp = lastDaysOfMonth - dayOfWeek + 1;
  dayNumber[i] = (temp + i) + "" ;
  } else if (i < daysOfMonth + dayOfWeek) { // 本月
  String day = String.valueOf(i - dayOfWeek + 1); // 得到的日期
  dayNumber[i] = i - dayOfWeek + 1 + "";
  // 对于当前月才去标记当前日期
  if (sys_year.equals(String.valueOf(year)) && sys_month.equals(String.valueOf(month)) && sys_day.equals(day)) {
   // 标记当前日期
   currentFlag = i;
  }
  setShowYear(String.valueOf(year));
  setShowMonth(String.valueOf(month));
  } else { // 下一个月
  dayNumber[i] = j + "";
  j++;
  }
 }
 }

 /**
 * 点击每一个item时返回item中的日期
 * @param position
 * @return
 */
 public String getDateByClickItem(int position) {
 return dayNumber[position];
 }

 /**
 * 在点击gridView时,得到这个月中第一天的位置
 * @return
 */
 public int getStartPosition() {
 return dayOfWeek + 7;
 }

 /**
 * 在点击gridView时,得到这个月中最后一天的位置
 * @return
 */
 public int getEndPosition() {
 return (dayOfWeek + daysOfMonth + 7) - 1;
 }

 public String getShowYear() {
 return showYear;
 }

 public void setShowYear(String showYear) {
 this.showYear = showYear;
 }

 public String getShowMonth() {
 return showMonth;
 }

 public void setShowMonth(String showMonth) {
 this.showMonth = showMonth;
 }
}

在MainActivity点击显示日历,可以指定PopWindow在哪一个控件的下方出现

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 final Button button = (Button)findViewById(R.id.button);
 button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
  PopCalendar popCalendar = new PopCalendar(MainActivity.this);
  popCalendar.showPopupWindow(button);
  }
 });
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现日历控件示例代码

    做的是一个酒店的项目,可以选择入住和离开的日期.声明为了省事在网上找的资料,自己修改的逻辑,希望对需要的朋友有帮助.喜欢的给个好评.谢谢啦!祝生活愉快! 先上图 第一步,搭建布局xml <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_w

  • Android可签到日历控件的实现方法

    最近在公司的功能需求中,需要实现可以签到的日历,签到后在签到过的日期做标志.本功能参考了网上一些大神的日历控件,在此基础上进行修改,已满足本公司的需求,现已完成,记录一下. 布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_wi

  • Android自定义日历控件实例详解

    为什么要自定义控件 有时,原生控件不能满足我们对于外观和功能的需求,这时候可以自定义控件来定制外观或功能:有时,原生控件可以通过复杂的编码实现想要的功能,这时候可以自定义控件来提高代码的可复用性. 如何自定义控件 下面我通过我在github上开源的Android-CalendarView项目为例,来介绍一下自定义控件的方法.该项目中自定义的控件类名是CalendarView.这个自定义控件覆盖了一些自定义控件时常需要重写的一些方法. 构造函数 为了支持本控件既能使用xml布局文件声明,也可在ja

  • Android学习教程之日历控件使用(7)

    本文实例为大家分享了Android日历控件的使用方法,供大家参考,具体内容如下 MainActivity.java代码: package siso.timessquare; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; p

  • Android日历控件的实现方法

    本文实例为大家分享了Android日历控件的实现代码,供大家参考,具体内容如下 1.效果图: 2.弹窗Dialog:SelectDateDialog: public class SelectDateDialog { private static final String TAG = "SelectDateDialog"; private Dialog dialog; private TextView dateText; private int selectYear, selectMon

  • Android使用GridLayout绘制自定义日历控件

    效果图 思路:就是先设置Gridlayout的行列数,然后往里面放置一定数目的自定义日历按钮控件,最后实现日历逻辑就可以了. 步骤: 第一步:自定义日历控件(初步) 第二步:实现自定义单个日期按钮控件 第三步:将第二步得到的控件动态添加到第一步的布局中,并实现日期逻辑 第四步:编写单个日期点击监听器接口 第一步:自定义日历控件(初步) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln

  • Android 一个日历控件的实现代码

    先看几张动态的效果图吧! 项目地址:https://github.com/Othershe/CalendarView 这里主要记录一下在编写日历控件过程中一些主要的点: 一.主要功能 1.支持农历.节气.常用节假日 2.日期范围设置,默认支持的最大日期范围[1900.1~2049.12] 3.默认选中日期设置 4.单选.多选 5.跳转到指定日期 6.通过自定义属性定制日期外观,以及简单的日期item布局配置 二.基本结构 我们要实现的日历控件采用ViewPager作为主框架,CalendarVi

  • Android实现可滑动的自定义日历控件

    最近用到的一个日历控件,记录下,效果如图 代码下载地址:点击打开链接 布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical&q

  • iOS自定义日历控件的简单实现过程

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

  • Android使用属性动画如何自定义倒计时控件详解

    为什么要引入属性动画? Android之前的补间动画机制其实还算是比较健全的,在android.view.animation包下面有好多的类可以供我们操作,来完成一系列的动画效果,比如说对View进行移动.缩放.旋转和淡入淡出,并且我们还可以借助AnimationSet来将这些动画效果组合起来使用,除此之外还可以通过配置Interpolator来控制动画的播放速度等等等等.那么这里大家可能要产生疑问了,既然之前的动画机制已经这么健全了,为什么还要引入属性动画呢? 其实上面所谓的健全都是相对的,如

  • Android自定义实现日历控件

    本文实例为大家分享了Android自定义实现日历控件的具体代码,供大家参考,具体内容如下 1. Calendar类 2. 布局 创建calendar_layout.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:padding="20sp" android:orientation="vertical" android:l

  • Android自定义组合控件之自定义下拉刷新和左滑删除实例代码

    绪论 最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么"那条友谊的小船儿真是说翻就翻啊",好了,下面先来具体看一下实现后的效果吧: 代码已经上传到Github上了,小伙伴们记

随机推荐