Fully customizable, built from scratch NumberPicker for android. Created as an alternative to non-customizable native android NumberPicker

Overview

GoodNumberPicker

GoodPicker is an Android library that provides a picker with customizable UI. It was developed as alternative to the default NumberPicker widget, which is not customizable enough and has some issues. The library does not have many options itself, but it is easy to expand so you can implement any UI you can imagine. Feel free to request new features or report bugs. You can find more information here

Examples

Standard number picker

Standard number picker

Number picker with custom overlay

Custom overlay example

Drawable picker

Drawable picker

Getting Started

Gradle

Add repository in project level build.gradle:

allprojects {
    repositories {
        maven {
            url "https://stonks.jfrog.io/artifactory/stonks-gradle-release"
        }
    }
} 

or if your gradle is set up to define repositories in settings.gradle:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven {
            url "https://stonks.jfrog.io/artifactory/stonks-gradle-release"
        }
    }
}

Add dependency to your build.gradle file:

implementation 'tech.stonks:goodpicker:0.9.3'

Layout

Add view to your layout:

<tech.stonks.goodpicker.GoodPicker android:id="@+id/number_picker"
    android:textColor="@color/picker_text_color" android:layout_margin="16dp"
    app:overlayColor="#00ff00" android:layout_marginHorizontal="16dp" android:font="@font/raleway"
    android:layout_gravity="center" android:layout_marginVertical="8dp" android:textFontWeight="900"
    android:textSize="30sp" app:layout_constraintTop_toBottomOf="@id/text_view"
    app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" android:layout_width="50dp"
    android:layout_height="250dp" />

Code

Listen to position selection

numberPicker.onSelectedPositionChanged = { position ->
    textView.text = "Position: $position"
}

Customization possibilities

XML

Attribute Description
app:overlayColor Color of the overlay lines
android:textColor Color of the text, You might use selector with state_selected to specify text color for selected value
android:textSize Size of the text
android:textFontWeight Weight of the text, will take effect only on API 28 or higher
android:font Font of the text
visibleItems Number of visible items in the picker
------------------------- ----------------------------------------------------------------------------------------------------------

Code

You can also customize your number picker in code

Field Description
style Style of the picker, see GoodNumberPicker.Style. Basically it contains all the fields that are available in xml
onSelectedPositionChanged Listener that will be called when selected position changes. By default, it will be called when user stops scrolling.
publishUpdatesOnlyOnAnimationEnd If set to true, onSelectedPositionChanged will be called only when animation ends. Otherwise, it will be called on every scroll event.
selectedPosition You can set it to change selected position programmatically.
items List of items that will be displayed in the picker.
itemFormatter Formatter that will be used to transform items
pickerOverlay Overlay that will be drawn above picked values. By default it will display two lines
visibleItems Number of visible items in the picker
tint Tint of the picker. It will be applied to all drawables in the picker. You can use selector with state_selected to specify tint for selected value.
size Size of the drawable item.

Formatting items

You can format each item by applying to it modified style. Here I will show few examples how you can format items.

There are a few ready to use formatters:

  • SelectedTextItemFormatter applies text color from ColorStateList to text items. state_selected will be applied to selected item.
  • SelectedDrawableItemFormatter applies tint from ColorStateList to drawable items. state_selected will be applied to selected item

Highlighting selected item

This example shows how to customize selected item.

numberPicker.itemFormatter = { index, item ->
    item.apply {
        val color = if (index == numberPicker.selectedPosition) {
            Color.RED
        } else {
            Color.BLACK
        }

        styleChanged(
            style.modifyCustomStyle<TextStyle> {
                this.copy(
                    textColor = color
                )
            }
        )
    }
}

Different colors based on an index

This example shows how to assign different textColor for various items based on their position. In the same way you can change any field of style to customize item.

