欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Setting 日期相关API,自定义DatePicker

程序员文章站 2022-07-04 13:56:58
最近在做setting日期相关的工作,整理一下相关的api(相关代码源自android 8.0高通代码) 注意:以下api来自setting,使用的地方也在setting中,如果其他非应用使用,可能...

最近在做setting日期相关的工作,整理一下相关的api(相关代码源自android 8.0高通代码)

注意:以下api来自setting,使用的地方也在setting中,如果其他非应用使用,可能需要加权限

设置日期api

void setdate(int year, int month, int day) {
 calendar c = calendar.getinstance();

 log.d(tag, "setdate: year " + year + " month " + month + " day " + day);
 c.set(calendar.year, year);
 c.set(calendar.month, month);
 c.set(calendar.day_of_month, day);
 long when = math.max(c.gettimeinmillis(), datepreferencecontroller.datepreferencehost.min_date);

 if (when / 1000 < integer.max_value) {
  ((alarmmanager) mcontext.getsystemservice(context.alarm_service)).settime(when);
 }
}

datepreferencecontroller.datepreferencehost.min_date:是一个长整型常量,表示日期可以设置的最小值。

dateformat api

private void set24hour(boolean is24hour) {
 log.d(tag, "set24hour: ");
 settings.system.putstring(mcontext.getcontentresolver(),
settings.system.time_12_24,
is24hour ? hours_24 : hours_12);
}

指定12小时 24小时制

获取当前dateformat api

public boolean is24hour() {
 log.d(tag, "is24hour: ");
 return dateformat.is24hourformat(mcontext);
}

设置时间api

void settime(int hourofday, int minute) {
 calendar c = calendar.getinstance();

 c.set(calendar.hour_of_day, hourofday);
 c.set(calendar.minute, minute);
 c.set(calendar.second, 0);
 c.set(calendar.millisecond, 0);
 long when = math.max(c.gettimeinmillis(), timepreferencehost.min_date);

 if (when / 1000 < integer.max_value) {
  ((alarmmanager) mcontext.getsystemservice(context.alarm_service)).settime(when);
 }
}

设置时区api

final alarmmanager alarm = (alarmmanager) activity.getsystemservice(context.alarm_service);
alarm.settimezone(tzid);

这里tzid是一个字符串,形式为 大洲/city
比如asia/shanghai
在android 8.0高通中一共有89个城市,设置的tzid必须在这89个数据中,否则底层会抛出异常,找不到指定的时区,应用crash

自定义datepicker

由于客户给出的设计图和android原生的datepicker相差过大,只能自定义datepicker了。
注意:这里使用的numberpicker在framework层的源码做过少量修改。设计图给出的样式比较丑,还没有原生的漂亮。给出的设计大概是这样的
Android Setting 日期相关API,自定义DatePicker

java代码

package com.android.settings.datetime;

import android.app.alarmmanager;
import android.app.alertdialog;
import android.content.context;
import android.os.build;
import android.support.annotation.nonnull;
import android.support.annotation.requiresapi;
import android.util.log;
import android.view.keyevent;
import android.view.viewgroup.layoutparams;
import android.view.windowmanager;
import android.widget.numberpicker;

import com.android.settings.r;

import java.util.calendar;

/**
 * created by caihuijian on 18-5-18.
 */

public class customdatepickerdialog extends alertdialog {
 private static final string tag = "customdatepickerdialog";

 private numberpicker mnumberyear;
 private numberpicker mnumbermonth;
 private numberpicker mnumberday;

 private static final int max_year = 37;//暂定 系统某处定义了
 private static final int min_year = 7;//暂定 系统某处定义了

 private static final int big_month_day = 31;//大月31天
 private static final int small_month_day = 30;//小月30天
 private static final int leap_feb_day = 29;//闰年二月29天
 private static final int not_leap_feb_day = 28;//平年二月28天
 private static final int min_day = 1;//最小日

 private static final int max_month = 12;//最大月数
 private static final int min_month = 1;//最小月数

 private context mcontext = null;
 final calendar calendar = calendar.getinstance();

