热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要为大家详细介绍了Android实现可滑动的自定义日历控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

布局文件


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

日历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<&#63;> 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,可以自定义类似签到效果的图标


 
 
 
 
 
 

日历的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 = 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 = 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 

在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);
  }
 });
 }
}

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


推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文是关于自学Android的笔记,包括查看类的源码的方法,活动注册的必要性以及布局练习的重要性。通过学习本文,读者可以了解到在自学Android过程中的一些关键点和注意事项。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了使用SSH免密登录的步骤,包括生成公私钥、传递公钥给被登录机、修改文件权限的操作。同时提醒用户注意私钥的传递方式,建议使用U盘等离线方式传递。 ... [详细]
author-avatar
ENE的蓝白胖次
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有