当前位置:   article > 正文

Android自定义日期滚动控件_datechoosewheelview

datechoosewheelview

今天公司让做一个滚动选择日期的功能,在网上搜到了很多,但一放到自己的项目中就变成了按钮点击的效果,后来发现只要设置Theme滚动效果就会消失。

滚动控件参考:

http://www.cnblogs.com/tiantianbyconan/p/3819304.html

https://github.com/wangjiegulu/WheelView

源代码中还需要引入两个依赖工程,这里通过提取依赖工程的代码对其进行了简化。

1、滚动控件WheelView代码:

  1. package com.cx.datechoosedialog;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.app.Activity;
  5. import android.content.Context;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.ColorFilter;
  9. import android.graphics.Paint;
  10. import android.graphics.drawable.Drawable;
  11. import android.util.AttributeSet;
  12. import android.util.TypedValue;
  13. import android.view.Gravity;
  14. import android.view.MotionEvent;
  15. import android.view.ViewGroup;
  16. import android.widget.LinearLayout;
  17. import android.widget.ScrollView;
  18. import android.widget.TextView;
  19. /**
  20. * Author: wangjie
  21. * Email: tiantian.china.2@gmail.com
  22. * Date: 7/1/14.
  23. */
  24. public class WheelView extends ScrollView {
  25. public static final String TAG = WheelView.class.getSimpleName();
  26. public static class OnWheelViewListener {
  27. public void onSelected(int selectedIndex, String item) {
  28. }
  29. ;
  30. }
  31. private Context context;
  32. // private ScrollView scrollView;
  33. private LinearLayout views;
  34. public WheelView(Context context) {
  35. super(context);
  36. init(context);
  37. }
  38. public WheelView(Context context, AttributeSet attrs) {
  39. super(context, attrs);
  40. init(context);
  41. }
  42. public WheelView(Context context, AttributeSet attrs, int defStyle) {
  43. super(context, attrs, defStyle);
  44. init(context);
  45. }
  46. // String[] items;
  47. List<String> items;
  48. private List<String> getItems() {
  49. return items;
  50. }
  51. public void setItems(List<String> list) {
  52. // if (null == items) {
  53. items = new ArrayList<String>();
  54. // }
  55. items.clear();
  56. items.addAll(list);
  57. // 前面和后面补全
  58. for (int i = 0; i < offset; i++) {
  59. items.add(0, "");
  60. items.add("");
  61. }
  62. initData();
  63. }
  64. public static final int OFF_SET_DEFAULT = 1;
  65. int offset = OFF_SET_DEFAULT; // 偏移量(需要在最前面和最后面补全)
  66. public int getOffset() {
  67. return offset;
  68. }
  69. public void setOffset(int offset) {
  70. this.offset = offset;
  71. }
  72. int displayItemCount; // 每页显示的数量
  73. int selectedIndex = 1;
  74. private void init(Context context) {
  75. this.context = context;
  76. this.setVerticalScrollBarEnabled(false);
  77. views = new LinearLayout(context);
  78. views.setOrientation(LinearLayout.VERTICAL);
  79. this.addView(views);
  80. scrollerTask = new Runnable() {
  81. public void run() {
  82. int newY = getScrollY();
  83. if (initialY - newY == 0) { // stopped
  84. final int remainder = initialY % itemHeight;
  85. final int divided = initialY / itemHeight;
  86. if (remainder == 0) {
  87. selectedIndex = divided + offset;
  88. onSeletedCallBack();
  89. } else {
  90. if (remainder > itemHeight / 2) {
  91. WheelView.this.post(new Runnable() {
  92. @Override
  93. public void run() {
  94. WheelView.this.smoothScrollTo(0, initialY - remainder + itemHeight);
  95. selectedIndex = divided + offset + 1;
  96. onSeletedCallBack();
  97. }
  98. });
  99. } else {
  100. WheelView.this.post(new Runnable() {
  101. @Override
  102. public void run() {
  103. WheelView.this.smoothScrollTo(0, initialY - remainder);
  104. selectedIndex = divided + offset;
  105. onSeletedCallBack();
  106. }
  107. });
  108. }
  109. }
  110. } else {
  111. initialY = getScrollY();
  112. WheelView.this.postDelayed(scrollerTask, newCheck);
  113. }
  114. }
  115. };
  116. }
  117. int initialY;
  118. Runnable scrollerTask;
  119. int newCheck = 50;
  120. public void startScrollerTask() {
  121. initialY = getScrollY();
  122. this.postDelayed(scrollerTask, newCheck);
  123. }
  124. private void initData() {
  125. views.removeAllViews();
  126. displayItemCount = offset * 2 + 1;
  127. for (String item : items) {
  128. views.addView(createView(item));
  129. }
  130. refreshItemView(0);
  131. }
  132. int itemHeight = 0;
  133. private TextView createView(String item) {
  134. TextView tv = new TextView(context);
  135. tv.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
  136. tv.setSingleLine(true);
  137. tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
  138. tv.setText(item);
  139. tv.setGravity(Gravity.CENTER);
  140. int padding = Utility.dip2px(context, 15);
  141. tv.setPadding(padding, padding, padding, padding);
  142. if (0 == itemHeight) {
  143. itemHeight = Utility.getViewMeasuredHeight(tv);
  144. views.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight * displayItemCount));
  145. LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
  146. this.setLayoutParams(new LinearLayout.LayoutParams(lp.width, itemHeight * displayItemCount));
  147. }
  148. return tv;
  149. }
  150. @Override
  151. protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  152. super.onScrollChanged(l, t, oldl, oldt);
  153. refreshItemView(t);
  154. if (t > oldt) {
  155. // Logger.d(TAG, "向下滚动");
  156. scrollDirection = SCROLL_DIRECTION_DOWN;
  157. } else {
  158. // Logger.d(TAG, "向上滚动");
  159. scrollDirection = SCROLL_DIRECTION_UP;
  160. }
  161. }
  162. private void refreshItemView(int y) {
  163. int position = y / itemHeight + offset;
  164. int remainder = y % itemHeight;
  165. int divided = y / itemHeight;
  166. if (remainder == 0) {
  167. position = divided + offset;
  168. } else {
  169. if (remainder > itemHeight / 2) {
  170. position = divided + offset + 1;
  171. }
  172. }
  173. int childSize = views.getChildCount();
  174. for (int i = 0; i < childSize; i++) {
  175. TextView itemView = (TextView) views.getChildAt(i);
  176. if (null == itemView) {
  177. return;
  178. }
  179. if (position == i) {
  180. itemView.setTextColor(Color.parseColor("#0288ce"));
  181. } else {
  182. itemView.setTextColor(Color.parseColor("#bbbbbb"));
  183. }
  184. }
  185. }
  186. /**
  187. * 获取选中区域的边界
  188. */
  189. int[] selectedAreaBorder;
  190. private int[] obtainSelectedAreaBorder() {
  191. if (null == selectedAreaBorder) {
  192. selectedAreaBorder = new int[2];
  193. selectedAreaBorder[0] = itemHeight * offset;
  194. selectedAreaBorder[1] = itemHeight * (offset + 1);
  195. }
  196. return selectedAreaBorder;
  197. }
  198. private int scrollDirection = -1;
  199. private static final int SCROLL_DIRECTION_UP = 0;
  200. private static final int SCROLL_DIRECTION_DOWN = 1;
  201. Paint paint;
  202. int viewWidth;
  203. @Override
  204. public void setBackgroundDrawable(Drawable background) {
  205. if (viewWidth == 0) {
  206. viewWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
  207. }
  208. if (null == paint) {
  209. paint = new Paint();
  210. paint.setColor(Color.parseColor("#83cde6"));
  211. paint.setStrokeWidth(Utility.dip2px(context, 1f));
  212. }
  213. background = new Drawable() {
  214. @Override
  215. public void draw(Canvas canvas) {
  216. canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[0], viewWidth * 5 / 6, obtainSelectedAreaBorder()[0], paint);
  217. canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[1], viewWidth * 5 / 6, obtainSelectedAreaBorder()[1], paint);
  218. }
  219. @Override
  220. public void setAlpha(int alpha) {
  221. }
  222. @Override
  223. public void setColorFilter(ColorFilter cf) {
  224. }
  225. @Override
  226. public int getOpacity() {
  227. return 0;
  228. }
  229. };
  230. super.setBackgroundDrawable(background);
  231. }
  232. @Override
  233. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  234. super.onSizeChanged(w, h, oldw, oldh);
  235. viewWidth = w;
  236. setBackgroundDrawable(null);
  237. }
  238. /**
  239. * 选中回调
  240. */
  241. private void onSeletedCallBack() {
  242. if (null != onWheelViewListener) {
  243. onWheelViewListener.onSelected(selectedIndex, items.get(selectedIndex));
  244. }
  245. }
  246. public void setSeletion(int position) {
  247. final int p = position;
  248. selectedIndex = p + offset;
  249. this.post(new Runnable() {
  250. @Override
  251. public void run() {
  252. WheelView.this.smoothScrollTo(0, p * itemHeight);
  253. }
  254. });
  255. }
  256. public String getSeletedItem() {
  257. return items.get(selectedIndex);
  258. }
  259. public int getSeletedIndex() {
  260. return selectedIndex - offset;
  261. }
  262. @Override
  263. public void fling(int velocityY) {
  264. super.fling(velocityY / 3);
  265. }
  266. @Override
  267. public boolean onTouchEvent(MotionEvent ev) {
  268. if (ev.getAction() == MotionEvent.ACTION_UP) {
  269. startScrollerTask();
  270. }
  271. return super.onTouchEvent(ev);
  272. }
  273. private OnWheelViewListener onWheelViewListener;
  274. public OnWheelViewListener getOnWheelViewListener() {
  275. return onWheelViewListener;
  276. }
  277. public void setOnWheelViewListener(OnWheelViewListener onWheelViewListener) {
  278. this.onWheelViewListener = onWheelViewListener;
  279. }
  280. }
