look at the renderings first:
1. DatePicker that does not display the number of days
2. Set the display date range of DatePicker 3.
Style
adjustment of DatePicker Specific code:
To achieve this effect, first hide the Number in the last column (the three columns of DatePicker are all implemented with numbers). There are two ways to hide the last column, as follows:
The first:
DatePicker dp = findDatePicker((ViewGroup) datePickerDialog.getWindow().getDecorView()); if (dp != null) { ((ViewGroup)((ViewGroup) dp.getChildAt(0)).getChildAt(0)).getChildAt(2).setVisibility(View.GONE); } } private DatePicker findDatePicker(ViewGroup group) { if (group != null) { for (int i = 0, j = group.getChildCount(); i < j; i++) { View child = group.getChildAt(i); if (child instanceof DatePicker) { return (DatePicker) child; } else if (child instanceof ViewGroup) { DatePicker result = findDatePicker((ViewGroup) child); if (result != null) return result; } } } return null; }
This method is used in DatePickerDialog, get the DatePicker through the findDatePicker method, and then get the number that displays the number of days according to the layout level of the DatePicker and set it to GONE. If we add the DatePicker to the layout by ourselves, we can directly get the number of the displayed days through the getChildAt method of DatePicker and set it to not display. In this example, it is set by the following method:
layout file:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="180dp" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:padding="5dip" android:paddingTop="10dp"> <TextView android:layout_width="wrap_content" android:layout_marginBottom="-15dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="Select month" /> <DatePicker android:theme="@android:style/Theme.Holo.Light" android:id="@+id/datePickerStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:calendarViewShown="false" /> <Button android:id="@+id/dd_btn_sure" android:layout_width="match_parent" android:layout_marginTop="-20dp" android:text="OK" android:textSize="18sp" android:background="@android:color/transparent" android:layout_height="wrap_content" /> </LinearLayout>
If the layout file is like the above, we can directly find the viewbyid in the logic code to get the DatePicker, and then call the following method to hide the control of the number of days.
.getChildAt(0)).getChildAt(0)).getChildAt(2).setVisibility(View.GONE);
Complete logic code:
public class MyChooseMonthDialog extends AlertDialog implements OnDateChangedListener, View.OnClickListener { private static final String YEAR = "YEAR"; private static final String MONTH = "MONTH"; private static final String DAY = "DAY"; private final DatePicker mDatePicker; private final MyChooseMonthDialog.OnDateSetListener mCallBack; /** * The callback used to indicate the user is done filling in the date. */ public interface OnDateSetListener { void onDateSet(DatePicker startDatePicker, int startYear, int startMonthOfYear, int startDayOfMonth); } /** * @param context The context the dialog is to run in. * @param callBack How the parent is notified that the date is set. * @param year The initial year of the dialog. * @param monthOfYear The initial month of the dialog. * @param dayOfMonth The initial day of the dialog. */ public MyChooseMonthDialog(Context context, MyChooseMonthDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { this(context, 0, callBack, year, monthOfYear, dayOfMonth); } public MyChooseMonthDialog(Context context, int theme, MyChooseMonthDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { this(context, 0, callBack, year, monthOfYear, dayOfMonth, true); } /** * @param context The context the dialog is to run in. * @param theme the theme to apply to this dialog * @param callBack How the parent is notified that the date is set. * @param year The initial year of the dialog. * @param monthOfYear The initial month of the dialog. * @param dayOfMonth The initial day of the dialog. */ public MyChooseMonthDialog(Context context, int theme, MyChooseMonthDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth, boolean isDayVisible) { super(context, theme); mCallBack = callBack; Context themeContext = getContext(); setIcon (0); LayoutInflater inflater = (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.datepicker_dialog, null); Button dd_btn_sure = (Button) view.findViewById(R.id.dd_btn_sure); dd_btn_sure.setOnClickListener(this); setView(view); mDatePicker = (DatePicker) view.findViewById(R.id.datePickerStart); mDatePicker.init(year, monthOfYear, dayOfMonth, this); mDatePicker.setMaxDate(System.currentTimeMillis()); setMyStyle(mDatePicker); // If you want to hide the current date, use the following method. if (!isDayVisible) { hidDay(mDatePicker); } } private void setMyStyle(DatePicker mDatePicker) { LinearLayout llFirst = (LinearLayout) mDatePicker.getChildAt(0); LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0); llSecond.setPadding(0, 0,0, 0); llSecond.setBackgroundResource(R.color.transparent);//Set the background of datepickerdialog for (int i = 0; i < llSecond.getChildCount(); i++) { NumberPicker picker = (NumberPicker) llSecond.getChildAt(i); // Numberpickers in llSecond Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (Field pf : pickerFields) { //change the color of the dividing line if (pf.getName().equals("mSelectionDivider")) { pf.setAccessible(true); try { pf.set(picker, ContextCompat.getDrawable(YztApplication.getInstance(), R.color.investor_ilp_red)); } catch (IllegalAccessException e) { e.printStackTrace (); } break; } } } } private void hidDay(DatePicker mDatePicker) { if(mDatePicker!=null){ ((ViewGroup)((ViewGroup) mDatePicker.getChildAt(0)).getChildAt(0)).getChildAt(2).setVisibility(View.GONE); } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.dd_btn_sure: tryNotifyDateSet(); this.dismiss(); break; } } @Override public void onDateChanged(DatePicker view, int year, int month, int day) { if (view.getId() == R.id.datePickerStart) mDatePicker.init(year, month, day, this); // updateTitle(year, month, day); } /** * Get the DatePicker of the start date * * @return The calendar view. */ public DatePicker getDatePickerStart() { return mDatePicker; } /** * Sets the start date. * * @param year The date year. * @param monthOfYear The date month. * @param dayOfMonth The date day of month. */ public void updateStartDate(int year, int monthOfYear, int dayOfMonth) { mDatePicker.updateDate(year, monthOfYear, dayOfMonth); } private void tryNotifyDateSet() { if (mCallBack != null) { mDatePicker.clearFocus(); mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth()); } } @Override protected void onStop() { // tryNotifyDateSet(); super.onStop(); } @Override public Bundle onSaveInstanceState() { Bundle state = super.onSaveInstanceState(); state.putInt(YEAR, mDatePicker.getYear()); state.putInt(MONTH, mDatePicker.getMonth()); state.putInt(DAY, mDatePicker.getDayOfMonth()); return state; } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState (savedInstanceState); int year = savedInstanceState.getInt(YEAR); int month = savedInstanceState.getInt(MONTH); int day = savedInstanceState.getInt(DAY); mDatePicker.init(year,month,day, this); } }
The most important of which is the following code:
private void setMyStyle(DatePicker mDatePicker) { LinearLayout llFirst = (LinearLayout) mDatePicker.getChildAt(0); LinearLayout llSecond = (LinearLayout) llFirst.getChildAt(0); llSecond.setPadding(0, 0,0, 0); llSecond.setBackgroundResource(R.color.transparent);//Set the background of datepickerdialog for (int i = 0; i < llSecond.getChildCount(); i++) { NumberPicker picker = (NumberPicker) llSecond.getChildAt(i); // Numberpickers in llSecond Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (Field pf : pickerFields) { //change the color of the dividing line if (pf.getName().equals("mSelectionDivider")) { pf.setAccessible(true); try { pf.set(picker, ContextCompat.getDrawable(YztApplication.getInstance(), R.color.investor_ilp_red)); } catch (IllegalAccessException e) { e.printStackTrace (); } break; } } } }
This code gets his sub-layout through DatePicker, then gets the dividing line in NumberPicker through reflection, and modifies its color. In the same way, we can also get the column showing the number of days through reflection and set it to be hidden. This is the second method. The code is as follows:
private void hidDay(DatePicker mDatePicker) { Field[] datePickerfFields = mDatePicker.getClass().getDeclaredFields(); for (Field datePickerField : datePickerfFields) { if ("mDaySpinner".equals(datePickerField.getName())) { datePickerField.setAccessible(true); Object dayPicker = new Object(); try { dayPicker = datePickerField.get(mDatePicker); } catch (IllegalAccessException e) { e.printStackTrace (); } catch (IllegalArgumentException e) { e.printStackTrace (); } // datePicker.getCalendarView().setVisibility(View.GONE); ((View) dayPicker).setVisibility(View.GONE); } } }
The code of the second method above comes from: http://www.cnblogs.com/jilianggqq/p/4139510.html
After 5.0, the system test failed, and the theme of setting holo is not enough. I took a look and the reason is because DatePickerDialog The layout level in the source code does not correspond to the logic reflected in the logic code. A slight modification should be able to achieve the same effect.
When the last column is hidden, the AlertDialog does not adjust the size of the layout. At this time, it looks very inconsistent. We need to call the setLayout method after calling the show in the Dialog. Note that it must be called after the show. The code is as follows:
datePickerDialog.show(); datePickerDialog.getWindow().setLayout(Utils.dip2px(IncomeDetailActivity.this,260),Utils.dip2px(IncomeDetailActivity.this,300));
Set DatePicker's date range:
mDatePicker.setMaxDate(System.currentTimeMillis());
There is a small problem after setting the date range. When the month displayed by DatePicker is the current month, you can see the next month. In theory, if the date range is set to today, the next month will not be displayed. When I saw the month display, it immediately returned to normal. That is to say, after mDatePicker.setMaxDate, the display of the year but not the month is refreshed.... The specific reason remains to be studied.
I hope that programming-loving friends can join this group, help each other, and learn together. Group number: 141877583