android自定义滚轴选择器_Android自定义滚动式时间选择器(在他人基础上修改)...
盡管Android給我們提供了時間選擇控件DatePicker和TimePicker(它們的使用方法可以參考我的這篇文章Android之日期時間選擇控件DatePicker和TimePicker),但無奈我的項目主色調是土豪金和高級黑,原生的控件用在里面顯得格格不入,特別是為了兼容低版本的系統之后顯示的是2.x年代的風格,不但是簡陋,簡直是丑陋了。要解決這種問題,就只有走自定義控件這條道。但我目前還是不太熟悉自定義控件的寫法,所以只好發揮拿來主義了。查看了一通之后,發現liuwan1992這位博主寫的非常漂亮,我在他的基礎上做了一些改動,使得整個控件更符合我的項目。
這是他的文章鏈接:Android 好看的自定義滾動式日期選擇控件,關于控件的使用大家直接閱讀他的文章即可。在此,感謝他的付出,本人只是巨人肩膀上的小白而已。
1、創建工程
你可以下載博主的源碼,用Android Studio打開之后就直接動手修改,也可以像我這樣新建一個工程,然后將需要用到的代碼和文件從源碼復制過來即可。
2、修改對話框外觀
由于我需要用到我自己的顏色,所以在colors.xml中做了一些改動:
#3F51B5
#303F9F
#FF4081
#F0F0F0 //年、月、日等單位的字體顏色
#FFFFFF
#B0B0B0 //未被選中的數字顏色
#666666
#57C5E8
#b0000000 //作為背景的高級黑
#ffda53 //作為字體的土豪金
其中color_bg和color_gold分別是背景高級黑和字體土豪金。
資源文件準備好之后,就可以到對話框的布局custom_date_picker.xml中修改背景和字體顏色了。滾輪中選中和未選中的字體顏色則需要到DatePickerView中修改:
private void init() {
timer = new Timer();
mDataList = new ArrayList<>();
//第一個paint
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Style.FILL);
mPaint.setTextAlign(Align.CENTER);
//被選中的數字顏色
mPaint.setColor(ContextCompat.getColor(context, R.color.color_gold));
//第二個paint
nPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
nPaint.setStyle(Style.FILL);
nPaint.setTextAlign(Align.CENTER);
//未選中的數字顏色
nPaint.setColor(ContextCompat.getColor(context, R.color.color_text_unselected));
}
修改完的效果如下,項目需求如此,如果覺得辣眼睛的請多多諒解。
3、給控件增加標題
雖然選擇的都是時間,但是如果我們在控件的標題中告訴用戶當前要選擇的是什么時間的話就更好一點。比如用戶要確定一個時間段的話,我們就可以在彈出的控件上顯示要選擇的是“起始時間”還是“結束時間”。因此,我們可以在CustomDatePicker的構造函數中再增加一個參數:
public CustomDatePicker(Context context,String title, ResultHandler resultHandler, String startDate, String endDate) {
}
這樣在創建控件時我們就可以把控件的標題傳進去了。
4、點擊控件以外的區域讓控件消失
這個修改比較簡單,我們的時間選擇控件其實就是一個Dialog,只要將setCancelable方法設置為true就可以了。
5、修改選擇順序
這個控件的時間選擇順序默認是“年-月-日-時-分”,也就是選好了年才能選擇月,選好了月才能選擇日,從左到右。但是如果用戶先確定了日,再去選擇月的話,之后月份改變,日數就會重新從1開始。用戶體驗無疑是十分糟糕的,所以我們要把用戶的每一步選擇都保存下來,使控件可以從右到左選擇時間。毫無疑問,這就需要到CustomDatePicker中改動了,因此,這一步的修改是最復雜也是最關鍵的。
5.1 保存用戶選好的時間數據
打開CustomDatePicker文件,創建以下幾個String變量:
private String currentMon, currentDay, currentHour, currentMin; //當前選中的月、日、時、分
年份位于最左端,“權限”是最高的,不會受其它數據的影響,可以不必保存。仔細想想,我們需要在兩種情況下保存選中的日期數據:
用戶滑動滾輪之后,保存選擇的數據;
用戶沒有滑動滾輪,但是點擊了對話框上的“確認”按鈕
源碼中,對于每個滾輪的滾動都寫了監聽方法,我們可以在每個監聽方法中賦值:
private void addListener() {
year_pv.setOnSelectListener(new DatePickerView.onSelectListener() {
@Override
public void onSelect(String text) {
selectedCalender.set(Calendar.YEAR, Integer.parseInt(text));
monthChange();
}
});
month_pv.setOnSelectListener(new DatePickerView.onSelectListener() {
@Override
public void onSelect(String text) {
selectedCalender.set(Calendar.DAY_OF_MONTH, 1);
selectedCalender.set(Calendar.MONTH, Integer.parseInt(text) - 1);
currentMon = text; //保存選擇的月份
dayChange();
}
});
day_pv.setOnSelectListener(new DatePickerView.onSelectListener() {
@Override
public void onSelect(String text) {
selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(text));
currentDay = text;//保存選擇的日期
hourChange();
}
});
hour_pv.setOnSelectListener(new DatePickerView.onSelectListener() {
@Override
public void onSelect(String text) {
selectedCalender.set(Calendar.HOUR_OF_DAY, Integer.parseInt(text));
currentHour = text; //保存選擇的小時
minuteChange();
}
});
minute_pv.setOnSelectListener(new DatePickerView.onSelectListener() {
@Override
public void onSelect(String text) {
selectedCalender.set(Calendar.MINUTE, Integer.parseInt(text));
currentMin = text; //保存選擇的分鐘
}
});
}
如果用戶沒有滑動滾輪,那么滾動監聽事件就不會觸發,這時就要到設置默認選中時間的方法setSelectedTime方法中去賦值了,比如分鐘的賦值:
currentMin = timeStr[1]; //保存選擇的分鐘
其它的時間數據同理,代碼太長,這里就不貼了,大家直接看Demo吧。
5.2 時間數據之間的聯動邏輯
保存好數據之后還沒有完,要知道,各個時間數據之間并不是可以任意選擇的,它們之間是相互關聯,相互制約的,特別是當你規定了最大時間不超過當前時間時。比如假設現在是2017年05月24日15:30,當我滑到2017年5月23日16:00,此時再將日改回24日時,時間顯然是不能超過15:30的。這時就要做一些判斷了。
以分鐘的數值為例,如果當前的分鐘數值小于60,而且之前選擇的分鐘數值比當前的分鐘數值大,那么就要將分鐘數值修改為當前的分鐘時間,否則繼續沿用之前的數值。
閱讀源碼可以看到,修改分鐘數值的方法為minuteChange,將復位處理的代碼注釋之后,然后加上我們的邏輯判斷。
// selectedCalender.set(Calendar.MINUTE, Integer.parseInt(minute.get(0)));
// minute_pv.setSelected(0);
if (minute.size() < 60 && minute.size() < Integer.valueOf(currentMin)) {
minute_pv.setSelected(minute.size() - 1);
selectedCalender.set(Calendar.MINUTE, minute.size());
//改變當前選擇的分鐘
currentMin = formatTimeUnit(minute.size());
} else {
minute_pv.setSelected(currentMin);
selectedCalender.set(Calendar.MINUTE, Integer.parseInt(currentMin));
}
小時的判斷跟分鐘的差不多,這里就貼代碼了,但是月份的就有點特殊了,因為無論哪一天都是24小時,無論哪一小時都有60分鐘,而每個月的天數卻不盡相同,比如二月份就只有28或者29天。我們需要再創建一個int值變量lastMonthDays來記錄上一個被選中的月份的天數。當前選中的月份天數比之前選中的月份天數少,而且之前選中的日的數值比當前選中的月份天數還有大時,那么日的數值就必須改為這個月的最后一天了。舉個例子,比如將2017年3月31日中月份改為2月份,由于二月份只有28天,那么日的數值就不能停留在31了,而是跳轉到28。
在dayChange方法中的代碼修改如下:
// selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day.get(0)));
// day_pv.setSelected(0);
if (day.size() < lastMonthDays && Integer.valueOf(currentDay) > day.size()) {
day_pv.setSelected(day.size() - 1);
currentDay = formatTimeUnit(day.size());
} else {
day_pv.setSelected(currentDay);
}
selectedCalender.set(Calendar.DAY_OF_MONTH, Integer.parseInt(currentDay));
//重新賦值
lastMonthDays = day.size();
最后,當然也別忘了到setSelectedTime中給lastMonthDays設置默認值。
lastMonthDays = day.size();
6、將某一列的數值設為單獨循環滾動
盡管源碼中已經有setIsLoop方法可以設置為循環滾動,但是這個是將所有列都同時設置為循環滾動的,如果我們想單獨將某一列設為循環滾動的話可以再增加幾個方法:
public void setYearIsLoop(boolean isLoop) {
if (canAccess) {
this.year_pv.setIsLoop(isLoop);
}
}
public void setMonIsLoop(boolean isLoop) {
if (canAccess) {
this.month_pv.setIsLoop(isLoop);
}
}
public void setDayIsLoop(boolean isLoop) {
if (canAccess) {
this.day_pv.setIsLoop(isLoop);
}
}
public void setHourIsLoop(boolean isLoop) {
if (canAccess) {
this.hour_pv.setIsLoop(isLoop);
}
}
public void setMinIsLoop(boolean isLoop) {
if (canAccess) {
this.minute_pv.setIsLoop(isLoop);
}
}
7、去除對話框與屏幕之間的間距
這個問題我在Demo中沒有發現,整合到工程中才遇到。彈出對話框時,左右和底部有一定的間距始終消除不了,但是在初始化對話框的方法initDialog方法中加了下面的代碼就可以了:
window.setBackgroundDrawableResource(R.color.color_bg);
顏色的值可以是透明的,但個人覺得最后還是設置一個背景色。這個問題,目前我也沒有找到原因……
8、總結
經過上面一番改動,我可以愉快地整合到我自己的項目中了,個人覺得這個控件挺美觀實用的,歡迎大家支持原博主。如果大家有什么好的改動,也歡迎給我留言。下面附上源碼:
總結
以上是生活随笔為你收集整理的android自定义滚轴选择器_Android自定义滚动式时间选择器(在他人基础上修改)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 组件监听页面切换_vue项目如何
- 下一篇: javamail课设_JAVA MAIL