我目前正在开发一个简单的项目,其中包括一个网站包装在一个网页视图与较小的互动,以提高网站本身和android移动设备之间的交互性。
由于网站包括用户生日的日期输入字段,我希望实现一个与所有设备兼容的微调格式的日期选择器。我尝试实现了以下解决方案:
`<style name="MyAppTheme" parent="android:Theme.Material">
<item name="android:dialogTheme">@style/MyDialogTheme</item>
<item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>
<style name="MyDialogTheme" parent="android:Theme.Material.Dialog">
<item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>
<style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
<item name="android:datePickerMode">spinner</item>
</style>`
如下所示:Datepicker dialog without calendar visualization in lollipop [spinner mode]?
然而,正如答案指出的那样,由于以下已知的错误,这个解决方案不能与Android7.0 Nougat /API24一起工作:https://issuetracker.google.com/issues/37119315
在做一些研究时,我遇到了一些建议的解决方案,例如:
https://gist.github.com/uqmessias/d9a8dc624af935f344dfa2e8928490ec
https://gist.github.com/lognaturel/232395ee1079ff9e4b1b8e7096c3afaf
DatePickerDialog Holo styling failed on Android 7 Nougat
然而,在我的例子中,它们似乎既不适用于安卓7.0的设备,也不适用于其他设备。
我在android开发方面非常缺乏经验,所以我想知道是什么导致了这个问题,我该如何解决它,因为一些解决方案一直维护到最近,这几乎丢弃了它们可能已经过时的东西。
我是否需要实现一些在我发布的代码中没有指出并且我没有意识到的东西?
是不是因为datepicker元素是直接从web视图调用的,而不是从应用程序本身调用的,所以这些解决方案对我来说毫无用处?如果是这样的话,有什么办法可以解决这个问题吗?
发布于 2018-07-21 03:28:31
我遇到了同样的问题(用户不想逐月滚动到40年前来查找他们的出生年份,大多数人也不知道你可以在android日期选择器中单击年份来滚动年份)。像你一样,我不能让微调工具通用工作,所以我想出了(在so和Google的帮助下)如何让它在年份选择模式下启动。
下面粘贴了我的DatePickerDialogFragment
的代码。
public class DatePickerDialogFragment extends DialogFragment {
private DatePickerDialog.OnDateSetListener listener = null;
void setListener(DatePickerDialog.OnDateSetListener listener) {
this.listener = listener;
}
private static final String START_IN_YEARS = "com.myapp.picker.START_IN_YEARS";
private static final String YEAR = "com.myapp.picker.YEAR";
private static final String MONTH = "com.myapp.picker.MONTH";
private static final String DAY_OF_MONTH = "com.myapp.picker.DAY_OF_MONTH";
public static DatePickerDialogFragment newInstance(boolean startInYears, Calendar c) {
DatePickerDialogFragment f = new DatePickerDialogFragment();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
Bundle args = new Bundle();
args.putBoolean(START_IN_YEARS, startInYears);
args.putInt(YEAR, year);
args.putInt(MONTH, month);
args.putInt(DAY_OF_MONTH, day);
f.setArguments(args);
return f;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
DatePickerDialog dpd = null;
if( listener != null && args != null) {
boolean startInYears = args.getBoolean(START_IN_YEARS);
Context context = getActivity();
boolean requireSpinnerMode = isBrokenSamsungDevice();
if (requireSpinnerMode) {
context = new ContextThemeWrapper(context, android.R.style.Theme_Holo_Light_Dialog);
}
int year = args.getInt(YEAR);
int month = args.getInt(MONTH);
int day = args.getInt(DAY_OF_MONTH);
dpd = new DatePickerDialog(context, listener, year, month, day);
if (startInYears && !requireSpinnerMode) {
boolean canOpenYearView = openYearView(dpd.getDatePicker());
if (!canOpenYearView) {
context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog);
dpd = new DatePickerDialog(context, listener, year, month, day);
}
}
}
else {
setShowsDialog(false);
dismissAllowingStateLoss();
}
return dpd;
}
private static boolean isBrokenSamsungDevice() {
return Build.MANUFACTURER.equalsIgnoreCase("samsung") &&
isBetweenAndroidVersions(
Build.VERSION_CODES.LOLLIPOP,
Build.VERSION_CODES.LOLLIPOP_MR1);
}
private static boolean isBetweenAndroidVersions(int min, int max) {
return Build.VERSION.SDK_INT >= min && Build.VERSION.SDK_INT <= max;
}
private static boolean openYearView(DatePicker datePicker) {
if( isBrokenSamsungDevice() ) {
return false;
}
View v = datePicker.findViewById(Resources.getSystem().getIdentifier("date_picker_header_year", "id", "android"));
if( v != null ) {
v.performClick();
}
else {
try {
Field mDelegateField = datePicker.getClass().getDeclaredField("mDelegate");
mDelegateField.setAccessible(true);
Object delegate = mDelegateField.get(datePicker);
Method setCurrentViewMethod = delegate.getClass().getDeclaredMethod("setCurrentView", int.class);
setCurrentViewMethod.setAccessible(true);
setCurrentViewMethod.invoke(delegate, 1);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
return true;
}
}
活动中的代码(onCreate
中的成员变量和其他东西)用来启动它(并在旋转时保留它),如下所示:
// Class member variables
private Calendar myCalendar = Calendar.getInstance();
private boolean birthday_is_set = false;
// this next part is in onCreate
// set the calendar date to a saved date if applicable
// and change birthday_is_set if they had saved a birthday
final DatePickerDialog.OnDateSetListener birthdayListener = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
// I save the date in a calendar, replace this
// with whatever you want to do with the selected date
myCalendar.set(Calendar.YEAR, year);
myCalendar.set(Calendar.MONTH, monthOfYear);
myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
birthday_is_set = true;
updateBirthdayLabel();
}
};
if (savedInstanceState != null) {
DatePickerDialogFragment dpf;
dpf = (DatePickerDialogFragment) getFragmentManager().findFragmentByTag("birthdayDatePicker");
if (dpf != null) {
// on rotation the listener will be referring to the old Activity,
// so we have to reset it here to act on the current Activity
dpf.setListener(birthdayListener);
}
}
birthdayDatePicker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Your logic may vary here. I chose not to start it in year
// mode if they've already selected a date.
boolean startInYears = !birthday_is_set;
DatePickerDialogFragment dpf = DatePickerDialogFragment.newInstance(startInYears, myCalendar);
dpf.setListener(birthdayListener);
dpf.show(getFragmentManager(), "birthdayDatePicker");
}
});
这既包括使其在年份模式下启动的黑客攻击,也包括修复某些特定年份的三星设备上随机出现的日期选择器故障。这个版本已经在15+接口上运行了几个月了,没有崩溃或用户投诉。
编辑:更新了openYearView以在Android10上运行
发布于 2018-10-11 10:46:41
对于那些想让WebView中的DatePicker正常工作而无需添加JS接口来手动调用您自己的DatePicker的人,这里有一个解决方案,可以覆盖您应用程序中的所有DatePickers:
https://github.com/Noisyfox/DatePickerForceSpinner
此修复还适用于由LayoutInflater创建的任何DatePicker,因此您无需担心更改现有布局文件。
https://stackoverflow.com/questions/51448575
复制相似问题