 protected customdatepickerdialog(@nonnull context context) {
  super(context);
  this.mcontext = context;
 }

 @requiresapi(api = build.version_codes.honeycomb)
 @override
 public void show() {
  super.show();

  //全屏dialog
  windowmanager.layoutparams layoutparams = getwindow().getattributes();
  layoutparams.width = layoutparams.match_parent;
  layoutparams.height = layoutparams.match_parent;
  getwindow().getdecorview().setpadding(0, 0, 0, 0);
  getwindow().setattributes(layoutparams);
  getwindow().getdecorview().setbackgroundresource(0x00000000);
  setcustomlayout();
 }

 @requiresapi(api = build.version_codes.honeycomb)
 private void setcustomlayout() {
  setcontentview(r.layout.cus_date_picker_dialog);

  //控件初始化
  mnumbermonth = (numberpicker) findviewbyid(r.id.month);
  mnumberday = (numberpicker) findviewbyid(r.id.day);
  mnumberyear = (numberpicker) findviewbyid(r.id.year);
  setviewmaxmin();
  initallview();

  mnumberyear.setonvaluechangedlistener(yearchangelistener);
  mnumbermonth.setonvaluechangedlistener(monthchangelistener);
  mnumberday.setonvaluechangedlistener(daychangelistener);
 }


 //取得当前时间 设置到view
 @requiresapi(api = build.version_codes.honeycomb)
 private void initallview() {
  int year, monthofyear, dayofmonth;
  if (calendar != null) {
//因为控件只显示年的后两位 所以对100取余
year = calendar.get(calendar.year) % 100;
monthofyear = calendar.get(calendar.month);
dayofmonth = calendar.get(calendar.day_of_month);

mnumberyear.setvalue(year);
mnumbermonth.setvalue(monthofyear);
mnumberday.setvalue(dayofmonth);

  }
 }

