日期选择器,项目中不少用,网上也有很多,包括我之前也抄过一个,但是没有这个漂亮,毕竟我也是在进步嘛,这次使用的三方框架为
AndroidPicker
,一开始看了几篇文章介绍,包括作者介绍的使用方式都不得其解,好在最后是解决了,同时简单封装了一下,大家请直接看下文把 ~
地址关联Blog
AndroidPicker 本身是一款很优秀的三方框架,在2017年
的时候就已经有很多扩展功能
,其中地址选择器
、时间选择器
只是很小的一部分,根据原作者描述,还包含以下选择器
日期及时间选择器
(可用于出生日期、营业时间等)单项选择器
(可用于性别、民族、职业、学历、星座等)二三级联动选择器
(可用于车牌号、基金定投日期等)城市地址选择器
(分省级、地市级及区县级)数字选择器
(可用于年龄、身高、体重、温度等)日历选日期择器
(可用于酒店及机票预定日期)颜色选择器
、文件及目录选择器
、图片选择器
等……
我是有幸在2022年
的时候又用到了AndroidPicker
,回想之前写过该框架的类似Blog,发现早之前(2017)的写法早就过时了
,所以在补入一版吧… 下方关于2017年的部分,可以直接无视!!!
~
2017年
我记得以前应该是Git图,不知道csdn后面怎么给转存的,效果都让人看不了,无语...
准备工作
如使用中出现错误,请看最后的错误点提醒
build 引入
latest.integration
是根据框架的版本自行调试的
compile 'cn.qqtheme.framework:WheelPicker:latest.integration'
插入动画
- res文件下创建anim文件夹
popup_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromYDelta="100%p"
android:toYDelta="0" />
<alpha
android:duration="500"
android:fromAlpha="0"
android:toAlpha="1" />
</set>
popup_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="1000"
android:fromYDelta="0"
android:toYDelta="50%p" />
<alpha
android:duration="500"
android:fromAlpha="1"
android:toAlpha="0" />
</set>
- value下的style内封装动画style
<style name="Animation_CustomPopup" parent="@android:style/Animation">
<item name="android:windowEnterAnimation">@anim/popup_in</item>
<item name="android:windowExitAnimation">@anim/popup_out</item>
</style>
使用方式
DateListener(使用此接口传输数据 - 接口回调)
package com.bakheet.effect.picker;
/**
* @author by YongLiu on 2017/11/14.
*/
public interface DateListener {
void setYear(String year);
void setMonth(String month);
void setDay(String day);
void setMouthDate(String year, String month);
void setYearDate(String year, String month, String day);
}
MainActivity
package com.bakheet.effect.picker;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView mContent;
private TextView mBtn;
private TextView mBtnMonth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtn = (TextView) findViewById(R.id.btn);
mContent = (TextView) findViewById(R.id.content);
mBtnMonth = (TextView) findViewById(R.id.btn_month);
/**
* 年月日
* */
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DateUtil.setYearDate(MainActivity.this, new DateListener() {
@Override
public void setYear(String year) {
}
@Override
public void setMonth(String month) {
}
@Override
public void setDay(String day) {
}
@Override
public void setMouthDate(String year, String month) {
}
@Override
public void setYearDate(String year, String month, String day) {
mContent.setText(year + "-" + month + "-" + day);
}
});
}
});
/**
* 年月
* */
mBtnMonth.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DateUtil.setMonthDate(MainActivity.this, new DateListener() {
@Override
public void setYear(String year) {
}
@Override
public void setMonth(String month) {
}
@Override
public void setDay(String day) {
}
@Override
public void setMouthDate(String year, String month) {
mContent.setText(year + "-" + month);
}
@Override
public void setYearDate(String year, String month, String day) {
}
});
}
});
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.bakheet.effect.picker.MainActivity">
<TextView
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="8dp"
android:text="弹出日期框 - 年月" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimaryDark" />
<TextView
android:id="@+id/btn_month"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="8dp"
android:text="弹出日期框 - 年月日" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimaryDark" />
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:text="日期展示区" />
</LinearLayout>
DateUtil (简单封装,方便使用)
package com.bakheet.effect.picker;
import android.app.Activity;
import android.text.format.Time;
import cn.qqtheme.framework.picker.DatePicker;
import cn.qqtheme.framework.picker.DateTimePicker;
/**
* Created by YongLiu on 2017/11/14.
* @author
*/
public class DateUtil {
/**
* 年-月
*/
static void setMonthDate(final Activity mContext,final DateListener dateListener){
DatePicker picker = new DatePicker(mContext, DateTimePicker.YEAR_MONTH);
//获取当前时间
Time time = new Time();
time.setToNow();
int year = time.year;
int month = time.month;
//设置时间区间
picker.setRange(2000,2020);
//设置默认显示时间
picker.setSelectedItem(year,month+1);
//加入动画
picker.setAnimationStyle(R.style.Animation_CustomPopup);
//回传数据
picker.setOnDatePickListener(new DatePicker.OnYearMonthPickListener() {
@Override
public void onDatePicked(String year, String month) {
dateListener.setMouthDate(year,month);
}
});
picker.show();
}
/**
* 年-月-日
*/
static void setYearDate(final Activity mContext,final DateListener dateListener){
DatePicker picker = new DatePicker(mContext);
//获取当前时间
Time time = new Time();
time.setToNow();
int year = time.year;
int month = time.month;
int monthDay = time.monthDay;
//设置时间区间
picker.setRange(2000,2020);
//设置默认显示时间
picker.setSelectedItem(year,month+1,monthDay);
//加入动画
picker.setAnimationStyle(R.style.Animation_CustomPopup);
//回传数据
picker.setOnDatePickListener(new DatePicker.OnYearMonthDayPickListener() {
@Override
public void onDatePicked(String year, String month, String day) {
dateListener.setYearDate(year,month,day);
}
});
picker.show();
}
/**
* 年-月 最后可选日期为当日
*/
public static void setMonthDate(final Activity mContext, String startYear, String startMonth, boolean dynamicStartTime, final DateListener dateListener) {
DatePicker picker = new DatePicker(mContext, DatePicker.YEAR_MONTH);
//获取当前时间
Time time = new Time();
time.setToNow();
int currentYear = time.year;
int currentMonth = time.month;
TLogUtils.e("currentMonth =" + currentMonth);
//设置时间区间
if (dynamicStartTime) {
//动态的开始时间
picker.setRangeStart(ToolUtil.getIntParseString(startYear), ToolUtil.getIntParseString(startMonth));
picker.setRangeEnd(2050, 1);
} else {
//动态的结束时间
picker.setRangeStart(2000, 1);
picker.setRangeEnd(currentYear, currentMonth + 1);
}
//设置时间区间
// picker.setRange(2000, year);
//循环
// picker.setCycleDisable(false);
//设置默认显示时间
picker.setSelectedItem(currentYear, currentMonth + 1);
//加入动画
picker.setAnimationStyle(R.style.Animation_CustomPopup);
//设置取消按钮文字颜色
picker.setCancelTextColor(ContextCompat.getColor(mContext, R.color.gray1));
//设置取消按钮文字大小
picker.setCancelTextSize(14);
//设置顶部标题栏下划线颜色
picker.setTopLineColor(ContextCompat.getColor(mContext, R.color.white1));
//设置分割线颜色
picker.setDividerColor(ContextCompat.getColor(mContext, R.color.white1));
//设置确定按钮文字颜色
picker.setSubmitTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setSubmitTextSize(14);
//设置标题文字颜色
picker.setTitleTextColor(ContextCompat.getColor(mContext, R.color.gray5));
//设置标题文字
picker.setTitleText("选择月份");
//设置标题文字大小
picker.setTitleTextSize(14);
//回传数据
picker.setOnDatePickListener(new DatePicker.OnYearMonthPickListener() {
@Override
public void onDatePicked(String year, String month) {
dateListener.setMouthDate(year, month);
}
});
picker.show();
}
}
/**
* 选择税率 - 偏向自定义样式
*/
public static void setRate(final Activity mContext, OptionPicker.OnOptionPickListener onOptionPickListener) {
String[] strings = {"0%", "3%", "17%"};
OptionPicker picker = new OptionPicker(mContext, strings);
picker.setSelectedIndex(0);
picker.setTextSize(22);
picker.setItemWidth(160);
//设置取消按钮文字颜色
picker.setCancelTextColor(ContextCompat.getColor(mContext, R.color.gray1));
//设置取消按钮文字大小
picker.setCancelTextSize(14);
//设置顶部标题栏下划线颜色
picker.setTopLineColor(ContextCompat.getColor(mContext, R.color.white1));
//设置分割线颜色
picker.setDividerColor(ContextCompat.getColor(mContext, R.color.white1));
//设置确定按钮文字颜色
picker.setSubmitTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setSubmitTextSize(14);
//设置标题文字颜色
picker.setTitleTextColor(ContextCompat.getColor(mContext, R.color.gray5));
//设置标题文字
picker.setTitleText("选择税率");
//设置标题文字大小
picker.setTitleTextSize(14);
picker.setOnOptionPickListener(onOptionPickListener);
picker.show();
}
/**
* 地址 - 因为加载本地的json文件,所以有时候会有一些卡顿
*/
public static void setPlace(Activity mContext, final PlaceListener placeListener) {
ArrayList<Province> data = new ArrayList<>();
String json = AssetsUtils.getStringFromAssert(mContext, "city.json");
data.addAll(JSON.parseArray(json, Province.class));
AddressPicker picker = new AddressPicker(mContext, data);
picker.setSelectedItem("上海", "上海市", "浦东新区");
//设置取消按钮文字颜色
picker.setCancelTextColor(ContextCompat.getColor(mContext, R.color.gray1));
//设置取消按钮文字大小
picker.setCancelTextSize(14);
//设置顶部标题栏下划线颜色
picker.setTopLineColor(ContextCompat.getColor(mContext, R.color.white1));
//设置分割线颜色
picker.setDividerColor(ContextCompat.getColor(mContext, R.color.white1));
//设置确定按钮文字颜色
picker.setSubmitTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setTextColor(ContextCompat.getColor(mContext, R.color.blue2));
picker.setSubmitTextSize(14);
//设置标题文字颜色
picker.setTitleTextColor(ContextCompat.getColor(mContext, R.color.gray5));
//设置标题文字
picker.setTitleText("选择城市区域");
//设置标题文字大小
picker.setTitleTextSize(14);
picker.setOnAddressPickListener(new AddressPicker.OnAddressPickListener() {
@Override
public void onAddressPicked(Province province, City city, County county) {
placeListener.setProvince(province.getAreaName());
//城市
placeListener.setCity(city.getAreaName());
//区县(如果设定了两级联动,那么该项返回空)
placeListener.setDistrict(county.getAreaName());
//全部地址
placeListener.setAllPlace(province.getAreaName() + " " + city.getAreaName() + " " + county.getAreaName());
}
});
picker.show();
}
注意
-
使用 地址选择器时,需要在
assets
文件夹下加入 “city.json” - city.json地址 -
因为要数据回调,需要一个接口
package com.bakheet.garage.mine.listener;
/**
* author YongLiu
* date 2017/12/14.
* desc:
*/
public interface PlaceListener {
void setProvince(String province);
void setCity(String city);
void setDistrict(String district);
void setAllPlace(String allPlace);
}
错误提示
如出现 Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with
build
//注释framework:WheelPicker:latest这个引用,引用下方新的AndroidPicker
//compile 'cn.qqtheme.framework:WheelPicker:latest.integration'
compile 'cn.qqtheme.framework:AndroidPicker:latest.integration'
同时修改DateUtil内的 DateTimePicker 为 DatePicker(可参考此处)
2022年
build(app) - 加入
//生日、地址、日期等选择器
implementation 'com.github.gzu-liyujiang.AndroidPicker:Common:4.1.6'
implementation 'com.github.gzu-liyujiang.AndroidPicker:AddressPicker:4.1.6'
implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.6'
implementation 'com.github.gzu-liyujiang.AndroidPicker:ImagePicker:4.1.6'
这是我在新项目某个类中用到的AndroidPicker方法
,涉及单项选择器(男、女性别)、地址选择器、日期选择器、时间(日期)选择器
,因为我用的的Kt+MVVM+ViewBind等等,所以看对应选择器方法即可
~
伪代码示例
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.lifecycle.Observer
import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.ToastUtils
import com.github.gzuliyujiang.imagepicker.ActivityBuilder
import com.github.gzuliyujiang.imagepicker.CropImageView
import com.github.gzuliyujiang.imagepicker.ImagePicker
import com.github.gzuliyujiang.imagepicker.PickCallback
import com.github.gzuliyujiang.wheelpicker.BirthdayPicker
import com.github.gzuliyujiang.wheelpicker.SexPicker
import com.github.gzuliyujiang.wheelpicker.contract.OnDatePickedListener
import com.github.gzuliyujiang.wheelpicker.contract.OnOptionPickedListener
import com.google.android.material.bottomsheet.BottomSheetDialog
import org.koin.androidx.viewmodel.ext.android.viewModel
import java.text.SimpleDateFormat
/**
* author: ly
* dsc: 信息完善
*/
class PerfectionActivity : BaseActivity<ActivityPerfectionBinding>(),
View.OnClickListener, OnDatePickedListener, OnOptionPickedListener, OnAddressPickedListener {
var updateBirthday: String = ""
private var sexDate = true
override fun initView() {
binding.csGenderParent.setOnClickListener(this)
binding.csCityParent.setOnClickListener(this)
binding.csBirthdayParent.setOnClickListener(this)
}
override fun initData() {}
override fun observerData() {}
override fun onClick(v: View?) {
when (v?.id) {
binding.csGenderParent.id -> genderDialog()
binding.csCityParent.id -> { addressDialog()}
binding.csBirthdayParent.id -> {
var tvBirthday = binding.tvBirthday.text.toString()
if (tvBirthday.isNullOrEmpty()) {
tvBirthday = "2022-3-14"
}
birthdayDialog(tvBirthday)
}
}
}
//地址选择器
fun addressDialog() {
val picker = AddressPicker(this)
picker.setAddressMode(AddressMode.PROVINCE_CITY_COUNTY)
picker.setDefaultValue("上海市", "上海市", "黄浦区")
picker.setOnAddressPickedListener(this);
picker.wheelLayout.setOnLinkageSelectedListener(object : OnLinkageSelectedListener {
override fun onLinkageSelected(first: Any?, second: Any?, third: Any?) {
picker.getTitleView().setText(
String.format(
"%s%s%s",
picker.getFirstWheelView().formatItem(first),
picker.getSecondWheelView().formatItem(second),
picker.getThirdWheelView().formatItem(third)
)
);
}
})
picker.show();
}
//性别单项选择器
private fun genderDialog() {
val picker = SexPicker(this)
picker.setBodyWidth(140)
picker.setIncludeSecrecy(false)
if (sexDate) {
picker.setDefaultValue("男")
} else {
picker.setDefaultValue("女")
}
picker.setOnOptionPickedListener(this)
picker.wheelLayout.setOnOptionSelectedListener { position, item -> }
picker.show()
}
//日期选择器
private fun birthdayDialog(birthday: String = "2022-3-14") {
val picker = BirthdayPicker(this)
var split = birthday.split("-".toRegex())
picker.setDefaultValue(split[0].toInt(), split[1].toInt(), split[2].toInt())
picker.setOnDatePickedListener(this)
picker.wheelLayout.setResetWhenLinkage(false)
picker.show()
}
//地址选择器 - 回调
override fun onAddressPicked(
province: ProvinceEntity?,
city: CityEntity?,
county: CountyEntity?
) {
binding.tvAddress.setText(province?.name + city?.name + county?.name)
}
//日期选择器 - 回调(已优化)
override fun onDatePicked(year: Int, month: Int, day: Int) {
//最简单 - binding.tvBirthday.setText("$year-$month-$day")
var tmpMonth = ""
var tmpDay = ""
tmpMonth = if (month < 10) {
"0" + month
} else {
month.toString()
}
tmpDay = if (day < 10) {
"0" + day
} else {
day.toString()
}
var date = "$year-$tmpMonth-$tmpDay"
val sdf = SimpleDateFormat("yyyy-MM-dd")
val millionSeconds = sdf.parse(date).time.toString()
//对应时间戳,主要用于传后台
var uploadTime = millionSeconds.substring(0, millionSeconds.length - 3)
Log.e("tag", millionSeconds)
Log.e("tag", uploadTime)
updateBirthday = uploadTime
binding.tvBirthday.text = date
}
//性别选择器 - 回调(已优化)
override fun onOptionPicked(position: Int, item: Any?) {
if (position == 0) {
sexDate = true
binding.tvGender.text = "男"
} else {
sexDate = false
binding.tvGender.text = "女"
}
}
}