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,可以自定義類(lèi)似簽到效果的圖標(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-08Android RecyclerView顯示Item布局不一致解決辦法
這篇文章主要介紹了Android RecyclerView顯示Item布局不一致解決辦法的相關(guān)資料,需要的朋友可以參考下2017-07-07Android實(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ù)和插件化是目前比較熱門(mén)的技術(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-06Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法,以實(shí)例形式較為詳細(xì)的分析了添加數(shù)據(jù)到Intent的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09Android開(kāi)發(fā)中多進(jìn)程共享數(shù)據(jù)簡(jiǎn)析
這篇文章主要為大家簡(jiǎn)單分析Android開(kāi)發(fā)中多進(jìn)程共享數(shù)據(jù),怎么做才能讓這兩邊共享數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-04-04Android基礎(chǔ)開(kāi)發(fā)之手勢(shì)識(shí)別
這篇文章主要為大家詳細(xì)介紹了Android基礎(chǔ)開(kāi)發(fā)之手勢(shì)識(shí)別的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-06-06