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

作者:满地韶华 时间:2022-09-01 02:12:21 

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

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

来源:https://blog.csdn.net/swd2lx/article/details/52440569

标签:Android,日历控件
0
投稿

猜你喜欢

  • java实现超市库存管理系统

    2022-06-28 01:23:44
  • 浅谈Java中replace与replaceAll区别

    2021-07-05 12:56:56
  • C#实现HTTP上传文件的方法

    2023-04-28 04:05:30
  • java保证对象在内存中唯一性的实现方法

    2023-11-27 21:30:03
  • 详解通过JDBC进行简单的增删改查(以MySQL为例)

    2023-08-14 20:16:40
  • 剖析设计模式编程中C#对于组合模式的运用

    2023-04-09 07:48:17
  • Android ListView ImageView实现单选按钮实例

    2023-09-19 20:25:39
  • Unity EasyTouch摇杆插件使用示例详解

    2023-01-26 17:09:17
  • Android TextView自定义数字滚动动画

    2023-10-03 09:48:17
  • Android布局之GridLayout网格布局

    2022-04-24 22:49:46
  • asp.net页面中如何获取Excel表的内容

    2022-11-18 11:40:31
  • Android Studio中统一管理版本号引用配置问题

    2023-03-06 04:23:54
  • Java基于享元模式实现五子棋游戏功能实例详解

    2023-07-23 16:20:18
  • Java C++ 算法题解leetcode652寻找重复子树

    2022-08-17 23:58:09
  • java安全编码指南之:表达式规则说明

    2021-06-01 17:48:44
  • 使用JPA主键@Id,@IdClass,@Embeddable,@EmbeddedId问题

    2022-07-07 18:35:41
  • ViewDragHelper实现QQ侧滑效果

    2022-12-25 23:26:54
  • 使用Stargate访问K8ssandra的过程之Springboot整合Cassandra

    2022-02-08 23:12:25
  • java 如何实现正确的删除集合中的元素

    2022-08-03 17:44:31
  • Flutter持久化存储之数据库存储(sqflite)详解

    2022-11-16 04:34:30
  • asp之家 软件编程 m.aspxhome.com