A customizable, easy-to-use, and functional circular time range picker library for Android

Overview

TimeRangePicker




A customizable, easy-to-use, and functional circular time range picker library for Android. Use this library to mimic Apple's iOS or Samsung's bedtime picker.

           By Joery Droppers

Screenshots

Playground app

    

Download the playground app from Google Play, with this app you can try out all features and even generate XML with your selected configuration.

Getting started

This library is available on Maven Central, add the following dependency to your build.gradle:

implementation 'nl.joery.timerangepicker:timerangepicker:1.0.0'

Define TimeRangePicker in your XML layout with custom attributes. See the Configuration section for more information.

">
<nl.joery.timerangepicker.TimeRangePicker
    android:id="@+id/picker"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    app:trp_thumbIconEnd="@drawable/ic_alarm"
    app:trp_thumbIconStart="@drawable/ic_moon"
    app:trp_endTime="6:30"
    app:trp_startTime="22:00" />

Get notified when the time or duration changes:

picker.setOnTimeChangeListener(object : TimeRangePicker.OnTimeChangeListener {
    override fun onStartTimeChange(startTime: TimeRangePicker.Time) {
        Log.d("TimeRangePicker", "Start time: " + startTime)
    }

    override fun onEndTimeChange(endTime: TimeRangePicker.Time) {
        Log.d("TimeRangePicker", "End time: " + endTime.hour)
    }

    override fun onDurationChange(duration: TimeRangePicker.TimeDuration) {
        Log.d("TimeRangePicker", "Duration: " + duration.hour)
    }
})

Managing picker programmatically

Managing time

Examples of how to set and retrieve start time programmatically, identical properties are available for the end time.

// Set new time with 'Time' object to 12:00
picker.startTime = TimeRangePicker.Time(12, 0)
// Set new time by minutes
picker.startTimeMinutes = 320

Time When retrieving the start or end time, the library will provide a TimeRangePicker.Time object.

  • Use time.hour, time.minute or time.totalMinutes to retrieve literal time.
  • Use time.calendar to retrieve a java.util.Calendar object.
  • Use time.localTime to retrieve a java.time.LocalTime object. (Available since API 26)

Managing duration

When retrieving the duration between the start and end time, the library will provide a TimeRangePicker.Duration object.

  • Use duration.hour, duration.minute or duration.durationMinutes to retrieve literal duration.
  • Use duration.classicDuration to retrieve a javax.xml.datatype.Duration object. (Available since API 8)
  • Use duration.duration to retrieve a java.time.Duration object. (Available since API 26)

Listening for starting and stopping of dragging

This listener is called whenever a user starts or stops dragging. It will also provide which thumb the user was dragging: start, end, or both thumbs. You can return false in the ònDragStart method to prevent the user from dragging a thumb.

picker.setOnDragChangeListener(object : TimeRangePicker.OnDragChangeListener {
    override fun onDragStart(thumb: TimeRangePicker.Thumb): Boolean {
        // Do something on start dragging
        return true // Return false to disallow the user from dragging a handle.
    }

    override fun onDragStop(thumb: TimeRangePicker.Thumb) {
        // Do something on stop dragging
    }
})

Configuration

The attributes listed below can be used to configure the look and feel of the picker. Note that all of these values can also be set programmatically using the properties.

Time

Attribute Description Default
trp_startTime Set the start time by providing a time with format h:mm. 0:00
trp_startTimeMinutes Set the start time by providing minutes between 0 and 1440 (24 hours). 0
trp_endTime Set the end time by providing a time with format h:mm. 8:00
trp_endTimeMinutes Set the end time by providing minutes between 0 and 1440 (24 hours). 480
trp_minDuration Set the minimum selectable duration by providing a duration with format h:mm.
trp_maxDuration Set the maximum selectable duration by providing a duration with format h:mm.
trp_maxDurationMinutes Set the maximum selectable duration by providing minutes between 0 and 1440 (24 hours). 480
trp_minDurationMinutes Set the minimum selectable duration by providing minutes between 0 and 1440 (24 hours). 0
trp_stepTimeMinutes Determines at what interval the time should be rounded. Setting it to a less accurate number (e.g. 10 minutes) makes it easier for a user to select his desired time. 10

Slider

Attribute Description Default
trp_sliderWidth The width of the slider wheel. 8dp
trp_sliderColor The background color of the slider wheel. #E1E1E1
trp_sliderRangeColor The color of the active part of the slider wheel. ?android:colorPrimary
trp_sliderRangeGradientStart Set the starting gradient color of the active part of the slider wheel.

Please note that both trp_sliderRangeGradientStart and trp_sliderRangeGradientEnd need to be configured.

