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

在开发中如果有地址或者日期选择等就会涉及到时间或者条件选择器,大家都会想到仿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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容