numberPicker.onSelectedPositionChanged = { index, item ->
    
    item.apply {
        styleChanged(
            numberPicker.style.modifyCustomStyle<TextStyle> {
                this.copy(
                    textColor = when (index % 3) {
                        0 -> Color.RED
                        1 -> Color.GREEN
                        else -> Color.BLUE
                    }
                )
            }
        )
    }
}

Custom Items

You can implement your completely custom item by extending PickerItem interface. It gives you possibility to draw anything on canvas in a draw method. Here example of implementation of DrawableNumberPickerItem:

class DrawablePickerItem(val drawable: Drawable) : PickerItem {
    private var _style: GoodPickerStyle = GoodPickerStyle.default
    override val style: GoodPickerStyle
        get() = _style
    private val _drawableStyle: DrawableStyle
        get() {
            return _style.getCustomStyle() ?: throw IllegalStateException("No drawable style found")
        }

    override fun draw(canvas: Canvas, y: Float, width: Int, height: Int) {
        val style = _drawableStyle
        canvas.save()
        canvas.translate(
            (width - style.size) / 2f, //here we center drawable
            y + ((height - style.size) / 2f),
        )
        drawable.setTint(style.tint) //before drawing we apply style
        drawable.setBounds(0, 0, style.size, style.size)
        drawable.draw(canvas)
        canvas.restore()
    }

    override fun styleChanged(style: GoodPickerStyle) {
        _style = style //after assignment you might want to invalidate your field to update paint or other things
    }

    companion object {
        fun fromResource(context: Context, resId: Int): DrawablePickerItem {
            return DrawablePickerItem(
                ContextCompat.getDrawable(context, resId)!!
            )
        }
    }
}

Custom Overlay

You can implement your completely custom overlay by extending PickerOverlay interface. It gives you possibility to draw anything on canvas in a draw method. Here example of implementation of DrawablePickerOverlay:

class DrawablePickerOverlay(
    private val _topDrawable: Drawable,
    private val _bottomDrawable: Drawable
) : PickerOverlay {
    private var _style: GoodPickerStyle = GoodPickerStyle.default
    override fun styleChanged(style: GoodPickerStyle) {
        _style = style
    }

    override fun draw(canvas: Canvas, centerItemRect: Rect) {
        _topDrawable.setBounds(
            0,
            0,
            canvas.width,
            centerItemRect.top
        )
        _topDrawable.draw(canvas)
        _bottomDrawable.setBounds(
            0,
            centerItemRect.bottom,
            canvas.width,
            canvas.height
        )
        _bottomDrawable.draw(canvas)
    }

    companion object {
        fun symmetric(topDrawable: Drawable): DrawablePickerOverlay {
            return DrawablePickerOverlay(topDrawable, RotateDrawable().apply {
                drawable = topDrawable.constantState?.newDrawable()!!.mutate()
                this.fromDegrees = 180f
            })
        }
    }
}
You might also like...
A study into creating a fully automatic FRC robot

AutoFRC This is a study into creating a fully automatic FRC robot. This process relies on several key algorithms: pose estiation: using the WpiLib Dif

FirestoreCleanArchitectureApp is an app built with Kotlin and Firestore that displays data in real-time using the MVVM Architecture Pattern. For the UI it uses Jetpack Compose,  Android's modern toolkit for building native UI.
FirestoreCleanArchitectureApp is an app built with Kotlin and Firestore that displays data in real-time using the MVVM Architecture Pattern. For the UI it uses Jetpack Compose, Android's modern toolkit for building native UI.

FirestoreCleanArchitectureApp FirestoreCleanArchitectureApp is an app built with Kotlin and Cloud Firestore that displays data in real-time using Andr

Mock up social media android application created to interact with a backend Java server using GraphQL.

The Community Board Project Authorship: author: dnglokpor date: may 2022 Project Summary: The Community Board Project consists of a Java Spring Boot b

Created a Dice Rolling App in Kotlin & JavaFX
Created a Dice Rolling App in Kotlin & JavaFX

