仿滴滴出行时间选择器

时间: 2023-11-13 admin IT培训

仿滴滴出行时间选择器

仿滴滴出行时间选择器

    1.自定义时间选择器:完美实现时间进场、出场选择(并有记录上次时间功能),弹出动画、界面可根据需求扩展(项目源码见底部链接)。下面是效果图:

         2.网上很多demo但问题颇多,就自己参照滴滴样式和项目需求自己修正,终成正果,欢迎探讨指正!

         3.下面开始项目开发:

                   001.思路:时间选择模块自定义实现,继承NumberPicker,对其做了我们需要的样式修改 --> 布局采用线性放置三个自定义CustomerNumberPicker实现我们时间选择界面 --> 代码修改NumberPicker为我们需要的样式 --> 代码配置我们需要的时间(根据个人需求修改) --> 时间记录功能:记录上次我们选择的时间点以供更改,原理也是手动设置时间详见代码 --> 在MainActivity中点击弹出时间选择器,完成选择 --> 将选择的时间显示在MainActivity当中

                   002.开始撸代码:

                          a.自定义CustomerNumberPicker

 

public class CustomNumberPicker extends NumberPicker {public CustomNumberPicker(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);}public CustomNumberPicker(Context context, AttributeSet attrs) {super(context, attrs);}public CustomNumberPicker(Context context) {super(context);}@Overridepublic void addView(View child) {this.addView(child, null);}@Overridepublic void addView(View child, android.view.ViewGroup.LayoutParams params) {this.addView(child, -1, params);}@Overridepublic void addView(View child, int index,android.view.ViewGroup.LayoutParams params) {super.addView(child, index, params);setNumberPicker(child);}/*** 设置CustomNumberPicker的属性 颜色 大小** @param view*/public void setNumberPicker(View view) {if (view instanceof EditText) {((EditText) view).setTextColor(Color.BLACK);((EditText) view).setTextSize(18);}}/*** 设置分割线的颜色值** @param numberPicker*/@SuppressWarnings("unused")public static void setNumberPickerDividerColor(NumberPicker numberPicker) {NumberPicker picker = numberPicker;Field[] pickerFields = NumberPicker.class.getDeclaredFields();for (Field pf : pickerFields) {if (pf.getName().equals("mSelectionDivider")) {pf.setAccessible(true);try {pf.set(picker, new ColorDrawable(Color.parseColor("#50cccccc")));} catch (IllegalArgumentException e) {e.printStackTrace();} catch (Resources.NotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}break;}}// 分割线高度for (Field pf : pickerFields) {if (pf.getName().equals("mSelectionDividerHeight")) {pf.setAccessible(true);try {int result = 3;pf.set(picker, result);} catch (Exception e) {e.printStackTrace();}break;}}}
}

 

 

                          b.TimeUtils辅助工具类,这里就不做具体介绍,后面源码有,主要是一些时间相关的转换

                          c.核心代码块:TimeSelectUtils

 