Tip: Set the thumbColor to transparent to mimic the Apple iOS slider.
trp_sliderRangeGradientStart Optional for gradient: set the middle gradient color of the active part of the slider wheel.
trp_sliderRangeGradientEnd Set the ending gradient color of the active part of the slider wheel.

Please note that both trp_sliderRangeGradientStart and trp_sliderRangeGradientEnd need to be configured.

Thumb

Attribute Description Default
trp_thumbIconStart Set the start thumb icon.
trp_thumbIconEnd Set the end thumb icon.
trp_thumbSize The size of both the starting and ending thumb. 28dp
trp_thumbSizeActiveGrow The amount of growth of the size when a thumb is being dragged. 1.2
trp_thumbColor The background color of the thumbs. ?android:colorPrimary
trp_thumbIconColor The color (tint) of the icons inside the thumbs. white
trp_thumbIconSize The size of the thumb icons. 24dp

Clock

Attribute Description Default
trp_clockVisible Whether the clock face in the middle should be visible. true
trp_clockFace There a two different clock faces (appearance of the inner clock) you can use, both mimicking the Clock apps:
APPLE

SAMSUNG
APPLE
trp_clockLabelSize The text size of the hour labels in the clock (1, 2, 3, etc.). This value is recommended to be set as scale-independent pixels (sp). 16sp
trp_clockLabelColor Set the text color of the hour labels in the clock. ?android:textColorPrimary
trp_clockIndicatorColor Set the color of the small time indicator lines in the clock. ?android:textColorPrimary
trp_clockRenderer Set the clock renderer through passing the full class name (with packages).
Note that, you should add @Keep annotation to your custom renderer class.
There are some requirements which should be met.
The renderer class should have a public constructor with no parameters.
Then renderer will be created through calling that constructor.
Or the class should have non-null public static final INSTANCE field.
The value of the field should extend ClockRenderer
If the class contains both public constructor and INSTANCE field, the way through calling constructor is preferred
nl.joery.timerangepicker.DefaultClockRenderer

Credits

  • Samsung's and Apple's Clock app have been used for inspiration, as they both implement this picker differently.

License

MIT License