Dice Rolling App in Kotlin Created a Dice Rolling App in Kotlin & JavaFX This is my attempt at making a Dice Roller in Kotlin using JavaFX. Hope you e

Project created in order to handle account management
Project created in order to handle account management

Account Service App Aplicação responsável em receber dados de uma conta, validá-los e retornar mensagem de sucesso ou erro. Tecnologias utilizadas - L

This library is created to make files uploading and downloading on Aws easier

S3Manager - aws files uploading library This library is created to make files uploading and downloading on Aws easier Features Easy to use Single/mult

Distance Sensor Localization Library created by FTC 16439, AlphaGo

AGDistanceLocalization A simple and easy-to-use library, written in Kotlin, to aid in the process of localizing your robot using Distance Sensors! Thi

An Android app built with Kotlin, consuming StarWars API to display characters of the popular StarWars Movie. It is built with the MVVM pattern and the latest Jetpack components.
An Android app built with Kotlin, consuming StarWars API to display characters of the popular StarWars Movie. It is built with the MVVM pattern and the latest Jetpack components.

StarWars An Android app built with Kotlin, consuming StarWars API to display characters of the popular StarWars Movie. It is built with the MVVM patte

Native-Blur: a C++/Kotlin library for blur bitmaps and activity, mobile-ready, android compatible
Native-Blur: a C++/Kotlin library for blur bitmaps and activity, mobile-ready, android compatible

Native-Blur The Native-Blur is a C++/Kotlin libraray for blur bitmaps and activity, mobile-ready, android compatible, powered by Java Native Interface

Owner
null
A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied

Satisfaketion A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied ?? ... With your fake data How to Install ?? Satisfaket

Ryan Brink 7 Oct 3, 2022
To-Do-List - Create a To Do List-style App from scratch and drive the entire development process using Kotlin

To-Do-List! Crie um App no estilo "To Do List" do zero e conduza todo o processo

River Diniz 0 Feb 14, 2022
Automatically filled the declared non-null field is missing or null with default value.

[TOC] Moshi-kotlin-nullsafe 中文版 1. moshi-kotlin moshi-kotlin support kotlin type safe check. When parsing json, fields declared as non-null types may

null 4 Oct 26, 2022
Utility library dedicated for functional & non-functional codebases to simplify modelling of success and failure responses for the JVM languages 🔀

Expressible Utility library, part of the panda-lang SDK, dedicated for functional codebases that require enhanced response handling. Express yourself

Panda 28 Nov 14, 2022
Bukkit library written in Kotlin to make with compatibility and ease non-playable-character (NPC)

mc-npk Easy to use, fast and efficient library to make non-playable-characters (

Luiz Otávio 3 Aug 4, 2022
A simple, lightweight, non-bloated redis client for kotlin and other JVM languages

rekt is a lightweight, non-bloated redis client, primarily written for the kotlin programming language, while also supporting other JVM-based languages, such as Java, Scala, and obviously way more.

Patrick 8 Nov 2, 2022
Alternative to DreamStorageService, but instead of storing files on a database, it is stored on the file system itself.

EtherealGambi Alternative to DreamStorageService, but instead of storing files on a database, it is stored on the file system itself. I made this beca

null 1 Jun 2, 2022
Open source Crypto Currency Tracker Android App made fully in Kotlin

CoinBit CoinBit is a beautiful CryptoCurrency app, completely open sourced and 100% in kotlin. It supports following features Track prices of over 300

Pranay Airan 50 Dec 5, 2022
High performance and fully asynchronous pulsar client with Kotlin and Vert.x

pulsarkt High performance pulsar client with Kotlin and Vert.x Features Basic Producer/Consumer API Partitioned topics Batching Chunking Compression T

null 1 Nov 5, 2021
Team management service is a production ready and fully tested service that can be used as a template for a microservices development.

team-mgmt-service Description Team management service is a production ready and fully tested service that can be used as a template for a microservice

Albert Llousas Ortiz 18 Oct 10, 2022