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

}

});

}

}

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

以上是 Android实现可滑动的自定义日历控件 的全部内容, 来源链接: utcz.com/p/240887.html

回到顶部