Copyright (c) 2021 Joery Droppers (https://github.com/Droppers)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this Software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Comments
  • Add support for custom clock renderers

    Add support for custom clock renderers

    This PR adds a support for custom clock renderers. A clock renderer become stateless (it was connected with the view before). An user can easily change default clock renderer to preferred one. But the render performance may degrade a lit bit because of virtualization.

    opened by pelmenstar1 3
  • Use precomputed tables to render labels in the clock

    Use precomputed tables to render labels in the clock

    By doing so, we could improve rendering speed a little bit.

    Benchmarks

    • ZTE Blade V9 (API 27): old -> 203,021 ns new -> 196,979 ns
    • Huawei ATU-L32 (API 27): new -> 267 188 ns old -> 269 167 ns

    Benchmark

    This bechmark checks rendering speed on bitmap. This is not 'pure' benchmark' but if we make such one, obviously getting values from array is faster than calling trigonometric functions.

    opened by pelmenstar1 2
  • Exception is thrown with empty message when trp_hourFormat attribute has invalid value.

    Exception is thrown with empty message when trp_hourFormat attribute has invalid value.

    If invalid value is passed to enum property, we will get a build error: AAPT: error: '420' is incompatible with attribute trp_hourFormat (attr) enum [FORMAT_SYSTEM=0, FORMAT_12=1, FORMAT_24=2]

    Code:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <nl.joery.timerangepicker.TimeRangePicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:trp_hourFormat="420" />
    
    </LinearLayout>
    

    But, nevertheless, if we pass a reference to integer with invalid value, we won't get any build error and code compiles successfully: ints.xml

    <resources>
        <integer name="some_invalid_value">3</integer>
    </resources>
    

    activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <nl.joery.timerangepicker.TimeRangePicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:trp_hourFormat="@integer/some_invalid_value" />
    
    </LinearLayout>
    

    Full code

    In runtime, we will get exception with no message:

         Caused by: java.lang.IllegalArgumentException
            at nl.joery.timerangepicker.TimeRangePicker$HourFormat$Companion.fromId(TimeRangePicker.kt:1160)
            at nl.joery.timerangepicker.TimeRangePicker.initAttributes(TimeRangePicker.kt:147)
            at nl.joery.timerangepicker.TimeRangePicker.<init>(TimeRangePicker.kt:114)
            at nl.joery.timerangepicker.TimeRangePicker.<init>(TimeRangePicker.kt:39)
            at nl.joery.timerangepicker.TimeRangePicker.<init>(TimeRangePicker.kt)
    

    Library tries to handle such cases but unsuccessfully: https://github.com/Droppers/TimeRangePicker/blob/a5c73dbbcb87dcc6b5d1c1f1f5b57e5c330bccd9/timerangepicker/src/main/java/nl/joery/timerangepicker/TimeRangePicker.kt#L135-L140 https://github.com/Droppers/TimeRangePicker/blob/a5c73dbbcb87dcc6b5d1c1f1f5b57e5c330bccd9/timerangepicker/src/main/java/nl/joery/timerangepicker/TimeRangePicker.kt#L1081-L1086

    Method fromId never returns null, but throws exception with empty message on invalid value, but initAttributes expects that fromId returns null and assignes default value (HourFormat.FORMAT_12) if returned enum value is null.

    So, what's expected behavior? To leave default value, or to throw exception. If the last one, it's better to throw exception with some message like 'Invalid attribute value(trp_hourFormat=value)'

    opened by pelmenstar1 2
  • Clock bitmap cache

    Clock bitmap cache

    When a user drags thumbs, obviously, the entire view is re-drawn. When a user interacts with the picker, clock settings are not changed. So we can cache clock in a bitmap. With bitmap cache, much fewer computations happen. But re-sizing becomes much more expensive. If caching bitmap is not preferred, it can be disabled.

    opened by pelmenstar1 1
  • Use more clear names for methods changing unit of value.

    Use more clear names for methods changing unit of value.

    For example expression 2.px tells nothing about from what to what unit we convert. It's better to use dpToPx name. This name tells us that we convert from dp to pixels. Everything is clear. Int.dp -> pxToDp(Float): Float Int.sp -> spToPx(Float): Float

    And argument and return type are changed to Float, because more often we use Float, not Int

    opened by pelmenstar1 1
  • Don't compute sin, cos twice for the same angle

    Don't compute sin, cos twice for the same angle

    There are few cases in code where exprensive functions are called twice for the same angle. Newer runtimes are able to optimize such cases and speed of my version and current one will be the same. But older runtimes cannot do that.

    Benchmarks:

    In drawTicks (Benchmark):

    • Fly FS504 (API 21): current - 1 655 ns new - 677 ns
    • ZTE Blade V9 (API 27) current - 426 ns new - 198 ns

    In differenceBetweenAngles (Benchmark):

    • Fly FS504 (API 21): current - 2 982 ns new - 1 830 ns
    • ZTE Blade V9 (API 27): current - 436 ns new - 425 ns

    As you can see, newer runtime optimized differenceBetweenAngles and speed is almost the same

    opened by pelmenstar1 1
  • Expose parseTimeString method and move it to companion object of TimeRangePicker.Time

    Expose parseTimeString method and move it to companion object of TimeRangePicker.Time

    This PR changes the implementation of parseTimeString (parsing time is not something complex like parsing e-mail and it can be replaced to simpler implementation). For testing and architectural reasons, it can be exposed and moved to companion object of TimeRangePicker.Time. To ensure that new method works in corrent way, tests was added.

    opened by pelmenstar1 1
  • Optimize ClockRenderer, reduce memory allocations

    Optimize ClockRenderer, reduce memory allocations

    I have noticed that ClockRenderer allocates memory during drawing the clock, which is not good. This PR fixes it. Besides, I have optimized it a little bit.

    opened by pelmenstar1 1
  • Fix for setting endTime

    Fix for setting endTime

    While using the library, I have encountered an issue with setting end time from Kotlin code. When updating endTime, the start angle is updated instead of the end angle. This PR fixes the issue.

    opened by adrijanrogan 1
  • init StartTime and EndTime by calendar.

    init StartTime and EndTime by calendar.

    Great library. How can I pass a calendar to set StartTime and EndTime for Picker? **picker.setStartTime(calendar);**

    I tried to use setStartTimeMinutes but seem it is not correct.

    picker.setStartTimeMinutes((int) TimeUnit.MILLISECONDS.toMinutes(Calendar.getInstance().getTimeInMillis()));

    opened by nguyencongbinh 1
  • How to setting StartTime, EndTime?

    How to setting StartTime, EndTime?

    i'll try set StartTime And EndTime.

    binding.timerangepicker.startTime = TimeRangePicker.Time(6, 0)
    binding.timerangepicker.endTime =TimeRangePicker.Time(8, 0)
    

    but only StartTime set yet

    i want all set at the same time on code

    someone can you help me?

    opened by hubeen 0
  • Don't use nullable types on primitive to avoid tons of (un)boxing

    Don't use nullable types on primitive to avoid tons of (un)boxing

    Type Int? in Kotlin JVM maps to reference type Integer. It causes memory allocations. In our case, nullability isn't necessary and can be avoided.

    To save compatibility with the last version of the library, some variables types are explicitly marked.

    Maybe we should break compatibility and then, boxed types won't be used at all.

    opened by pelmenstar1 2
Releases(1.0.0)
Owner
Joery Droppers
I am a 22-year-old software developer and live in Borculo, The Netherlands. In my spare time, I like to contribute to open-source projects and stay up to date w
Joery Droppers
A date time range picker for android written in Kotlin

DateTimeRangePicker A date time range picker for android Usage Firstly, grab latest release of the library via JitPack. And note that, it utilizes Jod

SkedGo 501 Dec 31, 2022
A material Date Range Picker based on wdullaers MaterialDateTimePicker

Material Date and Time Picker with Range Selection Credits to the original amazing material date picker library by wdullaer - https://github.com/wdull

Supratim 1.3k Dec 14, 2022
A material Date Range Picker based on wdullaers MaterialDateTimePicker

Material Date and Time Picker with Range Selection Credits to the original amazing material date picker library by wdullaer - https://github.com/wdull

Supratim 1.3k Dec 14, 2022
Time-DatePicker - A Simple Time Date Picker With Kotlin

Time-DatePicker Time.DatePicker.mp4

Faysal Hossain 0 Jan 19, 2022
Facebook-Styled-Image-Picker - Facebook Styled Image Picker

Facebook-Styled-Image-Picker Facebook Styled Gallery Files picker. One or multip

Hashim Tahir 11 Sep 27, 2022
Appleader707 1 Aug 9, 2022
Android Compose wheel picker library based on LazyColumn in vertical and LazyRow in horizontal.

About Android Compose wheel picker library based on LazyColumn in vertical and LazyRow in horizontal. Gradle Sample Default Item size Unfocused count

null 6 Dec 22, 2022
Nepali Date Picker library in Jetpack compose for android with Date conversion from BS to AD and vice-versa

Nepali Date picker Converter - Re in Compose This is a re-work of Nepali Date Picker Converter in jetpack compose and kotlin. English Locale Nepali Lo

Kiran Gyawali 4 Dec 23, 2022
[NO LONGER MAINTAINED] Android library for better Picker DialogFragments

/!\ This Project is no longer maintained /!\ DialogFragments modeled after the AOSP Clock and Calendar apps to improve UX for picking time, date, numb

Code-Troopers 2.7k Dec 29, 2022
[NO LONGER MAINTAINED] Android library for better Picker DialogFragments

/!\ This Project is no longer maintained /!\ DialogFragments modeled after the AOSP Clock and Calendar apps to improve UX for picking time, date, numb

Code-Troopers 2.7k Dec 29, 2022
Alwan 🎨 is an Android Jetpack Compose color picker library.

Alwan Alwan is an Android Jetpack Compose color picker library. Preview Recording.mp4 Download Gradle: dependencies { implementation 'com.raedapps:a

Raed Mughaus 6 Sep 16, 2022
Simplge ImageGallery Picker

SimpleImagePicker add camera and files permissions to manifest file <uses-permission android:name="android.permission.CAMERA" /> <uses-permiss

null 0 Nov 27, 2021
JetCountrypicker - Country code bottomsheet picker in Jetpack Compose

JetCountryPicker Country code bottomsheet picker in Jetpack Compose How to add i

Canopas Software 30 Nov 17, 2022
A simple compose weight picker drawn with canvas.

CanvasWeightPicker A simple compose weight picker drawn with canvas. Features Drag scale to select weight Haptic feedback on weight selected Video of

Timothy Serem 5 Dec 2, 2022
Easy-to-use animated clock icon for Android

Timecon Easy-to-use animated clock icon written in Kotlin Including in your project Add to your root build.gradle: allprojects { repositories {

Alexey Derbyshev 262 Dec 9, 2022
Fully customizable Calendar/DatePicker for Android/Kotlin

AMCalendar - Android Date (Range) Picker AMCalendar is a fully customisable widget for picking dates and ranges based on the native Calendar. It's an

null 6 Oct 18, 2022
Amazing Dynamic Time UI :clock1030: :hourglass: and More

FlatTimeCollection Amazing Dynamic Time UI ?? ⌛ for Android To help you design your Layout. it is Not just a UI, But it contains a CountDownTimer with

Anas Altair 72 Apr 28, 2022
Pick a date or time on Android in style

Material DateTime Picker - Select a time/date in style Material DateTime Picker tries to offer you the date and time pickers as shown in the Material

null 4.7k Jan 4, 2023
A material-styled android view that provisions picking of a date, time & recurrence option, all from a single user-interface.

SublimePicker A customizable view that provisions picking of a date, time & recurrence option, all from a single user-interface. You can also view 'Su

Vikram 2.3k Jan 4, 2023