├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── direct-select-example-advanced ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ramotion │ │ └── directselect │ │ └── examples │ │ └── advanced │ │ ├── AdvancedExampleActivity.java │ │ ├── AdvancedExampleCountryAdapter.java │ │ ├── AdvancedExampleCountryPOJO.java │ │ └── AdvancedExampleCountryPickerBox.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ds_bg_list_selector.xml │ ├── ds_bg_picker_box.xml │ ├── ds_countries_ar.png │ ├── ds_countries_au.png │ ├── ds_countries_br.png │ ├── ds_countries_ca.png │ ├── ds_countries_cn.png │ ├── ds_countries_dz.png │ ├── ds_countries_in.png │ ├── ds_countries_kz.png │ ├── ds_countries_ru.png │ ├── ds_countries_us.png │ ├── ds_picker_box_arrows.png │ └── ic_launcher_background.xml │ ├── layout │ ├── advanced_example_activity.xml │ ├── advanced_example_country_cell.xml │ ├── advanced_example_country_list_item.xml │ └── advanced_example_country_picker_box.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── arrays.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── direct-select-example-basic ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ramotion │ │ └── directselect │ │ └── examples │ │ └── basic │ │ └── BasicExampleActivity.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ds_basic_example_custom_picker_box_bg.xml │ └── ic_launcher_background.xml │ ├── layout │ └── ds_basic_example_activity.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── arrays.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── direct-select ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ramotion │ │ └── directselect │ │ ├── AnimationListenerAdapter.java │ │ ├── CustomListView.java │ │ ├── DSAbstractPickerBox.java │ │ ├── DSDefaultAdapter.java │ │ ├── DSDefaultPickerBox.java │ │ └── DSListView.java │ └── res │ ├── layout │ ├── ds_default_cell.xml │ ├── ds_default_list_item.xml │ ├── ds_default_picker_box.xml │ └── ds_list_view.xml │ └── values │ └── attr.xml ├── direct_select_preview.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── header.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Java compiled classes # 2 | *.class 3 | 4 | # Package Files # 5 | *.apk 6 | *.ap_ 7 | 8 | # IDEA Project files # 9 | *.iws 10 | *.iml 11 | *.ipr 12 | .idea/ 13 | 14 | # Build directory # 15 | /build/ 16 | /target/ 17 | */target/ 18 | */build/ 19 | 20 | # Generated files # 21 | bin/ 22 | gen/ 23 | 24 | # Local props file # 25 | local.properties 26 | 27 | # Gradle cache # 28 | .gradle 29 | 30 | # OSX files # 31 | .DS_Store 32 | 33 | # NDK # 34 | obj/ 35 | 36 | # files for the dex VM # 37 | *.dex 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ramotion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

DIRECT SELECT [JAVA]

7 | 8 |

Selection widget with an ethereal, full-screen modal popup displaying the available choices

9 | 10 | 11 | ___ 12 | 13 | 14 |

We specialize in the designing and coding of custom UI for Mobile Apps and Websites.
15 | 16 | 17 |

18 |

Stay tuned for the latest updates:
19 | 20 |