 @requiresapi(api = build.version_codes.honeycomb)
 private int getmonthday(int month) {
  switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
 return big_month_day;
case 4:
case 6:
case 9:
case 11:
 return small_month_day;
case 2:
 int year = mnumberyear.getvalue();
 boolean isleap = isleapyear(year);
 if (isleap) {
  return leap_feb_day;
 } else {
  return not_leap_feb_day;
 }
  }
  return 0;
 }

 //ui中,年只有2位,可以使用这两位进行闰年判断
 boolean isleapyear(int year) {
  if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
log.d(tag, "isleapyear: " + year + "年是闰年");
return true;
  } else {
log.d(tag, "isleapyear: " + year + "年不是闰年");
return false;
  }
 }

 @requiresapi(api = build.version_codes.honeycomb)
 private void setviewmaxmin() {
  mnumbermonth.setmaxvalue(max_month);
  mnumbermonth.setminvalue(min_month);
  mnumberday.setmaxvalue(big_month_day);
  mnumberday.setminvalue(min_day);
  mnumberyear.setmaxvalue(max_year);
  mnumberyear.setminvalue(min_year);
 }


 @requiresapi(api = build.version_codes.honeycomb)
 @override
 public boolean onkeyup(int keycode, keyevent event) {

  switch (keycode) {
case keyevent.keycode_dpad_center:
 if (mnumberyear.isfocused()) {
  mnumbermonth.requestfocus();
 } else if (mnumbermonth.isfocused()) {
  mnumberday.requestfocus();
 } else if (mnumberday.isfocused()) {
  setdate(2000 + mnumberyear.getvalue(), mnumbermonth.getvalue(), mnumberday.getvalue());
  this.dismiss();

 }
 return true;
case keyevent.keycode_back:
 if (mnumberday.isfocused()) {
  mnumbermonth.requestfocus();
  return true;
 } else if (mnumbermonth.isfocused()) {
  mnumberyear.requestfocus();
  return true;
 }
  }
  //手动输入数字 填充年月日
  if (keycode >= keyevent.keycode_0 && keycode <= keyevent.keycode_9) {
int singledigit = keycode - keyevent.keycode_0;
log.d(tag, "onkeyup: keycode" + keycode);
if (mnumberyear.hasfocus()) {
 log.d(tag, "onkeyup: year");
 //手动输入不会触发valuechangelistener,需要自己处理
 int yearchangeto = manualinput(mnumberyear, singledigit);
 yeartextchange(yearchangeto);
} else if (mnumbermonth.hasfocus()) {
 log.d(tag, "onkeyup: month");
 //手动输入不会触发valuechangelistener,需要自己处理
 int monthchange = manualinput(mnumbermonth, singledigit);
 monthtextchange(monthchange);
} else if (mnumberday.hasfocus()) {
 manualinput(mnumberday, singledigit);
}
return true;
  }

  return super.onkeyup(keycode, event);
 }

 @requiresapi(api = build.version_codes.honeycomb)
 private int manualinput(numberpicker numberpicker, int userinput) {
  //手动输入逻辑:
  //取个位数放到十位上
  //输入值作为个位数
  //十位 个位相加
  //判断该值是否在最大与最小值之间 小于最小值取最小值 大于最大值取最大值 十位取最大值的十位数,个位为用户输入

  int temp = numberpicker.getvalue();
  int value = temp % 10 * 10 + userinput;
  int maxvalue = numberpicker.getmaxvalue();
  int minvalue = numberpicker.getminvalue();
  if (value < minvalue) {
value = minvalue;
  } else if (value > maxvalue) {
value = maxvalue - maxvalue % 10 + userinput;
if(value > maxvalue){
 value = maxvalue;
}
  }
  log.d(tag, "manualinput: value" + value);
  numberpicker.setvalue(value);
  return value;
 }

 //设置日期api
 @requiresapi(api = build.version_codes.froyo)
 void setdate(int year, int month, int day) {
  calendar c = calendar.getinstance();
  log.d(tag, "setdate: year " + year + " month " + month + " day " + day);
  c.set(calendar.year, year);
  c.set(calendar.month, month);
  c.set(calendar.day_of_month, day);
  long when = math.max(c.gettimeinmillis(), datepreferencecontroller.datepreferencehost.min_date);

  if (when / 1000 < integer.max_value) {
((alarmmanager) mcontext.getsystemservice(context.alarm_service)).settime(when);
  }
 }

 numberpicker.onvaluechangelistener yearchangelistener = new numberpicker.onvaluechangelistener() {
  @requiresapi(api = build.version_codes.honeycomb)
  @override
  public void onvaluechange(numberpicker numberpicker, int yearold, int yearnew) {
yeartextchange(yearnew);
  }
 };
 numberpicker.onvaluechangelistener monthchangelistener = new numberpicker.onvaluechangelistener() {
  @requiresapi(api = build.version_codes.honeycomb)
  @override
  public void onvaluechange(numberpicker numberpicker, int monthold, int monthnew) {
monthtextchange(monthnew);
  }
 };
 numberpicker.onvaluechangelistener daychangelistener = new numberpicker.onvaluechangelistener() {
  @override
  public void onvaluechange(numberpicker numberpicker, int dayold, int daynew) {
  }
 };

 //年的控件变化需要做的处理
 @requiresapi(api = build.version_codes.honeycomb)
 public void yeartextchange(int yearnew) {
  //年的变化会导致2月是否有29日变化
  boolean isleapyear = isleapyear(yearnew);
  int month = mnumbermonth.getvalue();
  if (isleapyear && month == 2) {
//闰年二月
mnumberday.setmaxvalue(29);
  } else if (!isleapyear && month == 2) {
//非闰年二月
mnumberday.setmaxvalue(28);
  }
 }

 //月的控件变化需要做的处理
 @requiresapi(api = build.version_codes.honeycomb)
 private void monthtextchange(int monthnew) {
  int monthday = getmonthday(monthnew);
  mnumberday.setmaxvalue(monthday);
 }

}

xml




 
 

 
 

 
 
 
 

 
 

使用

 customdatepickerdialog datepickerdialog = new customdatepickerdialog(getactivity());
 datepickerdialog.show();