2、依赖工程中提取的方法
  1. package com.cx.datechoosedialog;
  2. import java.text.ParseException;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Calendar;
  5. import java.util.Date;
  6. import android.annotation.SuppressLint;
  7. import android.content.Context;
  8. import android.view.View;
  9. @SuppressLint("SimpleDateFormat")
  10. public class Utility {
  11. /**
  12. * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
  13. */
  14. public static int dip2px(Context context, float dpValue) {
  15. final float scale = context.getResources().getDisplayMetrics().density;
  16. return (int) (dpValue * scale + 0.5f);
  17. }
  18. /**
  19. * 获取控件的高度,如果获取的高度为0,则重新计算尺寸后再返回高度
  20. *
  21. * @param view
  22. * @return
  23. */
  24. public static int getViewMeasuredHeight(View view) {
  25. calcViewMeasure(view);
  26. return view.getMeasuredHeight();
  27. }
  28. /**
  29. * 测量控件的尺寸
  30. *
  31. * @param view
  32. */
  33. public static void calcViewMeasure(View view) {
  34. int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
  35. int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
  36. view.measure(width, expandSpec);
  37. }
  38. public static String dateFormat(Date date) {
  39. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
  40. return sdf.format(date);
  41. }
  42. public static String dateFormatDay(Date date) {
  43. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  44. return sdf.format(date);
  45. }
  46. /****
  47. * 获取月末最后一天
  48. *
  49. * @param sDate
  50. * 2014-11-24
  51. * @return 30
  52. */
  53. public static String getMonthMaxDay(String sDate) {
  54. SimpleDateFormat sdf_full = new SimpleDateFormat("yyyy-MM-dd");
  55. Calendar cal = Calendar.getInstance();
  56. Date date = null;
  57. try {
  58. date = sdf_full.parse(sDate + "-01");
  59. } catch (ParseException e) {
  60. e.printStackTrace();
  61. }
  62. cal.setTime(date);
  63. int last = cal.getActualMaximum(Calendar.DATE);
  64. return String.valueOf(last);
  65. }
  66. }