21 | 22 | Inspired by [Virgil Pana](https://dribbble.com/virgilpana) [shot](https://dribbble.com/shots/3876250-DirectSelect-Dropdown-ux) 23 | 24 | ## Requirements 25 | - Android 4.0 IceCreamSandwich (API lvl 14) or greater 26 | - Your favorite IDE 27 | ## Installation 28 | Just download the package from [here](http://central.maven.org/maven2/com/ramotion/directselect/direct-select/0.1.1/direct-select-0.1.1.aar) and add it to your project classpath, or use it as dependency in your build tool: 29 | - Gradle: 30 | ```groovy 31 | 'com.ramotion.directselect:direct-select:0.1.1' 32 | ``` 33 | - SBT: 34 | ```scala 35 | libraryDependencies += "com.ramotion.directselect" % "direct-select" % "0.1.1" 36 | ``` 37 | - Maven: 38 | ```xml 39 | 40 | com.ramotion.directselect 41 | direct-select 42 | 0.1.1 43 | 44 | ``` 45 | ## Basic usage 46 | Basic usage assumes a simple configuration through xml layout without writing program code, but this doesn't provide the possibility to create cells with custom content layout for your lists and pickers. 47 | So, all you need is two elements in your layout: 48 | ```xml 49 | 50 | 56 | 57 | 71 | 72 | 79 | 80 | 81 | ``` 82 | `DSListView` represents a list with options for the picker that shows up when the user touches a `DSDefaultPickerBox` element and hides when the user removes his finger from the screen. `DSListView` has a couple of custom attributes, some of them are required, some not, here is a list: 83 | - **`data_array`** is a required reference to your selector options represented as array of strings in application resources. 84 | - **`picker_box_view`** is a required reference to implemented picker box element, you can use default implementation provided by the library `DSDefaultPickerBox` or you can implement your own as shown in the advanced usage example in this repository. 85 | - **`selector_background`** is a drawable or color responsible for a highlighting of selector position when `DSListView` is shown on the screen. Using the same background as in your PickerBox element you can achieve a pretty nice and clean effect. 86 | - **`scale_animations`** is a boolean that turns on/off scale animations of the selected item. Try it. 87 | - **`scale_animations_factor`** is a float value that defines max scale ratio for scaling animation 88 | - **`scale_animations_pivot_center`** is a boolean that moves pivot point of scale animations to center of your element instead of default left aligned position. 89 | - **`selected_index`** is an integer that represents initially selected option. 90 | 91 | ## Advanced usage 92 | Here everything is more complicated. Let's start from creating layout files. 93 | 1. First of all we need to implement our custom cell layout, in separate xml file, eg `advanced_example_country_cell.xml`: 94 | ```xml 95 | 100 | 101 | 111 | 112 | 119 | 120 | 121 | ``` 122 | 2. Now we need to create a layout for our cell in the list view, `advanced_example_country_list_item.xml`- it just wraps our newly created cell with `FrameLayout` for correct element animations and positioning inside the list view. 123 | ```xml 124 | 131 | 132 | 136 | 137 | 138 | ``` 139 | 3. Third step - creation of our custom picker box layout, a new file named `advanced_example_country_picker_box.xml` that contains our custom cell layout, and inserts an additional custom elements that must appear only in picker box, like the direction arrows in our example. 140 | ```xml 141 | 147 | 148 | 152 | 153 | 166 | 167 | 168 | ``` 169 | 4. Finally, we need to write some code. First of all - we need to prepare a dataset, our cell contains two items - a title and image, so we can't use the default `data_array` attribute from the basic example. Our structure can be represented by plain old java object with two appropriate fields. 170 | ```java 171 | public class AdvancedExampleCountryPOJO { 172 | private String title; 173 | private int icon; 174 | 175 | public AdvancedExampleCountryPOJO(String title, int icon) { 176 | this.title = title; 177 | this.icon = icon; 178 | } 179 | 180 | public static List getExampleDataset() { 181 | return Arrays.asList( 182 | new AdvancedExampleCountryPOJO("Russian Federation", R.drawable.ds_countries_ru), 183 | new AdvancedExampleCountryPOJO("Canada", R.drawable.ds_countries_ca), 184 | new AdvancedExampleCountryPOJO("United States of America", R.drawable.ds_countries_us), 185 | new AdvancedExampleCountryPOJO("China", R.drawable.ds_countries_cn), 186 | new AdvancedExampleCountryPOJO("Brazil", R.drawable.ds_countries_br), 187 | new AdvancedExampleCountryPOJO("Australia", R.drawable.ds_countries_au), 188 | new AdvancedExampleCountryPOJO("India", R.drawable.ds_countries_in), 189 | new AdvancedExampleCountryPOJO("Argentina", R.drawable.ds_countries_ar), 190 | new AdvancedExampleCountryPOJO("Kazakhstan", R.drawable.ds_countries_kz), 191 | new AdvancedExampleCountryPOJO("Algeria", R.drawable.ds_countries_dz) 192 | ); 193 | } 194 | 195 | // getters, setters, equal, hashcode, etc. 196 | } 197 | ``` 198 | 5. Now, to more complex things - we need to somehow provide our dataset to `DSListView`, for this purpose in Android we have a `android.widget.ArrayAdapter` class, so we need a custom implementation to map data from our POJO to the actual cell described earlier: 199 | ```java 200 | public class AdvancedExampleCountryAdapter extends ArrayAdapter { 201 | private List items; 202 | private Context context; 203 | 204 | public AdvancedExampleCountryAdapter(@NonNull Context context, int resource, @NonNull List objects) { 205 | super(context, resource, objects); 206 | this.items = objects; 207 | this.context = context; 208 | } 209 | 210 | @Override 211 | public long getItemId(int position) { 212 | return position; 213 | } 214 | 215 | @Override 216 | public boolean hasStableIds() { 217 | return true; 218 | } 219 | 220 | @Override 221 | public int getCount() { 222 | return items.size(); 223 | } 224 | 225 | @NonNull 226 | @Override 227 | public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 228 | AdvancedExampleCountryAdapter.ViewHolder holder; 229 | 230 | if (null == convertView) { 231 | LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 232 | assert vi != null; 233 | convertView = vi.inflate(R.layout.advanced_example_country_list_item, parent, false); 234 | holder = new AdvancedExampleCountryAdapter.ViewHolder(); 235 | holder.text = convertView.findViewById(R.id.custom_cell_text); 236 | holder.icon = convertView.findViewById(R.id.custom_cell_image); 237 | convertView.setTag(holder); 238 | } else { 239 | holder = (AdvancedExampleCountryAdapter.ViewHolder) convertView.getTag(); 240 | } 241 | if (null != holder) { 242 | holder.text.setText(items.get(position).getTitle()); 243 | holder.icon.setImageResource(items.get(position).getIcon()); 244 | } 245 | return convertView; 246 | } 247 | 248 | private class ViewHolder { 249 | TextView text; 250 | ImageView icon; 251 | } 252 | } 253 | 254 | ``` 255 | 6. Almost done, but before we put it all together, there is one more thing. We almost forgot about our custom picker box to map the selected cell from the list view to the actual displayed picker. So, we need to implement simple view that inflates our layout for the picker box described earlier. To guarantee correctness, work must extend the `DSAbstractPickerBox` class and implement some abstract methods: 256 | ```java 257 | public class AdvancedExampleCountryPickerBox extends DSAbstractPickerBox { 258 | private TextView text; 259 | private ImageView icon; 260 | private View cellRoot; 261 | 262 | public AdvancedExampleCountryPickerBox(@NonNull Context context) { 263 | this(context, null); 264 | } 265 | 266 | public AdvancedExampleCountryPickerBox(@NonNull Context context, 267 | @Nullable AttributeSet attrs) { 268 | this(context, attrs, 0); 269 | } 270 | 271 | public AdvancedExampleCountryPickerBox(@NonNull Context context, 272 | @Nullable AttributeSet attrs, int defStyleAttr) { 273 | super(context, attrs, defStyleAttr); 274 | init(context); 275 | } 276 | 277 | private void init(@NonNull Context context) { 278 | LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 279 | assert mInflater != null; 280 | mInflater.inflate(R.layout.advanced_example_country_picker_box, this, true); 281 | } 282 | 283 | @Override 284 | protected void onFinishInflate() { 285 | super.onFinishInflate(); 286 | this.text = findViewById(R.id.custom_cell_text); 287 | this.icon = findViewById(R.id.custom_cell_image); 288 | this.cellRoot = findViewById(R.id.custom_cell_root); 289 | } 290 | 291 | @Override 292 | public void onSelect(AdvancedExampleCountryPOJO selectedItem, int selectedIndex) { 293 | this.text.setText(selectedItem.getTitle()); 294 | this.icon.setImageResource(selectedItem.getIcon()); 295 | } 296 | 297 | @Override 298 | public View getCellRoot() { 299 | return this.cellRoot; 300 | } 301 | } 302 | ``` 303 | 7. Finally - put all parts together in the main activity layout and write some code in `MainActivity`: 304 | ```java 305 | public class AdvancedExampleActivity extends AppCompatActivity { 306 | 307 | @SuppressLint("ClickableViewAccessibility") 308 | @Override 309 | protected void onCreate(Bundle savedInstanceState) { 310 | super.onCreate(savedInstanceState); 311 | setContentView(R.layout.advanced_example_activity); 312 | 313 | // Prepare dataset 314 | List exampleDataSet = AdvancedExampleCountryPOJO.getExampleDataset(); 315 | 316 | // Create adapter with our dataset 317 | ArrayAdapter adapter = new AdvancedExampleCountryAdapter( 318 | this, R.layout.advanced_example_country_list_item, exampleDataSet); 319 | 320 | // Set adapter to our DSListView 321 | DSListView pickerView = findViewById(R.id.ds_county_list); 322 | pickerView.setAdapter(adapter); 323 | 324 | } 325 | } 326 | ``` 327 | That's all. There are still some unmentioned features, like the possibility to change the size and position of the list view and the possibility to change default cell text appearance through `cell-font-size` settings or through applying your custom style. 328 | Full examples with some comments and explanations can be found in this repository. Feel free to report bugs and ask questions. 329 | 330 |
331 | 332 | ## 📄 License 333 | 334 | Direct Select Android is released under the MIT license. 335 | See [LICENSE](./LICENSE) for details. 336 | 337 | This library is a part of a selection of our best UI open-source projects 338 | 339 | If you use the open-source library in your project, please make sure to credit and backlink to www.ramotion.com 340 | 341 | ## 📱 Get the Showroom App for Android to give it a try 342 | Try this UI component and more like this in our Android app. Contact us if interested. 343 | 344 | 345 | 346 | 347 | 348 | 349 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.3.1' 9 | classpath 'com.bmuschko:gradle-nexus-plugin:2.3.1' 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | jcenter() 17 | } 18 | } 19 | 20 | task clean(type: Delete) { 21 | delete rootProject.buildDir 22 | } 23 | -------------------------------------------------------------------------------- /direct-select-example-advanced/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /direct-select-example-advanced/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.ramotion.directselect.examples.advenced" 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 2 10 | versionName "1.0.1" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | buildToolsVersion '28.0.3' 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(include: ['*.jar'], dir: 'libs') 25 | implementation project(':direct-select') 26 | implementation 'androidx.appcompat:appcompat:1.0.2' 27 | } 28 | -------------------------------------------------------------------------------- /direct-select-example-advanced/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/java/com/ramotion/directselect/examples/advanced/AdvancedExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect.examples.advanced; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.Bundle; 5 | import android.view.Window; 6 | import android.view.WindowManager; 7 | import android.widget.ArrayAdapter; 8 | 9 | import com.ramotion.directselect.DSListView; 10 | 11 | import java.util.List; 12 | 13 | import androidx.appcompat.app.ActionBar; 14 | import androidx.appcompat.app.AppCompatActivity; 15 | 16 | public class AdvancedExampleActivity extends AppCompatActivity { 17 | 18 | @SuppressLint("ClickableViewAccessibility") 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | 23 | // Make activity fullscreen 24 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 25 | requestWindowFeature(Window.FEATURE_NO_TITLE); 26 | ActionBar supportActionBar = getSupportActionBar(); 27 | if (null != supportActionBar) 28 | supportActionBar.hide(); 29 | 30 | setContentView(R.layout.advanced_example_activity); 31 | 32 | // Prepare dataset 33 | List exampleDataSet = AdvancedExampleCountryPOJO.getExampleDataset(); 34 | 35 | // Create adapter with our dataset 36 | ArrayAdapter adapter = new AdvancedExampleCountryAdapter( 37 | this, R.layout.advanced_example_country_list_item, exampleDataSet); 38 | 39 | // Set adapter to our DSListView 40 | DSListView pickerView = findViewById(R.id.ds_county_list); 41 | pickerView.setAdapter(adapter); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/java/com/ramotion/directselect/examples/advanced/AdvancedExampleCountryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect.examples.advanced; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | 12 | import java.util.List; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.annotation.Nullable; 16 | 17 | public class AdvancedExampleCountryAdapter extends ArrayAdapter { 18 | private List items; 19 | private Context context; 20 | 21 | public AdvancedExampleCountryAdapter(@NonNull Context context, int resource, @NonNull List objects) { 22 | super(context, resource, objects); 23 | this.items = objects; 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | public long getItemId(int position) { 29 | return position; 30 | } 31 | 32 | @Override 33 | public boolean hasStableIds() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public int getCount() { 39 | return items.size(); 40 | } 41 | 42 | @NonNull 43 | @Override 44 | public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 45 | AdvancedExampleCountryAdapter.ViewHolder holder; 46 | 47 | if (null == convertView) { 48 | LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 49 | assert vi != null; 50 | convertView = vi.inflate(R.layout.advanced_example_country_list_item, parent, false); 51 | holder = new AdvancedExampleCountryAdapter.ViewHolder(); 52 | holder.text = convertView.findViewById(R.id.custom_cell_text); 53 | holder.icon = convertView.findViewById(R.id.custom_cell_image); 54 | convertView.setTag(holder); 55 | } else { 56 | holder = (AdvancedExampleCountryAdapter.ViewHolder) convertView.getTag(); 57 | } 58 | 59 | if (null != holder) { 60 | holder.text.setText(items.get(position).getTitle()); 61 | holder.icon.setImageResource(items.get(position).getIcon()); 62 | } 63 | return convertView; 64 | } 65 | 66 | private class ViewHolder { 67 | TextView text; 68 | ImageView icon; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/java/com/ramotion/directselect/examples/advanced/AdvancedExampleCountryPOJO.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect.examples.advanced; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | public class AdvancedExampleCountryPOJO { 7 | 8 | private String title; 9 | private int icon; 10 | 11 | public AdvancedExampleCountryPOJO(String title, int icon) { 12 | this.title = title; 13 | this.icon = icon; 14 | } 15 | 16 | public String getTitle() { 17 | return title; 18 | } 19 | 20 | public void setTitle(String title) { 21 | this.title = title; 22 | } 23 | 24 | public int getIcon() { 25 | return icon; 26 | } 27 | 28 | public void setIcon(int icon) { 29 | this.icon = icon; 30 | } 31 | 32 | public static List getExampleDataset() { 33 | return Arrays.asList( 34 | new AdvancedExampleCountryPOJO("Russian Federation", R.drawable.ds_countries_ru), 35 | new AdvancedExampleCountryPOJO("Canada", R.drawable.ds_countries_ca), 36 | new AdvancedExampleCountryPOJO("United States of America", R.drawable.ds_countries_us), 37 | new AdvancedExampleCountryPOJO("China", R.drawable.ds_countries_cn), 38 | new AdvancedExampleCountryPOJO("Brazil", R.drawable.ds_countries_br), 39 | new AdvancedExampleCountryPOJO("Australia", R.drawable.ds_countries_au), 40 | new AdvancedExampleCountryPOJO("India", R.drawable.ds_countries_in), 41 | new AdvancedExampleCountryPOJO("Argentina", R.drawable.ds_countries_ar), 42 | new AdvancedExampleCountryPOJO("Kazakhstan", R.drawable.ds_countries_kz), 43 | new AdvancedExampleCountryPOJO("Algeria", R.drawable.ds_countries_dz) 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/java/com/ramotion/directselect/examples/advanced/AdvancedExampleCountryPickerBox.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect.examples.advanced; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.ramotion.directselect.DSAbstractPickerBox; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | 15 | public class AdvancedExampleCountryPickerBox extends DSAbstractPickerBox { 16 | 17 | private TextView text; 18 | private ImageView icon; 19 | private View cellRoot; 20 | 21 | public AdvancedExampleCountryPickerBox(@NonNull Context context) { 22 | this(context, null); 23 | } 24 | 25 | public AdvancedExampleCountryPickerBox(@NonNull Context context, @Nullable AttributeSet attrs) { 26 | this(context, attrs, 0); 27 | } 28 | 29 | public AdvancedExampleCountryPickerBox(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | init(context); 32 | } 33 | 34 | private void init(@NonNull Context context) { 35 | LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 36 | assert mInflater != null; 37 | mInflater.inflate(R.layout.advanced_example_country_picker_box, this, true); 38 | } 39 | 40 | @Override 41 | protected void onFinishInflate() { 42 | super.onFinishInflate(); 43 | this.text = findViewById(R.id.custom_cell_text); 44 | this.icon = findViewById(R.id.custom_cell_image); 45 | this.cellRoot = findViewById(R.id.custom_cell_root); 46 | } 47 | 48 | @Override 49 | public void onSelect(AdvancedExampleCountryPOJO selectedItem, int selectedIndex) { 50 | this.text.setText(selectedItem.getTitle()); 51 | this.icon.setImageResource(selectedItem.getIcon()); 52 | } 53 | 54 | @Override 55 | public View getCellRoot() { 56 | return this.cellRoot; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_bg_list_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_bg_picker_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_ar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_ar.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_au.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_au.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_br.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_ca.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_cn.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_dz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_dz.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_in.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_kz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_kz.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_ru.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_countries_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_countries_us.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ds_picker_box_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/drawable/ds_picker_box_arrows.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/layout/advanced_example_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 35 | 36 | 40 | 41 | 45 | 46 | 51 | 52 | 57 | 58 | 62 | 63 | 68 | 69 | 74 | 75 | 79 | 80 | 85 | 86 | 93 | 94 | 98 | 99 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/layout/advanced_example_country_cell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 19 | 20 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/layout/advanced_example_country_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/layout/advanced_example_country_picker_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 14 | 15 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-advanced/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Soccer 5 | American Football 6 | Basketball 7 | Cricket 8 | Table Tennis 9 | Tennis 10 | Hockey 11 | Volleyball 12 | Baseball 13 | Rugby 14 | Golf 15 | 16 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | #eeeeee 5 | #797979 6 | #6d74ff 7 | 8 | #dedede 9 | #9f9f9f 10 | #ffffff 11 | #ffffff 12 | #232323 13 | 14 | 15 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DS Advanced Example 3 | picker box arrows icon 4 | cell image 5 | Direct Select for Android 6 | New iOS and Android control for you and your company. Please make sure to use it properly, if you have any questions, please create an issue on our GitHub account. 7 | Here a fully customized picker with custom background and cell layout: 8 | Here a picker with default cell but custom background: 9 | by Ramotion inc. 10 | 11 | -------------------------------------------------------------------------------- /direct-select-example-advanced/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 23 | 24 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /direct-select-example-basic/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /direct-select-example-basic/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.ramotion.directselect.examples.basic" 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 2 10 | versionName "1.0.1" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | buildToolsVersion '28.0.3' 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(include: ['*.jar'], dir: 'libs') 25 | implementation project(':direct-select') 26 | implementation 'androidx.appcompat:appcompat:1.0.2' 27 | 28 | } 29 | -------------------------------------------------------------------------------- /direct-select-example-basic/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/java/com/ramotion/directselect/examples/basic/BasicExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect.examples.basic; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | public class BasicExampleActivity extends AppCompatActivity { 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | setContentView(R.layout.ds_basic_example_activity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/drawable/ds_basic_example_custom_picker_box_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/layout/ds_basic_example_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 23 | 24 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct-select-example-basic/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | January 5 | February 6 | March 7 | April 8 | May 9 | June 10 | July 11 | August 12 | September 13 | October 14 | November 15 | December 16 | 17 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #67f45959 8 | #49067397 9 | #ffffff 10 | 11 | 12 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DS Basic Example 3 | 4 | -------------------------------------------------------------------------------- /direct-select-example-basic/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /direct-select/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /direct-select/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'signing' 3 | apply plugin: 'com.bmuschko.nexus' 4 | 5 | group = 'com.ramotion.directselect' 6 | version = '0.1.1' 7 | 8 | android { 9 | compileSdkVersion 28 10 | buildToolsVersion '28.0.3' 11 | 12 | defaultConfig { 13 | minSdkVersion 14 14 | targetSdkVersion 28 15 | versionCode 2 16 | versionName version 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | implementation 'androidx.appcompat:appcompat:1.0.2' 32 | } 33 | 34 | modifyPom { 35 | project { 36 | name 'DirectSelect for Android' 37 | description 'DirectSelect is a selection widget with an ethereal, full-screen modal popup displaying the available choices when the widget is interact with. http://ramotion.com' 38 | url 'https://github.com/Ramotion/direct-select-android' 39 | inceptionYear '2018' 40 | 41 | scm { 42 | url 'https://github.com/Ramotion/direct-select-android' 43 | connection 'scm:git@github.com:Ramotion/direct-select-android.git' 44 | developerConnection 'scm:git@github.com:Ramotion/direct-select-android.git' 45 | } 46 | 47 | licenses { 48 | license { 49 | name 'The MIT License (MIT)' 50 | url 'https://opensource.org/licenses/mit-license.php' 51 | distribution 'repo' 52 | } 53 | } 54 | 55 | developers { 56 | developer { 57 | id 'oleg-vasiliev' 58 | name 'Oleg Vasiliev' 59 | email 'oleg-vasiliev@hotmail.com' 60 | } 61 | 62 | developer { 63 | id 'golovin47' 64 | name 'Ivan Golovin' 65 | email 'golovinivans@gmail.com' 66 | } 67 | } 68 | } 69 | } 70 | 71 | extraArchive { 72 | sources = false 73 | tests = false 74 | javadoc = false 75 | } 76 | 77 | nexus { 78 | sign = true 79 | repositoryUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' 80 | snapshotRepositoryUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' 81 | } -------------------------------------------------------------------------------- /direct-select/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /direct-select/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/AnimationListenerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.view.animation.Animation; 4 | 5 | abstract class AnimationListenerAdapter implements Animation.AnimationListener { 6 | 7 | @Override 8 | public void onAnimationStart(Animation animation) { 9 | 10 | } 11 | 12 | @Override 13 | public void onAnimationEnd(Animation animation) { 14 | 15 | } 16 | 17 | @Override 18 | public void onAnimationRepeat(Animation animation) { 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/CustomListView.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.widget.ListView; 7 | 8 | /** 9 | * Custom List View that reacts only to specific motion events 10 | */ 11 | class CustomListView extends ListView { 12 | 13 | public CustomListView(Context context) { 14 | super(context); 15 | } 16 | 17 | public CustomListView(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | @Override 26 | public boolean onTouchEvent(MotionEvent ev) { 27 | return ev.getSource() == DSListView.MOTION_EVENT_SOURCE && super.onTouchEvent(ev); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/DSAbstractPickerBox.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.widget.FrameLayout; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | 11 | /** 12 | * Represents a Picker Box for Direct Select with specified data type 13 | * 14 | * @param data type for direct select and picker box elements 15 | */ 16 | public abstract class DSAbstractPickerBox extends FrameLayout { 17 | 18 | public DSAbstractPickerBox(@NonNull Context context) { 19 | super(context); 20 | } 21 | 22 | public DSAbstractPickerBox(@NonNull Context context, @Nullable AttributeSet attrs) { 23 | super(context, attrs); 24 | } 25 | 26 | public DSAbstractPickerBox(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | } 29 | 30 | /** 31 | * This method will be invoked when directselect select's a item 32 | * 33 | * @param selectedItem data object of selected item 34 | * @param selectedIndex index of selected item 35 | */ 36 | public abstract void onSelect(T selectedItem, int selectedIndex); 37 | 38 | /** 39 | * This method must return a root view of your custom cell in most cases. 40 | * This view and all his children views will be used for scroll/show animations if they are enabled 41 | */ 42 | public abstract View getCellRoot(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/DSDefaultAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.TextView; 9 | 10 | import java.util.ArrayList; 11 | 12 | import androidx.annotation.NonNull; 13 | 14 | /** 15 | * Default implementation of ArrayAdapter for DSListView 16 | * Used by default for strings with default cell layout through simple and clean xml configuration 17 | */ 18 | public class DSDefaultAdapter extends ArrayAdapter { 19 | 20 | private ArrayList items; 21 | private Context context; 22 | 23 | // Things to provide proper cell configuration comparing to configuration of picker box element 24 | // Any custom implementation doesn't need this three vars 25 | private int cellHeight; 26 | private int cellTextSize; 27 | private DSDefaultPickerBox dsPickerBoxDefault; 28 | 29 | DSDefaultAdapter(Context context, int textViewResourceId, ArrayList stringItems, Integer cellHeight, Integer cellTextSize) { 30 | super(context, textViewResourceId, stringItems); 31 | this.items = stringItems; 32 | this.context = context; 33 | this.cellHeight = cellHeight; 34 | this.cellTextSize = cellTextSize; 35 | } 36 | 37 | void setDsPickerBoxDefault(DSDefaultPickerBox dsPickerBoxDefault) { 38 | this.dsPickerBoxDefault = dsPickerBoxDefault; 39 | } 40 | 41 | void setCellHeight(Integer cellHeight) { 42 | this.cellHeight = cellHeight; 43 | } 44 | 45 | void setCellTextSize(Integer cellTextSize) { 46 | this.cellTextSize = cellTextSize; 47 | } 48 | 49 | @Override 50 | public long getItemId(int position) { 51 | return position; 52 | } 53 | 54 | @Override 55 | public boolean hasStableIds() { 56 | return true; 57 | } 58 | 59 | @Override 60 | public int getCount() { 61 | return items.size(); 62 | } 63 | 64 | @NonNull 65 | @Override 66 | public View getView(int position, View convertView, @NonNull ViewGroup parent) { 67 | DSDefaultAdapter.ViewHolder holder; 68 | 69 | if (null == convertView) { 70 | LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 71 | assert vi != null; 72 | convertView = vi.inflate(R.layout.ds_default_list_item, parent, false); 73 | holder = new DSDefaultAdapter.ViewHolder(); 74 | holder.text = convertView.findViewById(R.id.ds_default_cell_text); 75 | convertView.setTag(holder); 76 | } else { 77 | holder = (ViewHolder) convertView.getTag(); 78 | } 79 | 80 | if (null != holder) { 81 | holder.text.setText(items.get(position)); 82 | 83 | if (cellHeight > 0) 84 | convertView.setMinimumHeight(cellHeight); 85 | 86 | if (cellTextSize > 0) 87 | holder.text.setTextSize(cellTextSize); 88 | 89 | if (null != this.dsPickerBoxDefault) 90 | convertView.setPadding(dsPickerBoxDefault.getPaddingLeft(), dsPickerBoxDefault.getPaddingTop(), 91 | dsPickerBoxDefault.getPaddingRight(), dsPickerBoxDefault.getPaddingBottom()); 92 | } 93 | return convertView; 94 | } 95 | 96 | private class ViewHolder { 97 | TextView text; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/DSDefaultPickerBox.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.annotation.Nullable; 12 | 13 | /** 14 | * Default implementation of Picker Box element for Strings to work "from the box" 15 | * with default cell layout 16 | */ 17 | public class DSDefaultPickerBox extends DSAbstractPickerBox { 18 | 19 | private TextView textView; 20 | private ViewGroup cellRoot; 21 | 22 | public DSDefaultPickerBox(@NonNull Context context) { 23 | this(context, null); 24 | 25 | } 26 | 27 | public DSDefaultPickerBox(@NonNull Context context, @Nullable AttributeSet attrs) { 28 | this(context, attrs, 0); 29 | } 30 | 31 | public DSDefaultPickerBox(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | init(context); 34 | } 35 | 36 | private void init(@NonNull Context context) { 37 | LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 38 | assert mInflater != null; 39 | mInflater.inflate(R.layout.ds_default_picker_box, this, true); 40 | this.setClipChildren(false); 41 | this.setClipToPadding(false); 42 | } 43 | 44 | void setCellTextSize(int cellTextSize) { 45 | if (cellTextSize > 0) 46 | this.textView.setTextSize(cellTextSize); 47 | } 48 | 49 | @Override 50 | protected void onFinishInflate() { 51 | super.onFinishInflate(); 52 | this.textView = findViewById(R.id.ds_default_cell_text); 53 | this.cellRoot = findViewById(R.id.ds_default_cell_root); 54 | this.cellRoot.setMinimumHeight(this.getHeight()); 55 | } 56 | 57 | @Override 58 | public void onSelect(String value, int index) { 59 | this.textView.setText(value); 60 | } 61 | 62 | @Override 63 | public View getCellRoot() { 64 | return this.cellRoot; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /direct-select/src/main/java/com/ramotion/directselect/DSListView.java: -------------------------------------------------------------------------------- 1 | package com.ramotion.directselect; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Color; 7 | import android.os.Build; 8 | import android.os.Handler; 9 | import android.util.AttributeSet; 10 | import android.view.LayoutInflater; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.animation.AccelerateInterpolator; 15 | import android.view.animation.AlphaAnimation; 16 | import android.view.animation.Animation; 17 | import android.view.animation.DecelerateInterpolator; 18 | import android.view.animation.ScaleAnimation; 19 | import android.widget.AbsListView; 20 | import android.widget.ArrayAdapter; 21 | import android.widget.FrameLayout; 22 | import android.widget.ListView; 23 | import android.widget.RelativeLayout; 24 | import android.widget.Space; 25 | 26 | import java.util.ArrayList; 27 | import java.util.Arrays; 28 | 29 | import androidx.annotation.ColorInt; 30 | import androidx.annotation.DrawableRes; 31 | 32 | /** 33 | * Represents a popup view with list of available options to choose from and selector view 34 | * at fixed position from top to indicate a selected option. Contains mail logic, animations, handlers, etc. 35 | */ 36 | @SuppressWarnings({"unused", "UnusedReturnValue", "unchecked"}) 37 | public class DSListView extends RelativeLayout implements AbsListView.OnScrollListener { 38 | static int MOTION_EVENT_SOURCE = 42; 39 | 40 | private ArrayAdapter adapter = null; 41 | private ArrayList dataFromAttributes = null; 42 | 43 | private Context context; 44 | 45 | // Inner parts 46 | private ListView listView = null; 47 | private View selectorView = null; 48 | 49 | // State variables 50 | private boolean selectorAnimationsEnabled = true; 51 | private boolean pickerInitialized; 52 | private boolean readyToHide; 53 | private boolean animationInProgress; 54 | private boolean scrollInProgress; 55 | private boolean listViewIsShown; 56 | 57 | // Settings and selector position 58 | private int firstVisibleItem = 0; 59 | private int selectedItem = 0; 60 | private int cellsBeforeSelector = 0; 61 | private int cellHeight = 100; 62 | private float scaleFactorDelta = 0.3f; 63 | private int selectorTopMargin = 0; 64 | private int subScrollDuration = 100; 65 | private int topMarginCompensation = 0; 66 | private boolean selectorAnimationCenterPivot = false; 67 | 68 | // Attached picker box view to display selected value and trigger show/hide animations of DSListView 69 | private DSAbstractPickerBox pickerBox; 70 | private int pickerBoxResId; 71 | private int cellTextSize; 72 | 73 | // Selector view background settings 74 | private int selectorBgColor = Color.parseColor("#116b2b66"); 75 | private int selectorBgDrawable; 76 | 77 | public DSListView(Context context) { 78 | this(context, null); 79 | } 80 | 81 | public DSListView(Context context, AttributeSet attrs) { 82 | this(context, attrs, 0); 83 | } 84 | 85 | public DSListView(Context context, AttributeSet attrs, int defStyle) { 86 | super(context, attrs, defStyle); 87 | TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.DSListView); 88 | final int count = styledAttrs.getIndexCount(); 89 | for (int i = 0; i < count; ++i) { 90 | int attr = styledAttrs.getIndex(i); 91 | if (attr == R.styleable.DSListView_cell_font_size) { 92 | this.cellTextSize = styledAttrs.getDimensionPixelSize(attr, 0); 93 | } else if (attr == R.styleable.DSListView_data_array) { 94 | String[] arr = getResources().getStringArray(styledAttrs.getResourceId(attr, 0)); 95 | this.dataFromAttributes = new ArrayList<>(Arrays.asList(arr)); 96 | } else if (attr == R.styleable.DSListView_scale_animations) { 97 | this.selectorAnimationsEnabled = styledAttrs.getBoolean(attr, true); 98 | } else if (attr == R.styleable.DSListView_selected_index) { 99 | this.selectedItem = styledAttrs.getInt(attr, 0); 100 | } else if (attr == R.styleable.DSListView_picker_box_view) { 101 | this.pickerBoxResId = styledAttrs.getResourceId(attr, 0); 102 | } else if (attr == R.styleable.DSListView_scale_animations_factor) { 103 | this.scaleFactorDelta = styledAttrs.getFloat(attr, 1.3f) - 1f; 104 | } else if (attr == R.styleable.DSListView_scale_animations_pivot_center) { 105 | this.selectorAnimationCenterPivot = styledAttrs.getBoolean(attr, false); 106 | } else if (attr == R.styleable.DSListView_selector_background) { 107 | try { 108 | this.selectorBgColor = styledAttrs.getColor(attr, Color.parseColor("#116b2b66")); 109 | } catch (Exception e) { 110 | this.selectorBgDrawable = styledAttrs.getResourceId(attr, 0); 111 | } 112 | } 113 | } 114 | styledAttrs.recycle(); 115 | initPicker(context); 116 | } 117 | 118 | private void initPicker(Context context) { 119 | this.context = context; 120 | 121 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 122 | 123 | assert inflater != null; 124 | inflater.inflate(R.layout.ds_list_view, this, true); 125 | 126 | listView = findViewById(R.id.list_view); 127 | selectorView = findViewById(R.id.selector_view); 128 | 129 | if (selectorBgDrawable > 0) 130 | selectorView.setBackgroundResource(selectorBgDrawable); 131 | else 132 | selectorView.setBackgroundColor(selectorBgColor); 133 | 134 | // If string data array provided from xml - use it with default string array adapter 135 | if (null != dataFromAttributes) 136 | setAdapter((ArrayAdapter) new DSDefaultAdapter(context, R.layout.ds_default_list_item, 137 | dataFromAttributes, cellHeight, cellTextSize)); 138 | 139 | } 140 | 141 | @Override 142 | public void onWindowFocusChanged(boolean hasWindowFocus) { 143 | super.onWindowFocusChanged(hasWindowFocus); 144 | 145 | // Init listView here, because we need to do some calculations when listView already has height 146 | if (pickerInitialized || null == adapter) 147 | return; 148 | 149 | int[] selectboxLocation = new int[2]; 150 | 151 | if (null != this.pickerBox) { 152 | this.pickerBox.getLocationInWindow(selectboxLocation); 153 | this.cellHeight = this.pickerBox.getHeight(); 154 | } 155 | 156 | if (null != this.adapter && this.adapter instanceof DSDefaultAdapter) 157 | ((DSDefaultAdapter) this.adapter).setCellHeight(cellHeight); 158 | 159 | // Calculate positions of selector and self position 160 | int[] selfLocation = new int[2]; 161 | this.getLocationInWindow(selfLocation); 162 | selectorTopMargin = selectboxLocation[1] - selfLocation[1]; 163 | if (selectorTopMargin < 0) selectorTopMargin = 0; 164 | 165 | // Move selectorView to required position, by the top margin 166 | if (selectorView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { 167 | ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) selectorView.getLayoutParams(); 168 | p.height = cellHeight; 169 | p.setMargins(0, selectorTopMargin, 0, 0); 170 | selectorView.requestLayout(); 171 | } 172 | 173 | topMarginCompensation = cellHeight - selectorTopMargin % cellHeight; 174 | cellsBeforeSelector = selectorTopMargin / cellHeight; 175 | cellsBeforeSelector += topMarginCompensation == 0 ? 0 : 1; 176 | 177 | // Add negative margin to list view to compensate remained space smaller than cell height 178 | if (listView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { 179 | ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) listView.getLayoutParams(); 180 | p.setMargins(0, -topMarginCompensation, 0, 0); 181 | listView.requestLayout(); 182 | } 183 | 184 | // Add empty space before list elements to make sure that all list items reachable 185 | for (int i = 0; i < cellsBeforeSelector; i++) { 186 | Space topSpace = new Space(context); 187 | topSpace.setMinimumHeight(cellHeight); 188 | listView.addHeaderView(topSpace); 189 | } 190 | 191 | // Add space after list elements to make sure that all list items reachable 192 | Space bottomSpace = new Space(context); 193 | bottomSpace.setMinimumHeight((DSListView.this.getHeight() - selectorTopMargin - cellHeight)); 194 | listView.addFooterView(bottomSpace); 195 | 196 | // Set adapter and scroll listener 197 | listView.setAdapter(adapter); 198 | listView.setOnScrollListener(this); 199 | 200 | pickerInitialized = true; 201 | 202 | // Set initial selection 203 | this.listView.setSelection(selectedItem); 204 | 205 | if (null != pickerBox) 206 | this.pickerBox.onSelect(this.adapter.getItem(selectedItem), selectedItem); 207 | } 208 | 209 | @Override 210 | public void onAttachedToWindow() { 211 | super.onAttachedToWindow(); 212 | if (null == this.pickerBox && this.pickerBoxResId > 0) 213 | setPickerBox((DSAbstractPickerBox) getRootView().findViewById(pickerBoxResId)); 214 | } 215 | 216 | private void hideListView() { 217 | if (!readyToHide || animationInProgress || scrollInProgress || !listViewIsShown || adapter == null) return; 218 | 219 | readyToHide = false; 220 | animationInProgress = true; 221 | listView.setEnabled(false); 222 | 223 | this.setVisibility(View.INVISIBLE); 224 | 225 | this.pickerBox.onSelect(adapter.getItem(selectedItem), selectedItem); 226 | 227 | AlphaAnimation hideAnimation = new AlphaAnimation(1f, 0f); 228 | hideAnimation.setStartOffset(subScrollDuration); 229 | hideAnimation.setDuration(200); 230 | hideAnimation.setInterpolator(new DecelerateInterpolator()); 231 | hideAnimation.setAnimationListener(new AnimationListenerAdapter() { 232 | @Override 233 | public void onAnimationEnd(Animation animation) { 234 | listViewIsShown = false; 235 | animationInProgress = false; 236 | } 237 | }); 238 | DSListView.this.startAnimation(hideAnimation); 239 | 240 | // Scale picker box text animation if animations enabled 241 | if (selectorAnimationsEnabled && null != this.pickerBox) { 242 | ScaleAnimation scaleAnimation = new ScaleAnimation(1f + scaleFactorDelta, 1f, 1f + scaleFactorDelta, 1f, 243 | Animation.RELATIVE_TO_SELF, selectorAnimationCenterPivot ? 0.5f : 0f, Animation.RELATIVE_TO_SELF, 0.5f); 244 | scaleAnimation.setInterpolator(new DecelerateInterpolator()); 245 | scaleAnimation.setStartOffset(100 + subScrollDuration); 246 | scaleAnimation.setDuration(100); 247 | scaleAnimation.setFillAfter(true); 248 | this.pickerBox.getCellRoot().startAnimation(scaleAnimation); 249 | } 250 | } 251 | 252 | private void showListView() { 253 | if (animationInProgress || scrollInProgress || listViewIsShown) return; 254 | listView.setEnabled(true); 255 | animationInProgress = true; 256 | 257 | this.setVisibility(View.VISIBLE); 258 | this.bringToFront(); 259 | this.readyToHide = false; 260 | 261 | // Scale picker box if animations enabled 262 | if (selectorAnimationsEnabled && null != this.pickerBox) { 263 | ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 1f + scaleFactorDelta, 1f, 1f + scaleFactorDelta, 264 | Animation.RELATIVE_TO_SELF, selectorAnimationCenterPivot ? 0.5f : 0f, Animation.RELATIVE_TO_SELF, 0.5f); 265 | scaleAnimation.setInterpolator(new AccelerateInterpolator()); 266 | scaleAnimation.setDuration(100); 267 | scaleAnimation.setFillAfter(true); 268 | this.pickerBox.getCellRoot().startAnimation(scaleAnimation); 269 | } 270 | 271 | // Show picker view animation 272 | AlphaAnimation showAnimation = new AlphaAnimation(0f, 1f); 273 | showAnimation.setDuration(200); 274 | showAnimation.setInterpolator(new AccelerateInterpolator()); 275 | showAnimation.setAnimationListener(new AnimationListenerAdapter() { 276 | @Override 277 | public void onAnimationEnd(Animation animation) { 278 | animationInProgress = false; 279 | listViewIsShown = true; 280 | hideListView(); 281 | } 282 | }); 283 | 284 | this.startAnimation(showAnimation); 285 | } 286 | 287 | ///////////////////////////////////////// CLIENT METHODS /////////////////////////////////////////// 288 | 289 | public void setAdapter(ArrayAdapter adapter) { 290 | this.adapter = adapter; 291 | // If default adapter set - use mechanisms to do default_cell configuration 292 | if (null != this.adapter && this.adapter instanceof DSDefaultAdapter) { 293 | DSDefaultAdapter ad = (DSDefaultAdapter) this.adapter; 294 | ad.setCellHeight(cellHeight); 295 | ad.setCellTextSize(cellTextSize); 296 | if (this.pickerBox instanceof DSDefaultPickerBox) 297 | ad.setDsPickerBoxDefault((DSDefaultPickerBox) this.pickerBox); 298 | } 299 | listView.setAdapter(adapter); 300 | } 301 | 302 | public void setPickerBox(DSAbstractPickerBox pickerBox) { 303 | this.pickerBox = pickerBox; 304 | if (this.pickerBox == null) return; 305 | this.pickerBox.setOnTouchListener(new View.OnTouchListener() { 306 | @SuppressLint("ClickableViewAccessibility") 307 | @Override 308 | public boolean onTouch(View v, MotionEvent event) { 309 | switch (event.getAction()) { 310 | case MotionEvent.ACTION_DOWN: 311 | DSListView.this.showListView(); 312 | break; 313 | case MotionEvent.ACTION_UP: 314 | DSListView.this.readyToHide = true; 315 | hideListView(); 316 | break; 317 | } 318 | event.offsetLocation(0, selectorTopMargin + topMarginCompensation); 319 | event.setSource(MOTION_EVENT_SOURCE); 320 | DSListView.this.listView.onTouchEvent(event); 321 | return true; 322 | } 323 | }); 324 | 325 | if (this.adapter != null && this.adapter instanceof DSDefaultAdapter && this.pickerBox instanceof DSDefaultPickerBox) { 326 | DSDefaultAdapter ad = (DSDefaultAdapter) this.adapter; 327 | DSDefaultPickerBox pbd = (DSDefaultPickerBox) this.pickerBox; 328 | ad.setDsPickerBoxDefault(pbd); 329 | pbd.setCellTextSize(cellTextSize); 330 | } 331 | } 332 | 333 | public void setSelectorBgColor(@ColorInt int chooserBgColor) { 334 | this.selectorBgColor = chooserBgColor; 335 | if (null != selectorView) 336 | selectorView.setBackgroundColor(chooserBgColor); 337 | } 338 | 339 | @SuppressLint("ResourceType") 340 | public void setSelectorBgDrawable(@DrawableRes int chooserBgDrawable) { 341 | this.selectorBgDrawable = chooserBgDrawable; 342 | if (chooserBgDrawable > 0 && null != selectorView) 343 | selectorView.setBackgroundResource(chooserBgDrawable); 344 | } 345 | 346 | public Integer getSelectedIndex() { 347 | return null == this.adapter ? null : this.selectedItem; 348 | } 349 | 350 | public void setSelectedIndex(int index) { 351 | this.selectedItem = index; 352 | 353 | if (pickerInitialized) 354 | this.listView.setSelection(index); 355 | 356 | if (null != pickerBox && null != this.adapter) 357 | this.pickerBox.onSelect(this.adapter.getItem(this.selectedItem), this.selectedItem); 358 | } 359 | 360 | public T getSelectedItem() { 361 | return null == this.adapter ? null : this.adapter.getItem(this.selectedItem); 362 | } 363 | 364 | //////////////////////////////////////// GETTERS&SETTERS /////////////////////////////////////////// 365 | 366 | public boolean isSelectorAnimationsEnabled() { 367 | return this.selectorAnimationsEnabled; 368 | } 369 | 370 | public void setSelectorAnimationsEnabled(boolean selectorAnimationsEnabled) { 371 | this.selectorAnimationsEnabled = selectorAnimationsEnabled; 372 | } 373 | 374 | /////////////////////////////////// ListView Scroll Listener /////////////////////////////////////// 375 | 376 | @Override 377 | public void onScrollStateChanged(AbsListView absListView, final int scrollState) { 378 | this.scrollInProgress = true; 379 | 380 | // If scroll not stopped - clear selector animations(hide/show scale) and return; 381 | if (scrollState != SCROLL_STATE_IDLE) { 382 | // if (null != this.pickerBox) { 383 | // Animation animation = DSListView.this.pickerBox.getAnimation(); 384 | // if (animation != null) 385 | // animation.cancel(); 386 | // 387 | // } 388 | return; 389 | } 390 | 391 | // So, scroll is stopped - we need to detect position and make subscroll to selected element 392 | this.scrollInProgress = false; 393 | 394 | // Get first visible child of list (invisible child are removed for recycling, so first visible child is always 0 index) 395 | View topChild = absListView.getChildAt(0); 396 | if (topChild == null) return; 397 | 398 | // Get position of of first visible child in dataFromAttributes array 399 | this.firstVisibleItem = this.listView.getFirstVisiblePosition(); 400 | 401 | // Switch to next item if height of visible part of top view is smaller than half height of one row 402 | if (-topChild.getTop() > topChild.getHeight() / 2) { 403 | this.firstVisibleItem++; 404 | } 405 | 406 | // Dirty trick with post-delayed handler to avoid known "fixed" issue (https://issuetracker.google.com/issues/36952786) 407 | new Handler().postDelayed(new Runnable() { 408 | @Override 409 | public void run() { 410 | listView.smoothScrollToPositionFromTop(firstVisibleItem, 0, subScrollDuration); 411 | hideListView(); 412 | } 413 | }, 0); 414 | 415 | this.selectedItem = this.firstVisibleItem; 416 | } 417 | 418 | @Override 419 | public void onScroll(AbsListView listView, int firstVisible, int visibleItemCount, int totalItemCount) { 420 | if (!pickerInitialized || !selectorAnimationsEnabled) return; 421 | 422 | int selectorPosY = cellHeight * cellsBeforeSelector; 423 | int applyingRangeY = cellHeight; 424 | 425 | for (int i = 0; i < listView.getChildCount(); i++) { 426 | 427 | // Exclude elements that does not need to edit 428 | if (!(listView.getChildAt(i) instanceof FrameLayout)) 429 | continue; 430 | 431 | ViewGroup itemRoot = (ViewGroup) listView.getChildAt(i); 432 | 433 | float deviation = 2f; 434 | if (itemRoot.getTop() > selectorPosY + applyingRangeY * deviation || itemRoot.getTop() < selectorPosY - applyingRangeY * deviation) 435 | continue; 436 | 437 | View cellContent = itemRoot.getChildAt(0); 438 | 439 | // Edit elements regarding to their position from selector 440 | float dy = Math.abs(itemRoot.getTop() - selectorPosY); 441 | if (!selectorAnimationCenterPivot) { 442 | cellContent.setPivotX(0); 443 | cellContent.setPivotY(cellContent.getHeight() / 2); 444 | } 445 | 446 | // Scale and "3d effect" for big scale factors on API>=LOLLIPOP 447 | if (dy <= applyingRangeY) { 448 | float k1 = 1 - (dy / applyingRangeY); 449 | float scale = 1 + scaleFactorDelta * k1; 450 | cellContent.setScaleX(scale); 451 | cellContent.setScaleY(scale); 452 | 453 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 454 | itemRoot.setZ((dy <= applyingRangeY / 2) ? 2 : 1); 455 | 456 | } else { 457 | cellContent.setScaleX(1f); 458 | cellContent.setScaleY(1f); 459 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 460 | itemRoot.setZ(0); 461 | } 462 | 463 | } 464 | } 465 | 466 | } 467 | -------------------------------------------------------------------------------- /direct-select/src/main/res/layout/ds_default_cell.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /direct-select/src/main/res/layout/ds_default_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /direct-select/src/main/res/layout/ds_default_picker_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /direct-select/src/main/res/layout/ds_list_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /direct-select/src/main/res/values/attr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /direct_select_preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/direct_select_preview.gif -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | android.useAndroidX=true 11 | android.enableJetifier=true 12 | 13 | # Specifies the JVM arguments used for the daemon process. 14 | # The setting is particularly useful for tweaking memory settings. 15 | org.gradle.jvmargs=-Xmx1536m 16 | 17 | # When configured, Gradle will run in incubating parallel mode. 18 | # This option should only be used with decoupled projects. More details, visit 19 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 20 | # org.gradle.parallel=true 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Feb 08 15:11:33 MSK 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ramotion/direct-select-android/6a4cf41153c522fc332293b7ad508f58ec028f07/header.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':direct-select-example-advanced', ':direct-select', ':direct-select-example-basic' 2 | --------------------------------------------------------------------------------