美文网首页编程设计之Android
安卓开发-高仿ios时间选择控件timepicker

安卓开发-高仿ios时间选择控件timepicker

作者: 庞哈哈哈12138 | 来源:发表于2017-06-20 15:36 被阅读5714次

    在开发中如果有地址或者日期选择等就会涉及到时间或者条件选择器,大家都会想到仿iOS的三级联动的效果,用wheelview实现,其实安卓原生自带了时间和日期选择器可能是效果来说太粗犷了,所以很多产品效果图都是清一色的ios那种效果,ok,废话说完了上图


    demo地址:https://github.com/PangHaHa12138/TimePackdemo

    1,安卓原生的时间和日期选择器

    代码:

    DatePickerDialog dialog = new
            DatePickerDialog(MainActivity.this, new DatePickerDialog.OnDateSetListener() {
                @Override
                public void onDateSet(DatePicker view, int year, int monthOfYear, int
                        dayOfMonth) {
    
                    if(monthOfYear<=9){
                        mouth1="0"+(monthOfYear+1);
                    }else{
                        mouth1=String.valueOf(monthOfYear+1);
                    }
                    if(dayOfMonth<=9){
                        day1= "0"+dayOfMonth;
                    }else{
                        day1=String.valueOf(dayOfMonth);
                    }
                    dateStr = String.valueOf(year)+"-"+mouth1+"-"+day1;
                    button1.setText(dateStr);
    
    
                }
            }, calender.get(Calendar.YEAR), calender.get(Calendar.MONTH),
            calender.get(Calendar.DAY_OF_MONTH));
    dialog.show();
    

    使用非常简单,自己写个时间过滤方法就行

    TimePickerDialog dialog = new TimePickerDialog(MainActivity.this, 
    new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
    
            button2.setText(String.valueOf(hourOfDay+":"+minute));
    
        }
    },calender2.get(Calendar.HOUR),calender2.get(Calendar.MINUTE),false);
    dialog.show();
    

    DatePickerDialog和TimePickerDialog都是原生带的,在5.0之前还是和ios那种效果差不多,来回上下滑选择日期的,但是5.0后就成日历了,虽然好看,不过占比屏太大,设计并不会考虑这种效果,哎,现在很多安卓的控件原生其实效果不错的,不过还是得为了遵循产品和设计的意思做成仿ios效果(小小的抱怨一下)

    2.开源日期选择器Timepickview和条件选择器Optionspickview

    代码:timepick:

    TimePickerView pvTime = new TimePickerView.Builder(MainActivity.this, new TimePickerView.OnTimeSelectListener() {
                        @Override
                        public void onTimeSelect(Date date2, View v) {//选中事件回调
                            String time = getTime(date2);
                           button3.setText(time);
                        }
                    })
                            .setType(TimePickerView.Type.YEAR_MONTH_DAY)//默认全部显示
                            .setCancelText("取消")//取消按钮文字
                            .setSubmitText("确定")//确认按钮文字
                            .setContentSize(20)//滚轮文字大小
                            .setTitleSize(20)//标题文字大小
    //                        .setTitleText("请选择时间")//标题文字
                            .setOutSideCancelable(true)//点击屏幕,点在控件外部范围时,是否取消显示
                            .isCyclic(true)//是否循环滚动
                            .setTextColorCenter(Color.BLACK)//设置选中项的颜色
                            .setTitleColor(Color.BLACK)//标题文字颜色
                            .setSubmitColor(Color.BLUE)//确定按钮文字颜色
                            .setCancelColor(Color.BLUE)//取消按钮文字颜色
    //                        .setTitleBgColor(0xFF666666)//标题背景颜色 Night mode
    //                        .setBgColor(0xFF333333)//滚轮背景颜色 Night mode
    //                        .setRange(calendar.get(Calendar.YEAR) - 20, calendar.get(Calendar.YEAR) + 20)//默认是1900-2100年
    //                        .setDate(selectedDate)// 如果不设置的话,默认是系统时间*/
    //                        .setRangDate(startDate,endDate)//起始终止年月日设定
    //                        .setLabel("年","月","日","时","分","秒")
                            .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
    //                        .isDialog(true)//是否显示为对话框样式
                            .build();
                    pvTime.setDate(Calendar.getInstance());//注:根据需求来决定是否使用该方法(一般是精确到秒的情况),此项可以在弹出选择器的时候重新设置当前时间,避免在初始化之后由于时间已经设定,导致选中时间与当前时间不匹配的问题。
                    pvTime.show();
    

    注释已经写的很详细了,各种选项干嘛用的
    Optionspickview:代码:

    options1Items.clear();
    options1Items.add("托儿索");
    options1Items.add("儿童劫");
    options1Items.add("小学生之手");
    options1Items.add("德玛西亚大保健");
    options1Items.add("面对疾风吧");
    options1Items.add("天王盖地虎");
    options1Items.add("我发一米五");
    options1Items.add("爆刘继芬");
    
    OptionsPickerView pvOptions = new  OptionsPickerView.Builder(MainActivity.this, new OptionsPickerView.OnOptionsSelectListener() {
                        @Override
                        public void onOptionsSelect(int options1, int option2, int options3 ,View v) {
                            //返回的分别是三个级别的选中位置
                           String s =  options1Items.get(options1);
                            button4.setText(s);
    
                        }
                    })
    //                        .setSubmitText("确定")//确定按钮文字
    //                        .setCancelText("取消")//取消按钮文字
    //                        .setTitleText("城市选择")//标题
                            .setSubCalSize(20)//确定和取消文字大小
    //                        .setTitleSize(20)//标题文字大小
    //                        .setTitleColor(Color.BLACK)//标题文字颜色
                            .setSubmitColor(Color.BLUE)//确定按钮文字颜色
                            .setCancelColor(Color.BLUE)//取消按钮文字颜色
    //                        .setTitleBgColor(0xFF333333)//标题背景颜色 Night mode
    //                        .setBgColor(0xFF000000)//滚轮背景颜色 Night mode
    //                        .setContentTextSize(18)//滚轮文字大小
    //                        .setTextColorCenter(Color.BLUE)//设置选中项的颜色
                            .setTextColorCenter(Color.BLACK)//设置选中项的颜色
    //                        .setLineSpacingMultiplier(1.6f)//设置两横线之间的间隔倍数
    //                        .setLinkage(false)//设置是否联动,默认true
    //                        .setLabels("省", "市", "区")//设置选择的三级单位
    //                        .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
    //                        .setCyclic(false, false, false)//循环与否
    //                        .setSelectOptions(1, 1, 1)  //设置默认选中项
    //                        .setOutSideCancelable(false)//点击外部dismiss default true
    //                        .isDialog(true)//是否显示为对话框样式
                            .build();
                    pvOptions.setPicker(options1Items);
                    pvOptions.show();
    

    条件自己定义,可以传简单集合,也可以传别的,比如省市县...

    3.结合wheelview和原生timepick自定义时间选择器

    用法:

    final String[] str = new String[10];
    ChangeDatePopwindow mChangeBirthDialog = new ChangeDatePopwindow(MainActivity.this);
    mChangeBirthDialog.setDate("2017", "6", "20");
    mChangeBirthDialog.showAtLocation(main, Gravity.BOTTOM, 0, 0);
    mChangeBirthDialog.setBirthdayListener(new ChangeDatePopwindow.OnBirthListener() {
    
        @Override
        public void onClick(String year, String month, String day) {
            // TODO Auto-generated method stub
            Toast.makeText(MainActivity.this,year + "-" + month + "-" + day,Toast.LENGTH_LONG).show();
            StringBuilder sb = new StringBuilder();
            sb.append(year.substring(0, year.length() - 1)).append("-").append(month.substring(0, day.length() - 1)).append("-").append(day);
            str[0] = year + "-" + month + "-" + day;
            str[1] = sb.toString();
    
            button5.setText(str[0]);
    
        }
    });
    

    大致思路:
    年-月-日,其实是三个wheelview,然后手动设置时间的范围,继承原有的adapter
    一个例子

    * Abstract wheel adapter provides common functionality for adapters.
     */
    public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {
        
        /** Text view resource. Used as a default view for adapter. */
        public static final int TEXT_VIEW_ITEM_RESOURCE = -1;
        
        /** No resource constant. */
        protected static final int NO_RESOURCE = 0;
        
        /** Default text color */
        public static final int DEFAULT_TEXT_COLOR = 0xFF585858;
        
        /** Default text color */
        public static final int LABEL_COLOR = 0xFF700070;
        
        /** Default text size */
        public static final int DEFAULT_TEXT_SIZE = 18;
        
        // Text settings
        private int textColor = DEFAULT_TEXT_COLOR;
        private int textSize = DEFAULT_TEXT_SIZE;
        
        // Current context
        protected Context context;
        // Layout inflater
        protected LayoutInflater inflater;
        
        // Items resources
        protected int itemResourceId;
        protected int itemTextResourceId;
        
        // Empty items resources
        protected int emptyItemResourceId;
       
        /**
         * Constructor
         * @param context the current context
         */
        protected AbstractWheelTextAdapter(Context context) {
            this(context, TEXT_VIEW_ITEM_RESOURCE);
        }
    
        /**
         * Constructor
         * @param context the current context
         * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
         */
        protected AbstractWheelTextAdapter(Context context, int itemResource) {
            this(context, itemResource, NO_RESOURCE);
        }
        
        /**
         * Constructor
         * @param context the current context
         * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
         * @param itemTextResource the resource ID for a text view in the item layout
         */
        protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {
            this.context = context;
            itemResourceId = itemResource;
            itemTextResourceId = itemTextResource;
            
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }
        
        /**
         * Gets text color
         * @return the text color
         */
        public int getTextColor() {
            return textColor;
        }
        
        /**
         * Sets text color
         * @param textColor the text color to set
         */
        public void setTextColor(int textColor) {
            this.textColor = textColor;
        }
        
        /**
         * Gets text size
         * @return the text size
         */
        public int getTextSize() {
            return textSize;
        }
        
        /**
         * Sets text size
         * @param textSize the text size to set
         */
        public void setTextSize(int textSize) {
            this.textSize = textSize;
        }
        
        /**
         * Gets resource Id for items views
         * @return the item resource Id
         */
        public int getItemResource() {
            return itemResourceId;
        }
        
        /**
         * Sets resource Id for items views
         * @param itemResourceId the resource Id to set
         */
        public void setItemResource(int itemResourceId) {
            this.itemResourceId = itemResourceId;
        }
        
        /**
         * Gets resource Id for text view in item layout 
         * @return the item text resource Id
         */
        public int getItemTextResource() {
            return itemTextResourceId;
        }
        
        /**
         * Sets resource Id for text view in item layout 
         * @param itemTextResourceId the item text resource Id to set
         */
        public void setItemTextResource(int itemTextResourceId) {
            this.itemTextResourceId = itemTextResourceId;
        }
    
        /**
         * Gets resource Id for empty items views
         * @return the empty item resource Id
         */
        public int getEmptyItemResource() {
            return emptyItemResourceId;
        }
    
        /**
         * Sets resource Id for empty items views
         * @param emptyItemResourceId the empty item resource Id to set
         */
        public void setEmptyItemResource(int emptyItemResourceId) {
            this.emptyItemResourceId = emptyItemResourceId;
        }
        
        
        /**
         * Returns text for specified item
         * @param index the item index
         * @return the text of specified items
         */
        protected abstract CharSequence getItemText(int index);
    
        @Override
        public View getItem(int index, View convertView, ViewGroup parent) {
            if (index >= 0 && index < getItemsCount()) {
                if (convertView == null) {
                    convertView = getView(itemResourceId, parent);
                }
                TextView textView = getTextView(convertView, itemTextResourceId);
                if (textView != null) {
                    CharSequence text = getItemText(index);
                    if (text == null) {
                        text = "";
                    }
                    textView.setText(text);
        
                    if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
                        configureTextView(textView);
                    }
                }
                return convertView;
            }
           return null;
        }
    
        @Override
        public View getEmptyItem(View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = getView(emptyItemResourceId, parent);
            }
            if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {
                configureTextView((TextView)convertView);
            }
                
            return convertView;
       }
    
        /**
         * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.
         * @param view the text view to be configured
         */
        protected void configureTextView(TextView view) {
            view.setTextColor(textColor);
            view.setGravity(Gravity.CENTER);
            view.setTextSize(textSize);
            view.setEllipsize(TextUtils.TruncateAt.END);
            view.setLines(1);
    //        view.setCompoundDrawablePadding(20);
    //        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
        }
        
        /**
         * Loads a text view from view
         * @param view the text view or layout containing it
         * @param textResource the text resource Id in layout
         * @return the loaded text view
         */
        public TextView getTextView(View view, int textResource) {
           TextView text = null;
           try {
                if (textResource == NO_RESOURCE && view instanceof TextView) {
                    text = (TextView) view;
                } else if (textResource != NO_RESOURCE) {
                    text = (TextView) view.findViewById(textResource);
                }
            } catch (ClassCastException e) {
                Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView");
                throw new IllegalStateException(
                        "AbstractWheelAdapter requires the resource ID to be a TextView", e);
            }
            
            return text;
        }
        
        /**
         * Loads view from resources
         * @param resource the resource Id
         * @return the loaded view or null if resource is not set
         */
        public View getView(int resource, ViewGroup parent) {
            switch (resource) {
            case NO_RESOURCE:
                return null;
            case TEXT_VIEW_ITEM_RESOURCE:
                return new TextView(context);
            default:
                return inflater.inflate(resource, parent, false);    
            }
        }
    

    还有设置滑动监听,改变日期

    wvYear.addChangingListener(new OnWheelChangedListener() {
    
       @Override
       public void onChanged(WheelView wheel, int oldValue, int newValue) {
          // TODO Auto-generated method stub
          String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem());
          selectYear = currentText;
          setTextviewSize(currentText, mYearAdapter);
          currentYear = currentText.substring(0, currentText.length()-1).toString();
          Log.d("currentYear==",currentYear);
          setYear(currentYear);
          initMonths(Integer.parseInt(month));
          mMonthAdapter = new CalendarTextAdapter(context, arry_months, 0, maxTextSize, minTextSize);
          wvMonth.setVisibleItems(5);
          wvMonth.setViewAdapter(mMonthAdapter);
          wvMonth.setCurrentItem(0);
    
          calDays(currentYear, month);
       }
    });
    
    wvYear.addScrollingListener(new OnWheelScrollListener() {
    
       @Override
       public void onScrollingStarted(WheelView wheel) {
          // TODO Auto-generated method stub
    
       }
    
       @Override
       public void onScrollingFinished(WheelView wheel) {
          // TODO Auto-generated method stub
          String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem());
          setTextviewSize(currentText, mYearAdapter);
       }
    });
    
    wvMonth.addChangingListener(new OnWheelChangedListener() {
    
       @Override
       public void onChanged(WheelView wheel, int oldValue, int newValue) {
          // TODO Auto-generated method stub
          String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem());
          selectMonth = currentText;
          setTextviewSize(currentText, mMonthAdapter);
          setMonth(currentText.substring(0, 1));
          initDays(Integer.parseInt(day));
          mDaydapter = new CalendarTextAdapter(context, arry_days, 0, maxTextSize, minTextSize);
          wvDay.setVisibleItems(5);
          wvDay.setViewAdapter(mDaydapter);
          wvDay.setCurrentItem(0);
    
          calDays(currentYear, month);
       }
    });
    
    wvMonth.addScrollingListener(new OnWheelScrollListener() {
    
       @Override
       public void onScrollingStarted(WheelView wheel) {
          // TODO Auto-generated method stub
    
       }
    
       @Override
       public void onScrollingFinished(WheelView wheel) {
          // TODO Auto-generated method stub
          String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem());
          setTextviewSize(currentText, mMonthAdapter);
       }
    });
    
    wvDay.addChangingListener(new OnWheelChangedListener() {
    
       @Override
       public void onChanged(WheelView wheel, int oldValue, int newValue) {
          // TODO Auto-generated method stub
          String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem());
          setTextviewSize(currentText, mDaydapter);
          selectDay = currentText;
       }
    });
    
    wvDay.addScrollingListener(new OnWheelScrollListener() {
    
       @Override
       public void onScrollingStarted(WheelView wheel) {
          // TODO Auto-generated method stub
    
       }
    
       @Override
       public void onScrollingFinished(WheelView wheel) {
          // TODO Auto-generated method stub
          String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem());
          setTextviewSize(currentText, mDaydapter);
       }
    });
    

    然后弹出的弹窗popuwindows里,设置时间

    public String getYear() {
       Calendar c = Calendar.getInstance();
       return c.get(Calendar.YEAR)+"";
    }
    
    public String getMonth() {
       Calendar c = Calendar.getInstance();
       return c.get(Calendar.MONTH) + 1+"";
    }
    
    public String getDay() {
       Calendar c = Calendar.getInstance();
       return c.get(Calendar.DATE)+"";
    }
    
    public void initData() {
       setDate(getYear(), getMonth(), getDay());
       this.currentDay = 1+"";
       this.currentMonth = 1+"";
    }
    
    /**
     * 设置年月日
     * 
     * @param year
     * @param month
     * @param day
     */
    public void setDate(String year, String month, String day) {
       selectYear = year + "年";
       selectMonth = month + "月";
       selectDay = day + "日";
       issetdata = true;
       this.currentYear = year;
       this.currentMonth = month;
       this.currentDay = day;
       if (year == getYear()) {
          this.month = getMonth();
       } else {
          this.month = 12+"";
       }
       calDays(year, month);
    }
    
    /**
     * 设置年份
     * 
     * @param year
     */
    public int setYear(String year) {
       int yearIndex = 0;
       if (!year.equals(getYear())) {
          this.month = 12+"";
       } else {
          this.month = getMonth();
       }
       for (int i = Integer.parseInt(getYear()); i > 1950; i--) {
          if (i == Integer.parseInt(year)) {
             return yearIndex;
          }
          yearIndex++;
       }
       return yearIndex;
    }
    
    /**
     * 设置月份
     * 
     * @param month
     * @param month
     * @return
     */
    public int setMonth(String month) {
       int monthIndex = 0;
       calDays(currentYear, month);
       for (int i = 1; i < Integer.parseInt(this.month); i++) {
          if (Integer.parseInt(month) == i) {
             return monthIndex;
          } else {
             monthIndex++;
          }
       }
       return monthIndex;
    }
    
    /**
     * 计算每月多少天
     * 
     * @param month
     * @param year
     */
    public void calDays(String year, String month) {
       boolean leayyear = false;
       if (Integer.parseInt(year) % 4 == 0 && Integer.parseInt(year) % 100 != 0) {
          leayyear = true;
       } else {
          leayyear = false;
       }
       for (int i = 1; i <= 12; i++) {
          switch (Integer.parseInt(month)) {
          case 1:
          case 3:
          case 5:
          case 7:
          case 8:
          case 10:
          case 12:
             this.day = 31+"";
             break;
          case 2:
             if (leayyear) {
                this.day = 29+"";
             } else {
                this.day = 28+"";
             }
             break;
          case 4:
          case 6:
          case 9:
          case 11:
             this.day = 30+"";
             break;
          }
       }
       if (year.equals( getYear()) && month .equals( getMonth())) {
          this.day = getDay();
       }
    

    然后设置点击事件

    @Override
    public void onClick(View v) {
    
       if (v == btnSure) {
          if (onBirthListener != null) {
             onBirthListener.onClick(selectYear, selectMonth, selectDay);
             Log.d("cy",""+selectYear+""+selectMonth+""+selectDay);
          }
       } else if (v == btnSure) {
    
       }  else {
          dismiss();
       }
       dismiss();
    
    }
    

    其实就是点击确定保存选择的日期,取消dismiss
    底下确定键是黄色按钮那个就是换了个样式而已原理都是一样的
    感谢阅读:~have a nice day~
    demo地址:https://github.com/PangHaHa12138/TimePackdemo

    相关文章

      网友评论

      • 40f614d9bb95:这个可以改成时间范围的吗,比如左边是显示一个月,右边是显示时间的范围,早上9.30-下午18.00,然后时间范围是每隔15分钟的
      • f4c4561c2638:谢谢楼主,学习了,不过有一个小问题,就是在你的结合wheelview和原生timepick自定义时间选择器那个里面,由于执行顺序的问题,导致setDate方法没有用,默认时间一直都是当前时间,导致不能定位到setDate传进去的时间,我建议是把adapter初始化的那一段放到setDate方法里面,试过是可以的,再次感谢楼主
        kelloy:其实能直接给 构造方法 加几个参数 年月日 这样省事.记得在getYear,getMonth,getDay里面加判断.这样解决显示问题 还能解决选中字体大小问题
        庞哈哈哈12138:@若_水 多谢多谢
      • 无奈又彷徨:1、选中的时间中间两条线怎么生成的?
        2、怎么在标题背景下面在增加一条线?
        感谢!!!!
      • yann_x:选中的时间中间两条线怎么生成的
      • 龍1987:com.contrarywind:Android-PickerView:3.2.4在哪里呢?
      • 96f13387a342:哈撒给!
      • 奔跑的果冻:hello 下载不了 ,能提供包吗
        庞哈哈哈12138:@奔跑的果冻 我好像给链接了,https://github.com/PangHaHa12138/TimePackdemo
        奔跑的果冻:@庞哈哈哈12138 我想下载源码,但是github没有找到下载的地方
        庞哈哈哈12138:@奔跑的果冻 可以下载啊,demo里有debug的apk,没明白你是怎么弄的下载不了?

      本文标题:安卓开发-高仿ios时间选择控件timepicker

      本文链接:https://www.haomeiwen.com/subject/ygzoqxtx.html