public class TimeSelectUtils implements NumberPicker.OnValueChangeListener, View.OnClickListener {private final Button selectTime;private final Button totalTime;private String initDateTime;private Context activity;private Calendar calendar;private CustomNumberPicker hourpicker;private CustomNumberPicker minutepicker;private CustomNumberPicker datepicker;private String[] minuteArrs;private String hourStr;private String minuteStr;private String dateStr;private Dialog dialog;private String[] dayArrays;private long currentTimeMillis;private RadioButton rgOut;private RadioButton rgIn;private boolean goIn = true;//标记我们入场时间选取和为选区:true为未选取时间private String startTime = "";private String endTime = "";private GetSubmitTime mSubTime;//构造方法public TimeSelectUtils(Context activity, String initDateTime, Button selectTime, Button totalTime, GetSubmitTime subTime) {this.selectTime = selectTime;this.totalTime = totalTime;this.activity = activity;this.initDateTime = initDateTime;this.mSubTime = subTime;}//初始化时间选择器:设置当前时间(根据自己需求更改)public void initPicker() {Calendar calendar = Calendar.getInstance();int hours = calendar.get(Calendar.HOUR_OF_DAY);int minutes = calendar.get(Calendar.MINUTE);if (45 <= minutes)minutes = 0;else if (30 <= minutes)minutes = 3;else if (15 <= minutes)minutes = 2;elseminutes = 1;// 设置日期 2天以内dayArrays = new String[2];dayArrays[0] = "今天";dayArrays[1] = "明天";switch (dayArrays.length) {case 0:getStatetime();break;case 1:getStatetime(1);break;}currentTimeMillis = System.currentTimeMillis();// 设置当前时间的毫秒值//时间选取改变监听datepicker.setOnValueChangedListener(this);datepicker.setDisplayedValues(dayArrays);datepicker.setMinValue(0);datepicker.setMaxValue(dayArrays.length - 1);datepicker.setValue(0);dateStr = dayArrays[0];// 初始值// 设置小时 预约15分钟以后hourpicker.setOnValueChangedListener(this);hourpicker.setMaxValue(23);hourpicker.setMinValue(0);if (minutes == 0) {hourpicker.setValue(hours + 1);hourStr = hours + 1 + "";// 初始值} else {hourpicker.setValue(hours);hourStr = hours + "";// 初始值}// 设置分钟minuteArrs = new String[]{"00", "15", "30", "45"};minutepicker.setOnValueChangedListener(this);minutepicker.setDisplayedValues(minuteArrs);minutepicker.setMinValue(0);minutepicker.setMaxValue(minuteArrs.length - 1);minutepicker.setValue(minutes);minuteStr = minuteArrs[minutes];// 初始值}/*** 弹出日期时间选择框方法** @return*/@SuppressWarnings("deprecation")public Dialog dateTimePicKDialog() {View dateTimeLayout = View.inflate(activity, R.layout.item_time_select,null);dateTimeLayout.findViewById(R.id.tv_cancel).setOnClickListener(this);dateTimeLayout.findViewById(R.id.tv_confirm).setOnClickListener(this);rgIn = (RadioButton) dateTimeLayout.findViewById(R.id.rb_go_in);rgOut = (RadioButton) dateTimeLayout.findViewById(R.id.rb_go_out);rgIn.setOnClickListener(this);rgOut.setOnClickListener(this);datepicker = (CustomNumberPicker) dateTimeLayout.findViewById(R.id.datepicker);hourpicker = (CustomNumberPicker) dateTimeLayout.findViewById(R.id.hourpicker);minutepicker = (CustomNumberPicker) dateTimeLayout.findViewById(R.id.minuteicker);//滑动或者点击时取消焦点且屏蔽键盘datepicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);hourpicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);minutepicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);//分割线颜色datepicker.setNumberPickerDividerColor(datepicker);hourpicker.setNumberPickerDividerColor(hourpicker);minutepicker.setNumberPickerDividerColor(minutepicker);initPicker();//弹出时间选择器dialog = new Dialog(activity, R.style.dialog);dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);dialog.setContentView(dateTimeLayout, new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));Window window = dialog.getWindow();window.setWindowAnimations(R.style.main_menu_animstyle);WindowManager.LayoutParams wl = window.getAttributes();wl.x = 0;wl.y = ((Activity) activity).getWindowManager().getDefaultDisplay().getHeight();wl.width = RelativeLayout.LayoutParams.MATCH_PARENT;wl.height = RelativeLayout.LayoutParams.WRAP_CONTENT;dialog.onWindowAttributesChanged(wl);// 设置点击外围隐藏dialog.setCanceledOnTouchOutside(true);dialog.show();onDateChanged();return dialog;}@SuppressWarnings("deprecation")public void onDateChanged() {// 获得日历实例calendar = Calendar.getInstance();calendar.setTime(new Date(currentTimeMillis));Date date = calendar.getTime();date.setHours(Integer.parseInt(hourStr));date.setMinutes(Integer.parseInt(minuteStr));calendar.setTime(date);//当前选取的时间SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");initDateTime = sdf.format(calendar.getTime()) + " " + hourStr + ":" + minuteStr;}@Overridepublic void onValueChange(NumberPicker picker, int oldVal, int newVal) {switch (picker.getId()) {//改变一定要记得更新数据case R.id.datepicker:currentTimeMillis = System.currentTimeMillis() + newVal * 24 * 3600 * 1000;dateStr = dayArrays[newVal];onDateChanged();break;case R.id.hourpicker:hourStr = newVal + "";onDateChanged();break;case R.id.minuteicker:minuteStr = minuteArrs[newVal];onDateChanged();break;default:break;}}//改接口用于在MainActivity获取我们选取的开始时间、结束时间public interface GetSubmitTime {void selectTime(String startDate, String entDate);}@Overridepublic void onClick(View v) {switch (v.getId()) {//取消case R.id.tv_cancel:dialog.dismiss();break;//下一步case R.id.tv_confirm:selectTimes();break;//入场case R.id.rb_go_in://点击入场时记录我们之前出场选取的时间且是在入场时间已经选择状态if (goIn == false) {endTime = initDateTime;//手动设置我们选取的入场时间if (startTime != null && !startTime.equals("")) {setTimes(startTime);}goIn = true;}Log.i("TAG", startTime + "------开始时间00");break;//出场case R.id.rb_go_out://未选择入场时间:保存入场时间if (goIn) {startTime = initDateTime;Log.i("TAG", startTime + "------开始时间11");if (!TimeUtilspareNowTime(startTime)) {Toast.makeText(activity, "请选择正确的入场时间", Toast.LENGTH_SHORT).show();Log.i("TAG", startTime + "------开始时间22");} else {goIn = false;}}//手动设置我们选取的出场时间if (endTime != null && !endTime.equals("")) {setTimes(endTime);}break;default:break;}}//设置时间(此处用于记录上次选中的时间)private void setTimes(String startTime) {try {Date date = TimeUtils.stringToDate(startTime + ":00", "yyyy-MM-dd HH:mm:ss");Calendar calendar = Calendar.getInstance();calendar.setTime(date);int hours = calendar.get(Calendar.HOUR_OF_DAY);int minutes = calendar.get(Calendar.MINUTE);String time = calendar.get(Calendar.YEAR) + "-" + formatTime(calendar.get(Calendar.MONTH) + 1) + "-" + formatTime(calendar.get(Calendar.DAY_OF_MONTH));Log.i("TAG", time + ",000000," + TimeUtils.getStatetime());if (time.equals(getStatetime())) {datepicker.setValue(0);} else {datepicker.setValue(1);}if (45 <= minutes)minutes = 3;else if (30 <= minutes)minutes = 2;else if (15 <= minutes)minutes = 1;elseminutes = 0;//设置我们记录的值hourpicker.setValue(hours);minutepicker.setValue(minutes);} catch (ParseException e) {e.printStackTrace();}}//分钟小于10补0private String formatTime(int t) {return t >= 10 ? "" + t : "0" + t;//三元运算符 t>10时取 ""+t}//点击下一步选取时间private void selectTimes() {if (rgIn.isChecked()) {//点击下一步保存我们的入场时间startTime = initDateTime;//选取15分钟以后时间段if (calendar.getTimeInMillis() <= System.currentTimeMillis() || calendar.getTimeInMillis() > System.currentTimeMillis()+ 2 * 24 * 3600 * 1000 || startTime.equals("") || startTime == null) {Toast.makeText(activity, "请选择距现在15分钟后有效时间", Toast.LENGTH_SHORT).show();} else {startTime = initDateTime;rgOut.setChecked(true);goIn = false;}} else {//点击下一步保存我们的出场时间endTime = initDateTime;if (!TimeUtilspareTwoTime(startTime, endTime)) {Toast.makeText(activity, "请选择正确的出场时间", Toast.LENGTH_SHORT).show();} else {endTime = initDateTime;Log.i("TAG", endTime + "------结束时间11");setTextTime(startTime, endTime);dialog.dismiss();}}//将选取的时间保存到借口mSubTime.selectTime(startTime + ":00", endTime + ":00");}//直接设置我们选取的时间:转化为Stringprivate void setTextTime(String startTime, String endTime) {if (startTime.equals("") || startTime == null || endTime.equals("") || endTime == null) {return;}String s = TimeUtils.formatDateTime(startTime);//此处这么做是为了防止选择的时间为今天凌晨显示错误String s1 = startTime.substring(0, 10).trim().equals(getStatetime()) ? "今天" : "明天";String s2 = s.substring(3, s.length()).trim();String e = TimeUtils.formatDateTime(endTime);String e1 = endTime.substring(0, 10).trim().equals(getStatetime()) ? "今天" : "明天";String e2 = e.substring(3, e.length()).trim();String result = TimeUtils.getTimeDifference(startTime, endTime);Log.i("TAG", "主界面时间选择器选取的时间p:" + s1 + "," + e1);if (s1.equals(e1)) {selectTime.setText("选择时间:" + s1 + s2 + "-" + e2);} else {selectTime.setText("选择时间:" + s1 + s2 + "-" + e1 + e2);}totalTime.setVisibility(View.VISIBLE);totalTime.setText("(" + "合计 : " + result + ")");Log.i("TAG", s + "------开始时间" + e + "------结束时间");}
}

                     

 

                        d.MainActivity中几号代码完成调用显示时间选择器:

 

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final Button selectTime = (Button) findViewById(R.id.bt_select_time);final Button totalTime = (Button) findViewById(R.id.bt_total_time);//点击监听((LinearLayout) findViewById(R.id.ll_popup_time_selsect)).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {TimeSelectUtils timeSelectUtils = new TimeSelectUtils(MainActivity.this, null, selectTime, totalTime, new TimeSelectUtils.GetSubmitTime() {@Overridepublic void selectTime(String startDate, String entDate) {Log.i("TAG", "选择的开始时间:" + startDate + ",结束时间:" + entDate);}});//显示我们的时间选择器timeSelectUtils.dateTimePicKDialog();}});}
}

          4.至此代码完成,完美实现了时间选择器,还有一些资源文件见项目源码

            5.项目源码:   点击下载源码