Android實(shí)現(xiàn)可滑動(dòng)的自定義日歷控件
最近用到的一個(gè)日歷控件,記錄下,效果如圖

代碼下載地址:點(diǎn)擊打開(kāi)鏈接
布局文件
<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; // 每次滑動(dòng),增加或減去一個(gè)月,默認(rèn)為0(即顯示當(dāng)前月)
private static int jumpYear = 0; // 滑動(dòng)跨越一年,則增加或者減去一年,默認(rèn)為0(即當(dāng)前年)
private int yearC = 0;
private int monthC = 0;
private int dayC = 0;
private String currentDate = "";
//當(dāng)前年月,顯示在日歷頂端
private TextView currentMonthTv;
//上個(gè)月,下個(gè)月的圖標(biāo)
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); // 當(dāng)期日期
yearC = Integer.parseInt(currentDate.split("-")[0]);
monthC = Integer.parseInt(currentDate.split("-")[1]);
dayC = Integer.parseInt(currentDate.split("-")[2]);
jumpMonth = 0;
jumpYear = 0;
//設(shè)置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) {
// 像左滑動(dòng)
enterNextMonth();
return true;
} else if (e1.getX() - e2.getX() < -120) {
// 向右滑動(dòng)
enterPrevMonth();
return true;
}
return false;
}
}
/**
* 移動(dòng)到下一個(gè)月
*
*/
private void enterNextMonth() {
addGridView(); // 添加一個(gè)gridView
jumpMonth++; // 下一個(gè)月
calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
gvCalendar.setAdapter(calV);
addTextToTopTextView(currentMonthTv); // 移動(dòng)到下一月后,將當(dāng)月顯示在頭標(biāo)題中
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);
}
/**
* 移動(dòng)到上一個(gè)月
*
*/
private void enterPrevMonth() {
addGridView(); // 添加一個(gè)gridView
jumpMonth--; // 上一個(gè)月
calV = new CalendarAdapter(mContext, mContext.getResources(), jumpMonth, jumpYear, yearC, monthC, dayC);
gvCalendar.setAdapter(calV);
addTextToTopTextView(currentMonthTv); // 移動(dòng)到上一月后,將當(dāng)月顯示在頭標(biāo)題中
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
// 點(diǎn)擊任何一個(gè)item,得到這個(gè)item的日期(排除點(diǎn)擊的是周日到周六(點(diǎn)擊不響應(yīng)))
int startPosition = calV.getStartPosition();
int endPosition = calV.getEndPosition();
if (startPosition <= position + 7 && position <= endPosition - 7) {
String scheduleDay = calV.getDateByClickItem(position); // 這一天的陽(yáng)歷
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: // 下一個(gè)月
enterNextMonth();
break;
case R.id.prevMonth: // 上一個(gè)月
enterPrevMonth();
break;
default:
break;
}
}
/**
* 顯示popWindow
*/
public void showPopupWindow(View parent) {
if (!this.isShowing()) {
// 以下拉方式顯示popupwindow
this.showAsDropDown(parent);
} else {
this.dismiss();
}
}
}
日歷的內(nèi)容是一個(gè)GridView,可以自定義類似簽到效果的圖標(biāo)
<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; // 某月的天數(shù)
private int dayOfWeek = 0; // 具體某一天是星期幾
private int lastDaysOfMonth = 0; // 上一個(gè)月的總天數(shù)
private Context context;
private String[] dayNumber = new String[42]; // 一個(gè)gridview中的日期存入此數(shù)組中
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; // 用于標(biāo)記當(dāng)天
private String showYear = ""; // 用于在頭部顯示的年份
private String showMonth = ""; // 用于在頭部顯示的月份
// 系統(tǒng)當(dāng)前時(shí)間
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); // 當(dāng)期日期
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) {
// 往下一個(gè)月滑動(dòng)
if (stepMonth % 12 == 0) {
stepYear = year_c + stepMonth / 12 - 1;
stepMonth = 12;
} else {
stepYear = year_c + stepMonth / 12;
stepMonth = stepMonth % 12;
}
} else {
// 往上一個(gè)月滑動(dòng)
stepYear = year_c - 1 + stepMonth / 12;
stepMonth = stepMonth % 12 + 12;
if (stepMonth % 12 == 0) {
}
}
currentYear = String.valueOf(stepYear); // 得到當(dāng)前的年份
currentMonth = String.valueOf(stepMonth); // 得到本月
// (jumpMonth為滑動(dòng)的次數(shù),每滑動(dòng)一次就增加一月或減一月)
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);// 字體設(shè)黑
if (position % 7 == 0 || position % 7 == 6) {
// 當(dāng)前月信息顯示
textView.setTextColor(res.getColor(R.color.green));// 周末字體設(shè)綠色
}
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))) {
// 當(dāng)前月信息顯示
int a[] = {2, 6, 29};//每個(gè)月不標(biāo)記的天數(shù)
for (int i = 0; i < a.length; i++) {
if (position == a[i]+dayOfWeek-1) {
textView.setBackgroundColor(res.getColor(R.color.yellow));//為寫(xiě)日記日期填充黃色
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) {
// 設(shè)置本月當(dāng)天之后的背景
textView.setBackgroundColor(res.getColor(R.color.bg_gray));//全部填充灰色
ivPen.setVisibility(View.INVISIBLE);
}
if (currentFlag == position) {
//設(shè)置當(dāng)天的背景
textView.setBackgroundColor(res.getColor(R.color.blue));
textView.setTextColor(Color.WHITE);
}
return convertView;
}
// 得到某年的某月的天數(shù)且這月的第一天是星期幾
public void getCalendar(int year, int month) {
isLeapYear = sc.isLeapYear(year); // 是否為閏年
daysOfMonth = sc.getDaysOfMonth(isLeapYear, month); // 某月的總天數(shù)
dayOfWeek = sc.getWeekdayOfMonth(year, month); // 某月第一天為星期幾
lastDaysOfMonth = sc.getDaysOfMonth(isLeapYear, month - 1); // 上一個(gè)月的總天數(shù)
getWeek(year, month);
}
// 將一個(gè)月中的每一天的值添加入數(shù)組dayNuber中
private void getWeek(int year, int month) {
int j = 1;
// 得到當(dāng)前月的所有日程日期(這些日期需要標(biāo)記)
for (int i = 0; i < dayNumber.length; i++) {
if (i < dayOfWeek) { // 前一個(gè)月
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 + "";
// 對(duì)于當(dāng)前月才去標(biāo)記當(dāng)前日期
if (sys_year.equals(String.valueOf(year)) && sys_month.equals(String.valueOf(month)) && sys_day.equals(day)) {
// 標(biāo)記當(dāng)前日期
currentFlag = i;
}
setShowYear(String.valueOf(year));
setShowMonth(String.valueOf(month));
} else { // 下一個(gè)月
dayNumber[i] = j + "";
j++;
}
}
}
/**
* 點(diǎn)擊每一個(gè)item時(shí)返回item中的日期
* @param position
* @return
*/
public String getDateByClickItem(int position) {
return dayNumber[position];
}
/**
* 在點(diǎn)擊gridView時(shí),得到這個(gè)月中第一天的位置
* @return
*/
public int getStartPosition() {
return dayOfWeek + 7;
}
/**
* 在點(diǎn)擊gridView時(shí),得到這個(gè)月中最后一天的位置
* @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點(diǎn)擊顯示日歷,可以指定PopWindow在哪一個(gè)控件的下方出現(xiàn)
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);
}
});
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義控件實(shí)現(xiàn)可左右滑動(dòng)的導(dǎo)航條
- Android控件之SlidingDrawer(滑動(dòng)式抽屜)詳解與實(shí)例分享
- Android開(kāi)源堆疊滑動(dòng)控件仿探探效果
- Android自定義控件ScrollView實(shí)現(xiàn)上下滑動(dòng)功能
- Android控件SeekBar仿淘寶滑動(dòng)驗(yàn)證效果
- Android自定義View實(shí)現(xiàn)隨手勢(shì)滑動(dòng)控件
- Android仿微信列表滑動(dòng)刪除之可滑動(dòng)控件(一)
- Android自定義滑動(dòng)解鎖控件使用詳解
- Android自定義控件實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)效果
- Android自定義雙向滑動(dòng)控件
相關(guān)文章
Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼
這篇文章主要介紹了Android輸入框?qū)崟r(shí)模糊搜索效果的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Android RecyclerView顯示Item布局不一致解決辦法
這篇文章主要介紹了Android RecyclerView顯示Item布局不一致解決辦法的相關(guān)資料,需要的朋友可以參考下2017-07-07
Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法
這篇文章主要介紹了Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法,實(shí)例分析了Android操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-06-06
關(guān)于Android中自定義ClassLoader耗時(shí)問(wèn)題的追查
熱修復(fù)和插件化是目前比較熱門的技術(shù),要想更好的掌握它們需要了解ClassLoader,下面這篇文章主要給大家介紹了關(guān)于Android中自定義ClassLoader耗時(shí)問(wèn)題追查的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧2018-06-06
如何在Android中實(shí)現(xiàn)左右滑動(dòng)的指引效果
本篇文章是對(duì)在Android中實(shí)現(xiàn)左右滑動(dòng)指引效果的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法,以實(shí)例形式較為詳細(xì)的分析了添加數(shù)據(jù)到Intent的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
Android開(kāi)發(fā)中多進(jìn)程共享數(shù)據(jù)簡(jiǎn)析
這篇文章主要為大家簡(jiǎn)單分析Android開(kāi)發(fā)中多進(jìn)程共享數(shù)據(jù),怎么做才能讓這兩邊共享數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-04-04
Android基礎(chǔ)開(kāi)發(fā)之手勢(shì)識(shí)別
這篇文章主要為大家詳細(xì)介紹了Android基礎(chǔ)開(kāi)發(fā)之手勢(shì)識(shí)別的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-06-06