通过自定义Dialog实现日期选择控件,这里也可以控制日期的可选范围

  1. package com.cx.datechoosedialog;
  2. import java.util.ArrayList;
  3. import java.util.Date;
  4. import java.util.List;
  5. import android.annotation.SuppressLint;
  6. import android.app.Dialog;
  7. import android.content.Context;
  8. import android.content.DialogInterface;
  9. import android.view.LayoutInflater;
  10. import android.view.View;
  11. import android.view.ViewGroup.LayoutParams;
  12. import android.widget.Button;
  13. import android.widget.TextView;
  14. import com.cx.datechoosedialog.WheelView.OnWheelViewListener;
  15. public class DateChooseDialog extends Dialog {
  16. public DateChooseDialog(Context context) {
  17. super(context);
  18. // TODO Auto-generated constructor stub
  19. }
  20. public DateChooseDialog(Context context, int theme) {
  21. super(context, theme);
  22. }
  23. @SuppressLint("NewApi")
  24. public static class Builder{
  25. private Context context;
  26. private String title;
  27. private int yearsSeletion;
  28. private int monthSeletion;
  29. private int daySeletion;
  30. private List<String> yearsItems;
  31. private List<String> monthItems;
  32. private List<String> dayItems;
  33. private TextView textView;
  34. private TextView tvTime;
  35. private WheelView wheelView1, wheelView2, wheelView3;
  36. private Button positiveButton, negativeButton;
  37. private DialogInterface.OnClickListener positiveButtonClickListener;
  38. private DialogInterface.OnClickListener negativeButtonClickListener;
  39. private String years;
  40. private String month;
  41. private String day;
  42. public Builder(Context context) {
  43. this.context = context;
  44. yearsItems = new ArrayList<String>();
  45. monthItems = new ArrayList<String>();
  46. dayItems = new ArrayList<String>();
  47. String date = Utility.dateFormatDay(new Date());
  48. years = date.split("-")[0];
  49. month = date.split("-")[1];
  50. day = date.split("-")[2];
  51. for(int i = 2000; i < 2030; i++){
  52. yearsItems.add(i + "");
  53. }
  54. for(int i = 0; i < 12; i++){
  55. if(1 + i < 10){
  56. monthItems.add("0" + (1 + i));
  57. }else{
  58. monthItems.add(1 + i + "");
  59. }
  60. }
  61. for(int i = 0; i < Integer.valueOf(Utility.getMonthMaxDay(Utility.dateFormat(new Date()))); i++){
  62. if(1 + i < 10){
  63. dayItems.add("0" + (1 + i));
  64. }else{
  65. dayItems.add(1 + i + "");
  66. }
  67. }
  68. yearsSeletion = Integer.valueOf(date.split("-")[0]) - 2000;
  69. monthSeletion = Integer.valueOf(date.split("-")[1]) - 1;
  70. daySeletion = Integer.valueOf(date.split("-")[2]) - 1;
  71. }
  72. /**
  73. * Set the Dialog title from resource
  74. *
  75. * @param title
  76. * @return
  77. */
  78. public Builder setTitle(int title) {
  79. this.title = (String) context.getText(title);
  80. return this;
  81. }
  82. /**
  83. * Set the Dialog title from String
  84. *
  85. * @param title
  86. * @return
  87. */
  88. public Builder setTitle(String title) {
  89. this.title = title;
  90. return this;
  91. }
  92. public Builder setYearsItems(List<String> list){
  93. this.yearsItems = list;
  94. return this;
  95. }
  96. public Builder setMonthItems(List<String> list){
  97. this.monthItems = list;
  98. return this;
  99. }
  100. public Builder setTextView(TextView tv) {
  101. this.textView = tv;
  102. return this;
  103. }
  104. /**
  105. * Set the positive button resource and it's listener
  106. *
  107. * @param positiveButtonText
  108. * @return
  109. */
  110. public Builder setPositiveButton(int positiveButtonText,
  111. DialogInterface.OnClickListener listener) {
  112. this.positiveButtonClickListener = listener;
  113. return this;
  114. }
  115. public Builder setPositiveButton(String positiveButtonText,
  116. DialogInterface.OnClickListener listener) {
  117. this.positiveButtonClickListener = listener;
  118. return this;
  119. }
  120. public Builder setNegativeButton(int negativeButtonText,
  121. DialogInterface.OnClickListener listener) {
  122. this.negativeButtonClickListener = listener;
  123. return this;
  124. }
  125. public Builder setNegativeButton(String negativeButtonText,
  126. DialogInterface.OnClickListener listener) {
  127. this.negativeButtonClickListener = listener;
  128. return this;
  129. }
  130. public DateChooseDialog create() {
  131. LayoutInflater inflater = (LayoutInflater) context
  132. .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  133. // instantiate the dialog with the custom Theme
  134. final DateChooseDialog dialog = new DateChooseDialog(context, R.style.Dialog);
  135. View layout = inflater.inflate(R.layout.date_choose_dialog, null);
  136. tvTime = (TextView) layout.findViewById(R.id.title);
  137. wheelView1 = (WheelView)layout.findViewById(R.id.wheelview1);
  138. wheelView2 = (WheelView)layout.findViewById(R.id.wheelview2);
  139. wheelView3 = (WheelView)layout.findViewById(R.id.wheelview3);
  140. positiveButton = (Button) layout.findViewById(R.id.positiveButton);
  141. negativeButton = (Button) layout.findViewById(R.id.negativeButton);
  142. dialog.addContentView(layout, new LayoutParams(
  143. LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
  144. // set the dialog title
  145. tvTime.setText(title);
  146. // set the confirm button
  147. positiveButton.setOnClickListener(new View.OnClickListener() {
  148. public void onClick(View v) {
  149. textView.setText(years + "-"
  150. + month + "-"
  151. + day);
  152. positiveButtonClickListener.onClick(dialog,
  153. DialogInterface.BUTTON_POSITIVE);
  154. }
  155. });
  156. negativeButton.setOnClickListener(new View.OnClickListener() {
  157. public void onClick(View v) {
  158. negativeButtonClickListener.onClick(dialog,
  159. DialogInterface.BUTTON_NEGATIVE);
  160. }
  161. });
  162. // set the content message
  163. wheelView1.setOffset(1);
  164. wheelView1.setItems(yearsItems);
  165. wheelView1.setSeletion(yearsSeletion);
  166. wheelView1.setOnWheelViewListener(new OnWheelViewListener(){
  167. public void onSelected(int selectedIndex, String item) {
  168. years = item;
  169. wheelView2.setItems(monthItems);
  170. ArrayList<String> items = new ArrayList<String>();
  171. for(int i = 0; i < Integer.valueOf(Utility.getMonthMaxDay(years + "-" + month)); i++){
  172. if(1 + i < 10){
  173. items.add("0" + (1 + i));
  174. }else{
  175. items.add(1 + i + "");
  176. }
  177. }
  178. wheelView3.setItems(items);
  179. }
  180. });
  181. wheelView2.setOffset(1);
  182. wheelView2.setItems(monthItems);
  183. wheelView2.setSeletion(monthSeletion);
  184. wheelView2.setOnWheelViewListener(new OnWheelViewListener(){
  185. public void onSelected(int selectedIndex, String item) {
  186. month = item;
  187. int maxDay = Integer.valueOf(Utility.getMonthMaxDay(years + "-" + item));
  188. ArrayList<String> items = new ArrayList<String>();
  189. for(int i = 0; i < maxDay; i++){
  190. if(1 + i < 10){
  191. items.add("0" + (1 + i));
  192. }else{
  193. items.add(1 + i + "");
  194. }
  195. }
  196. wheelView3.setItems(items);
  197. if(Integer.valueOf(day) > maxDay){
  198. day = maxDay + "";
  199. wheelView3.setSeletion(maxDay);
  200. }
  201. }
  202. });
  203. wheelView3.setOffset(1);
  204. wheelView3.setItems(dayItems);
  205. wheelView3.setSeletion(daySeletion);
  206. wheelView3.setOnWheelViewListener(new OnWheelViewListener(){
  207. public void onSelected(int selectedIndex, String item) {
  208. day = item;
  209. }
  210. });
  211. dialog.setContentView(layout);
  212. return dialog;
  213. }
  214. }
  215. }
弹出日期选择框代码
  1. package com.cx.datechoosedialog;
  2. import android.content.DialogInterface;
  3. import android.os.Bundle;
  4. import android.support.v7.app.ActionBarActivity;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import android.widget.TextView;
  8. public class MainActivity extends ActionBarActivity {
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. findViewById(R.id.text).setOnClickListener(new OnClickListener() {
  14. @Override
  15. public void onClick(View arg0) {
  16. // TODO Auto-generated method stub
  17. DateChooseDialog.Builder builder = new DateChooseDialog.Builder(MainActivity.this);
  18. builder.setTitle("选择日期");
  19. builder.setTextView((TextView)findViewById(R.id.text));
  20. builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
  21. public void onClick(DialogInterface dialog, int which) {
  22. dialog.dismiss();
  23. //设置你的操作事项
  24. }
  25. });
  26. builder.setNegativeButton("取消",
  27. new android.content.DialogInterface.OnClickListener() {
  28. public void onClick(DialogInterface dialog, int which) {
  29. dialog.dismiss();
  30. }
  31. });
  32. builder.create().show();
  33. }
  34. });
  35. }
  36. }
效果图:


源码下载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/278829
推荐阅读
相关标签
  

闽ICP备14008679号