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…