If you see this article, I hope you have the patience to finish it. I promise you’ll read them all and you won’t be disappointed. Because you’ve probably come across the best PickerView library ever. This article will make a detailed comparison with the most popular PickerView library on Github so that you can clearly feel its ease of use and power.
Github address: github.com/jaaksi/pick…
A very useful Android PickerView library, internal provides three common types of Picker. Support for extended custom pickers.
- TimePicker: a TimePicker that contains dates
- MixedTimePicker: : Time picker for aggregation
- OptionPicker: linkage picker
Screenshot
TimePicker.gif
MixedTimePicker.gif
custom.png
APK
Demo App download connection
PickerView
README
Picker
Implement the commonly used Picker selector by assembling a PickerView. The three commonly used pickers provided have been listed above.
BasePicker
Picker base class: encapsulates TopBar, PickerView container, Create and add PickerView methods, Picker popovers, etc. All three kinds of pickers inherit from BasePicker, and you can extend your own Picker by inheriting from it.
API
api | description |
---|---|
setPickerBackgroundColor | Set the picker background |
setPadding | Set the PickerView parent container padding unit to px |
setTag | Tag the Picker to distinguish between different pickers and so on. Use the same as View setTag |
getRootLayout | Gets the parent container of the PickerView, which must be specified when creating DefaultTopBar |
setOnPickerChooseListener | Set picker cancel to make sure the button listens. Can be used to intercept selected operations |
setTopBar | Set a custom TopBar |
setInterceptor | Setting up interceptors |
createPickerView | Create PickerView |
getPickerViews | Gets the collection of all pickerViews in the Picker |
addPicker | Add the created PickerView to the collection above, and the method is already called inside the createPickerView |
findPickerViewByTag | Find the corresponding PickerView by tag |
isScrolling | Whether scrolling has not stopped. Do not respond to Picker’s cancel while scrolling |
getPickerDialog | Get the Picker popover. The Dialog property can be set after new |
show | Shows the Picker popover |
The Android PickerView library encapsulates general related logic, such as TopBar, in a base class and provides code to create PickerView methods without relying on XML. When you customize the Picker, you inherit from BasePicker and just need to handle your own logic, which is easy and convenient. For Android-PickerView, the implementation of custom Picker still needs to deal with TopBar and other logic. Resulting in a lot of duplicate code.
TopBar
TopBar:TopBar is managed through the abstract interface ITopBar, which decouples Picker from TopBar. Provide a default implementation DefaultTopBar. You can implement your own TopBar interface customization.
public interface ITopBar { /** * @return topbar view */ View getTopBarView(); /** * @return Cancel button view */ view getBtnCancel(); /** * @return confirm button view */ view getBtnConfirm(); /** * @return title view */ TextView getTitleView(); }Copy the code
DefaultTopBar API
api | description |
---|---|
setDividerColor | Set topbar Bottom Line color |
setDividerHeight | Set the bottom Divider line height |
getDivider | Get the TopBar Bottom line |
getTitleView | Get the TopBar Title View |
Interceptor
Interceptor: Used to intercept the pickerView when it is created, setting the properties of the pickerView.
The Picker does not provide a method to set the PickerView internally, but is provided by the Interceptor. This is designed to perfectly decouple the Picker from the PickerView’s property Settings.
private void init(){ mTimePicker.setInterceptor(new BasePicker.Interceptor() { @Override public void intercept(PickerView pickerView) { pickerView.setVisibleItemCount(5); // Set year to loop int type = (int) pickerView.getTag(); if (type == TimePicker.TYPE_YEAR || type == TimePicker.TYPE_MONTH) { pickerView.setIsCirculation(true); }}})}Copy the code
This is compared to android-pickerView. Each Picker needs to declare the setting method of the PickerView, which is heavily coupled with the PickerView. It requires a lot of duplicate code for developers to copy, and there is no way to distinguish between the different properties set for each PickerView.
TimePicker
Commonly used time picker, supporting year, month, day, hour, minute
- Design of time types: Free combination, arbitrary (of course it should make sense)
TYPE_YEAR | TYPE_MONTH | TYPE_DAY | TYPE_HOUR | TYPE_MINUTE
Copy the code
Compared with Android – PickerView TimePickerView
/**
* Android-PickerView中的设置type方法:参数设置麻烦且不易理解
* 长度必须为6的数组,表示年月日时分秒 的显示与否,不设置则默认全部显示
*/
setType(boolean[] type)
// 本项目设置type方法:简单易懂,组合方便
setType(TYPE_DATE | TYPE_HOUR)
Copy the code
- Perfect support for time interval setting and selected linkage
- Support Format, such as display this year, next year
API
api | description |
---|---|
type | The time type, which needs to be specified in the Builder constructor, cannot be changed |
OnTimeSelectListener | Select the time callback, which needs to be specified in the Builder constructor and cannot be changed |
setRangDate | Set the start and end times |
setSelectedDate | Set the selected timestamp |
setInterceptor | Setting up interceptors |
setFormatter | Sets the Formatter, internally providing the default Formatter |
create | Build TimePicker with Builder |
The above is for timepicker. Builder and the following is for TimePicker | |
setFormatter | Same as above |
setSelectedDate | Same as above |
getType | Get the type |
hasType | Determines whether a type is included |
Formatter
TimePicker Formatter: Used to format time copy by type and num
Public interface Formatter {/** * public interface Formatter {/** * public interface Formatter {/** * public interface Formatter {/** * public interface Formatter {/** * @param picker * @param position position * @param num Position item Number displayed */ CharSequence format(TimePicker picker, int type, int position, int num); }Copy the code
The DefaultFormatter implementation DefaultFormatter is provided internally. Users can set a custom Formatter or extend it by inheriting DefaultFormatter.
TimePicker initializes, if no time interval is set, the default interval is used. All three pickers are initialized in Builder mode. User-defined pickers should also be initialized in this mode.
Simple Example
SetRangDate (1526361240000L) Is the biggest monthly user in the world. The value is new timepicker. Builder(mActivity, type, this). SetSelectedDate () // Set pickerView style.setInterceptor (new Basepicker.interceptor () { @Override public void intercept(PickerView pickerView) { pickerView.setVisibleItemCount(5); // Set year to loop int type = (int) pickerView.getTag(); if (type == TimePicker.TYPE_YEAR || type == TimePicker.TYPE_MONTH) { pickerView.setIsCirculation(true); }}}) / / set the Formatter. SetFormatter (new TimePicker. DefaultFormatter () {/ / custom Formatter according to last year, this year, @override public CharSequence format(TimePicker picker, int type, int position, int num) { if (type == TimePicker.TYPE_YEAR) { int offset = num - mCurrYear; If (offset == -1) return "last "; If (offset == 0) return "year "; If (offset == 1) return "next year "; Return num + "year "; } return super.format(picker, type, position, num); } }).create(); //mTimePicker.setSelectedDate(1549349843000L); mTimePicker.show();Copy the code
MixedTimePicker
Common aggregation time picker. Date (year, month, day) aggregation, time (hour, minute) aggregation.
- Mixed mode: Almost no TimePicker library on Github offers this type of Picker
- Support custom date format, time format
- You can set the interval
- You can set ranges and select linkage
- Support to set pure date, pure time mode, using type and TimePicker
API
api | description |
---|---|
type | Type, which needs to be specified in the Builder constructor and cannot be changed |
OnTimeSelectListener | Select the time callback, which needs to be specified in the Builder constructor and cannot be changed |
setRangDate | Set the start and end times |
setSelectedDate | Set the selected timestamp |
setTimeMinuteOffset | Set the interval minutes (valid only when 60%offset==0), starting with 0 |
setContainsStarDate | Whether to contain the exceeded startDate when setting mTimeMinuteOffset |
setContainsEndDate | Set mTimeMinuteOffset to contain the excess endDate |
setInterceptor | Setting up interceptors |
setFormatter | Sets the Formatter, internally providing the default Formatter |
create | Build the MixedTimePicker with the Builder |
Mixedtimepicker. Builder and MixedTimePicker | |
setFormatter | Same as above |
setSelectedDate | Same as above |
getType | Get the type |
hasType | Determines whether a type is included |
Formatter
MixedTimePicker Formatter: Used to customize date and time formats. The default Formatter implementation is provided internally.
Public interface Formatter {/** ** You can customize the date format and time format ** @param picker picker * @param date Date or time corresponding to the current status * @param Position Position */ CharSequence format(MixedTimePicker picker, int type, Date Date, int position); }Copy the code
MixedTimePicker’s Formatter perfectly illustrates the subtleties of Formatter design. You can customize the date and time format based on type and date in the callback. Such as today, or xx, xx, day, week x
Simple Example
mTimePicker = new MixedTimePicker.Builder(mActivity, MixedTimePicker.TYPE_ALL, <=.setContainSendDate (false) // Set the interval to 30 minutes. SetTimeMinuteOffset (30).setrangDate (1517771651000L, 1577976666000L) .setFormatter(new MixedTimePicker.DefaultFormatter() { @Override public CharSequence format(MixedTimePicker picker, int type, Date date, int position) { if (type == MixedTimePicker.TYPE_DATE) { CharSequence text; int dayOffset = DateUtil.getDayOffset(date.getTime(), System.currentTimeMillis()); If (dayOffset == 0) {text = "today "; } else if (dayOffset == 1) {text = "tomorrow "; } else {// xx month xx day week x text = mdateformat.format (date); } return text; } return super.format(picker, type, date, position); } }) .create(); // 2018/2/5 03:14:11 - 2020/1/2 22:51:6 Dialog pickerDialog = mTimePicker.getPickerDialog(); pickerDialog.setCanceledOnTouchOutside(true); DefaultTopBar topBar = (DefaultTopBar) mTimePicker.getTopBar(); Topbar.gettitleview ().settext (" Please select time ");Copy the code
Unlike TimePicker, MixedTimePicker does not provide a default range because it supports a pure time mode (the date takes the date of the selected time). If the schema contains a date schema, the time interval is forced </font>
OptionPicker
- Support setting hierarchy
- Constructing a data source is extremely simple, requiring only the implementation of the OptionDataSet interface
- You can set the selected item through values. Internal processing of the selected item logic, avoid user record subscript and cumbersome traversal processing
Compare the Android-PickerView OptionsPickerView
function | Android-PickerViews | This control |
---|---|---|
multistage | Supports up to 3 levels (written dead) | Set level when building (unrestricted) |
Constructing the data source | The collection of each level needs to be built, and the second and third levels are nested | The level-1 data entity can implement the OptionDataSet interface |
Setting a Data source | Three methods are provided for primary, secondary and tertiary | You only need to set up a level 1 dataset |
Linkage is selected | Provides three, can only set the selected subscript. The user needs to navigate through multiple levels to locate the selected subscript at each level and then set it |
You just pass in the selected values(variable length array) without any calculation |
OptionsPickerView code in android-PickerView. Since the hierarchy is not known, each method provides three to correspond to (at most) three levels of selection.
// Provide three selected methods, Public void setSelectOptions(int option1) public void setSelectOptions(int Option1, Int option2) public void setSelectOptions(int option1, int option2, int option3) Public void setPicker(List<T> optionsItems) public void setPicker(List<T> options1Items, List<List<T>> options2Items) public void setPicker(List<T> options1Items, List<List<T>> options2Items, List<List<List<T>>> options3Items) { }Copy the code
OptionPicker in this library
/** * Initializes the selected position based on the selected values and initializes pickerView data ** @param options data * @param values Selects the value of the data {@link OptionDataSet#getValue()} */ public void setDataWithValues(List<? extends OptionDataSet> options, String... values) { mOptions = options; setSelectedWithValues(values); Position ** @param values select data value{@link OptionDataSet#getValue()}, if values[0]==null, */ public void setSelectedWithValues(String... values) { ... }Copy the code
As illustrated in the comparison table above, the library’s API is simple and convenient for hierarchy, constructing and setting data sources, and setting selected options.
API
api | description |
---|---|
mHierarchy | The hierarchy, which needs to be specified in the Builder constructor, cannot be changed |
OnOptionSelectListener | Select the callback, which needs to be specified in the Builder constructor and cannot be changed |
setInterceptor | Setting up interceptors |
setFormatter | Set the Formatter |
create | Build an OptionPicker with the Builder |
This is OptionPicker.Builder, and this is OptionPicker | |
setFormatter | Same as above |
setDataWithValues | Initialize the selected position based on the selected values and initialize the PickerView data. The values argument is a variable length array and can be left unchecked. |
setDataWithIndexs | Set the data and select Position. SetDataWithValues is not recommended |
setSelectedWithValues | Initializes the selected position based on the selected values |
setSelectedWithIndexs | Sets the selected position. SetSelectedWithValues is not recommended |
getOptions | Get data set |
getSelectedPosition | Get the selected subscript, size=mHierarchy, -1 indicates that the column has no data |
getSelectedOptions | Gets the selected option. If index is null, the column has no data |
Note that the OptionPicker in this library is only used for linkage, and does not support multiple levels and no linkage. There is very little need for this, and if there is a need for this, I will support it in subsequent iterations.
Others
Weird design: Some default properties are declared static instead of final
Set the default property globally
Weird or brilliant. As a UI control, different APP, different UI, different products will naturally have different styles. Given that we use a lot of pickers in an app, and we need to customize the style of our UI, it would be too much trouble to style it dynamically. So do this design. You can configure these static variables to quickly customize a Picker that meets your app style requirements. Of course, you can also wrap methods to handle PickerView, Picker, decorator, etc., but that’s still a hassle. I’m sure you’d hate it yourself.
Static defaults
All of these static property values start with sDefault
- BasePickerView
field | description | defaultValue |
---|---|---|
sDefaultVisibleItemCount | Number of items visible by default | 5 |
sDefaultItemSize | The default itemSize | 50(dp) |
sDefaultIsCirculation | Whether to loop by default | false |
- PickerView
field | description | defaultValue |
---|---|---|
sOutTextSize | default out text size | 18(dp) |
sCenterTextSize | default center text size | 22(dp) |
sCenterColor | default center text color | Color.BLUE |
sOutColor | default out text color | Color.GRAY |
- BasePicker
field | description | defaultValue |
---|---|---|
sDefaultPaddingRect | Default padding of the pickerView parent container | Null (no padding) |
sDefaultPickerBackgroundColor | default picker background color | Color.WHITE |
sDefaultTopBarCreator | Interface for building a custom defaultTopBar | null |
- DefaultCenterDecoration
field | description | defaultValue |
---|---|---|
sDefaultLineColor | default line color | Color.BLUE |
sDefaultLineWidth | default line width | 1(dp) |
sDefaultDrawable | default item background drawable | null |
sDefaultMarginRect | default line margin | Null (no margin) |
It is recommended that these attribute values be initialized in Application to avoid the failure caused by app crash
Simple Example
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); InitDefaultPicker (); } private void initDefaultPicker() {private void initDefaultPicker() { Rapid customization a Picker to satisfy his app style demand. / / BasePickerView PickerView. SDefaultVisibleItemCount = 3; PickerView.sDefaultItemSize = 50; PickerView.sDefaultIsCirculation = true; // PickerView PickerView.sOutTextSize = 18; PickerView.sCenterTextSize = 18; PickerView.sCenterColor = Color.RED; PickerView.sOutColor = Color.GRAY; // BasePicker int padding = Util.dip2px(this, 20); BasePicker.sDefaultPaddingRect = new Rect(padding, padding, padding, padding); BasePicker.sDefaultPickerBackgroundColor = Color.WHITE; . / / custom TopBar BasePicker sDefaultTopBarCreator = new BasePicker. IDefaultTopBarCreator () {@ Override public ITopBar createDefaultTopBar(LinearLayout parent) { return new CustomTopBar(parent); }}; // DefaultCenterDecoration DefaultCenterDecoration.sDefaultLineWidth = 1; DefaultCenterDecoration.sDefaultLineColor = Color.RED; //DefaultCenterDecoration.sDefaultDrawable = new ColorDrawable(Color.WHITE); int leftMargin = Util.dip2px(this, 10); int topMargin = Util.dip2px(this, 2); DefaultCenterDecoration.sDefaultMarginRect = new Rect(leftMargin, -topMargin, leftMargin, -topMargin); }}Copy the code
Change Log
V1.0.0 (2018-03-03)
- Release v1.0.0
Gradle
The compile ‘org. Jaaksi: pickerview: 1.0.0 @ aar’
Thanks
- ScrollPickerView
- Android-PickerView
Thank you for your patience. Comments are welcome. Github address: github.com/jaaksi/pick…