B4A Library [B4X] [XUI] AS DatePickerTimeline

Date Picker Library that provides a calendar as a horizontal timeline.
This library is inspired by a Flutter library, but the B4X one is better ;)

I spend a lot of time in creating views, like this and to create a high quality view cost a lot of time. If you want to support me and further views, then you can do it here by Paypal or with a coffee. :)

The view has 2 modes:
  • Paging - you scroll page by page
  • List - scrolling without snapping
cpdfGfuVmnKjmJGQi3J5GmP0JJGtEUnDEmmdPYAdcxYL6ambPW.jpeg


1653132764985.png

Make all sundays red:
Private Sub AS_DatePickerTimeline1_CustomDrawDay (Date As Long, BackgroundPanel As B4XView)
    Dim xlbl_Date As B4XView = BackgroundPanel.GetView(0)
 
    'Month Name - January
    Dim xlbl_Month As B4XView = BackgroundPanel.GetView(1) 'Ignore
    'WeekDay Name - Monday
    Dim xlbl_WeekDay As B4XView = BackgroundPanel.GetView(2) 'Ignore
 
    If DateTime.GetDayOfWeek(Date) = 1 Then '1=Sunday
        xlbl_Date.TextColor = xui.Color_ARGB(255,221, 95, 96)
    End If
End Sub
1653141708792.png

Badge example

Make sure you are using ASViewPager V1.31+
ASDatePickerTimeline
Author: Alexander Stolte
Version: 1.00

  • ASDatePickerTimeline_BodyProperties
    • Fields:
      • DateTextColor As Int
      • DateTextFont As B4XFont
      • IsInitialized As Boolean
        Tests whether the object has been initialized.
      • MonthTextColor As Int
      • MonthTextFont As B4XFont
      • WeekDayTextColor As Int
      • WeekDayTextFont As B4XFont
    • Functions:
      • Initialize
        Initializes the fields to their default value.
  • ASDatePickerTimeline_MonthNameShort
    • Fields:
      • April As String
      • August As String
      • December As String
      • February As String
      • IsInitialized As Boolean
        Tests whether the object has been initialized.
      • January As String
      • July As String
      • June As String
      • March As String
      • May As String
      • November As String
      • October As String
      • September As String
    • Functions:
      • Initialize
        Initializes the fields to their default value.
  • ASDatePickerTimeline_SelectedDayProperties
    • Fields:
      • Color As Int
      • CornerRadius As Float
      • IsInitialized As Boolean
        Tests whether the object has been initialized.
    • Functions:
      • Initialize
        Initializes the fields to their default value.
  • ASDatePickerTimeline_WeekNameShort
    • Fields:
      • Friday As String
      • IsInitialized As Boolean
        Tests whether the object has been initialized.
      • Monday As String
      • Saturday As String
      • Sunday As String
      • Thursday As String
      • Tuesday As String
      • Wednesday As String
    • Functions:
      • Initialize
        Initializes the fields to their default value.
  • AS_DatePickerTimeline
    • Events:
      • SelectedDateChanged (Date As Long)
    • Fields:
      • mBase As B4XView
      • Tag As Object
    • Functions:
      • Class_Globals As String
      • CreateASDatePickerTimeline_BodyProperties (DateTextColor As Int, DateTextFont As B4XFont, MonthTextColor As Int, MonthTextFont As B4XFont, WeekDayTextColor As Int, WeekDayTextFont As B4XFont) As ASDatePickerTimeline_BodyProperties
      • CreateASDatePickerTimeline_MonthNameShort (January As String, February As String, March As String, April As String, May As String, June As String, July As String, August As String, September As String, October As String, November As String, December As String) As ASDatePickerTimeline_MonthNameShort
      • CreateASDatePickerTimeline_SelectedDayProperties (Color As Int, CornerRadius As Float) As ASDatePickerTimeline_SelectedDayProperties
      • CreateASDatePickerTimeline_WeekNameShort (Monday As String, Tuesday As String, Wednesday As String, Thursday As String, Friday As String, Saturday As String, Sunday As String) As ASDatePickerTimeline_WeekNameShort
      • DesignerCreateView (Base As Object, Lbl As Label, Props As Map) As String
        Base type must be Object
      • getBodyProperties As ASDatePickerTimeline_BodyProperties
        Call Refresh if you change something
      • getMonthNameShort As ASDatePickerTimeline_MonthNameShort
        Call Refresh if you change something
      • getSelectedDayProperties As ASDatePickerTimeline_SelectedDayProperties
      • getStartDate As Long
      • getWeekNameShort As ASDatePickerTimeline_WeekNameShort
        Call Refresh if you change something
      • Initialize (Callback As Object, EventName As String) As String
      • IsInitialized As Boolean
        Tests whether the object has been initialized.
      • NextWeek As String
      • PreviousWeek As String
      • Refresh
        Rebuilds the visible items
      • setFirstDayOfWeek (number As Int) As String
        1-7
        Friday = 1
        Thursday = 2
        Wednesday = 3
        Tuesday = 4
        Monday = 5
        Sunday = 6
        Saturday = 7
      • setStartDate (StartDate As Long) As String
    • Properties:
      • BodyProperties As ASDatePickerTimeline_BodyProperties [read only]
        Call Refresh if you change something
      • FirstDayOfWeek
        1-7
        Friday = 1
        Thursday = 2
        Wednesday = 3
        Tuesday = 4
        Monday = 5
        Sunday = 6
        Saturday = 7
      • MonthNameShort As ASDatePickerTimeline_MonthNameShort [read only]
        Call Refresh if you change something
      • SelectedDayProperties As ASDatePickerTimeline_SelectedDayProperties [read only]
      • StartDate As Long
      • WeekNameShort As ASDatePickerTimeline_WeekNameShort [read only]
        Call Refresh if you change something
Changelog
  • 1.00
    • Release
  • 1.01
    • Add Event CustomDrawDay
  • 1.02
    • Add new Type ASDatePickerTimeline_CustomDrawDay
    • Breaking Change on Event CustomDrawDay - The second parameter has changed to Views As ASDatePickerTimeline_CustomDrawDay
    • Add Designer Property CurrentDateColor
    • Add Designer Property SelectedDateColor
    • BugFixes
  • 1.03
    • Add get and set SelectedDate
    • Add Scroll2Date
    • BugFixes
  • 1.04
    • Add set MonthNameShort
    • Add set WeekNameShort
  • 1.05 (read more)
    • Add CustomDrawDay - You can make changes on one day without having to reload the entire week, with refresh
  • 1.06
    • Function "Refresh" is now even better
      • No visual flickering
      • Changes are instant
  • 1.07
    • Add get and set MaxDate - Will restrict date navigations features of forward, and also cannot swipe the control using touch gesture beyond the max date range
    • Add get and set MinDate - Will restrict date navigations features of backward, and also cannot swipe the control using touch gesture beyond the max date range
    • Add Rebuild - Clears the DatePicker and builds the DatePicker new
  • 1.08
    • BugFix
  • 1.09
    • BugFixes
  • 1.10
    • BugFix
  • 1.11
    • BugFixes
  • 1.12
    • Add get and set Enabled - If False then click events and scroll (only on paging mode) is disabled
  • 1.13
    • Scroll2Date BugFix
  • 1.14
  • 1.15
    • ListMode List
      • Completely rewritten logic
      • Each day now has its own slot, instead of always adding 1 week to the list
      • MinDate and MaxDate can now be used in a more targeted manner
  • 1.16 (read more)
    • Add Designer Property CreateMode - If you set it to Manual then you need to call CreateDatePicker
  • 1.17
    • B4A BugFix
  • 1.18
    • Add Event PageChanged
  • 1.19
    • BugFix - The CustomDrawDayEvent is now also triggered when a different day is selected
      • Old Day and New Day
Have Fun :)
 

Attachments

  • Example AS DatePickerTimeline.zip
    11.5 KB · Views: 556
  • AS_DatePickerTimeline.b4xlib
    7.1 KB · Views: 38
Last edited:

Sandman

Expert
Licensed User
Longtime User
Nice view, Alexander.

Two possible improvements come to mind, both events meant for the user to respond to your lib with info:
  • GetDateBackgroundColor(Date as Long, Weekday as Int) as Color
  • GetBadgeNumber(Date as Long) as Int

So, basically, when you display a date, you could call these events, and if they are available and return something you use that for that day. This would keep all that logic (and data) out of your library, while still make it possible for the user to color Sundays red (or whatever makes sense in their situation). And also, if there's already three things happening for a day, the badge number could show that 3. (A zero or null would remove the badge.)
 

Alexander Stolte

Expert
Licensed User
Longtime User
Update
  • 1.01
    • Add Event CustomDrawDay
Two possible improvements
I have a better solution for this ;)
1653132909062.png

Make all sundays red:
Private Sub AS_DatePickerTimeline1_CustomDrawDay (Date As Long, BackgroundPanel As B4XView)
    Dim xlbl_Date As B4XView = BackgroundPanel.GetView(0)
  
    'Month Name - January
    Dim xlbl_Month As B4XView = BackgroundPanel.GetView(1) 'Ignore
    'WeekDay Name - Monday
    Dim xlbl_WeekDay As B4XView = BackgroundPanel.GetView(2) 'Ignore
  
    If DateTime.GetDayOfWeek(Date) = 1 Then '1=Sunday
        xlbl_Date.TextColor = xui.Color_ARGB(255,221, 95, 96)
    End If
End Sub
 

Sandman

Expert
Licensed User
Longtime User
So you basically moved even more responsibility into the code in the event? Yep, that should work fine also.

I forget how badges work, would it be possible to slap on one in that event too?
 

Sandman

Expert
Licensed User
Longtime User
No idea what you mean by badges.
Sorry, I thought it was a known thing. I mean these:

A badge on the day-number could show the number of planned things already on that day (for instance, it could obviously stand for whatever made sense in the app).
 

Alexander Stolte

Expert
Licensed User
Longtime User
A badge on the day-number could show the number of planned things already on that day (for instance, it could obviously stand for whatever made sense in the app).
The new event is very powerfull, because you can add all the things with ease.
1653141495515.png

B4X:
Private Sub CustomDrawDay (Date As Long, Views As ASDatePickerTimeline_CustomDrawDay)

    
    If DateTime.GetDayOfWeek(Date) = 1 Then '1=Sunday
        Views.xlbl_Date.TextColor = xui.Color_ARGB(255,221, 95, 96)
    End If
    
    '***********Badge Code**************************************
    Dim BadgePanelWidth As Float = Views.BackgroundPanel.Width/2
    Dim BadgePanelHeight As Float = 20dip
    
    Dim xpnl_BadgeBackground As B4XView = xui.CreatePanel("")
    xpnl_BadgeBackground.Color = xui.Color_Transparent
    Views.BackgroundPanel.AddView(xpnl_BadgeBackground,BadgePanelWidth - BadgePanelWidth/2,Views.BackgroundPanel.Height/2 - BadgePanelHeight/2,BadgePanelWidth,BadgePanelHeight)
    
    Dim Badger1 As Badger
    Badger1.Initialize
    Badger1.SetBadge(xpnl_BadgeBackground,Rnd(0,20))
    
End Sub
 

Attachments

  • Example Badges AS DatePickerTimeline.zip
    13.2 KB · Views: 274
Last edited:

Alexander Stolte

Expert
Licensed User
Longtime User
Update
  • 1.02
    • Add new Type ASDatePickerTimeline_CustomDrawDay
    • Breaking Change on Event CustomDrawDay - The second parameter has changed to Views As ASDatePickerTimeline_CustomDrawDay
    • Add Designer Property CurrentDateColor
    • Add Designer Property SelectedDateColor
    • BugFixes
Examples were updated
 

pliroforikos

Active Member
Licensed User
Hello,
I'm trying to set Greek language to months and days names in the example with

B4X:
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ")
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ")

But nothing happens. Where do i have to set them?
 

pliroforikos

Active Member
Licensed User
When i call refresh
B4X:
Private Sub AS_DatePickerTimeline1_CustomDrawDay (Date As Long, Views As ASDatePickerTimeline_CustomDrawDay)
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ")
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ")
    AS_DatePickerTimeline1.Refresh
    CustomDrawDay(Date,Views)
End Sub

it crushes...

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
** Activity (main) Resume **
as_datepickertimeline_xclv_main_visiblerangechanged (java line: 1287)
java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
at anywheresoftware.b4a.objects.collections.List.Get(List.java:117)
at b4a.example3.customlistview._getrawlistitem(customlistview.java:447)
at b4a.example3.customlistview._getpanel(customlistview.java:440)
at com.stoltex.datepickertimeline.as_datepickertimeline._xclv_main_visiblerangechanged(as_datepickertimeline.java:1287)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:213)
at anywheresoftware.b4a.keywords.Common$11.run(Common.java:1181)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6138)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
 

Alexander Stolte

Expert
Licensed User
Longtime User
Private Sub AS_DatePickerTimeline1_CustomDrawDay (Date As Long, Views As ASDatePickerTimeline_CustomDrawDay) AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ") AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ") AS_DatePickerTimeline1.Refresh CustomDrawDay(Date,Views) End Sub
thats a big misstake...
dont call refresh in the CustomDrawDayEvent... thats an endless loop then...

If you call refresh, then the visible area will be recreated, which means that the CustomDrawDay event will be triggered again and again for the same item.
 

pliroforikos

Active Member
Licensed User
thats a big misstake...
dont call refresh in the CustomDrawDayEvent... thats an endless loop then...

If you call refresh, then the visible area will be recreated, which means that the CustomDrawDay event will be triggered again and again for the same item.
But when i do this:

B4X:
'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("frm_main")
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ")
    AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ")
    AS_DatePickerTimeline1.Refresh
    B4XPages.SetTitle(Me,"AS DatePickerTimeline")
End Sub

I get

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
** Activity (main) Resume **
java.lang.RuntimeException: java.lang.IndexOutOfBoundsException: Index: 291, Size: 0
at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1719)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6138)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
Caused by: java.lang.IndexOutOfBoundsException: Index: 291, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
at anywheresoftware.b4a.objects.collections.List.Get(List.java:117)
at b4a.example3.customlistview._getrawlistitem(customlistview.java:447)
at com.stoltex.datepickertimeline.as_datepickertimeline$ResumableSub_AddWeeks.resume(as_datepickertimeline.java:440)
at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1717)
... 7 more
 

Alexander Stolte

Expert
Licensed User
Longtime User
Large lists are always difficult, in the background when creating the view for each week an item is added to the list, I use LazyLoading, but it still takes time until the items are added. Therefore it is safer to include a sleep.
B4X:
AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ")
AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ")
Sleep(0)
AS_DatePickerTimeline1.Refresh
 

Alexander Stolte

Expert
Licensed User
Longtime User
Update
  • 1.04
    • Add set MonthNameShort
    • Add set WeekNameShort
but no Greeks too.
B4X:
    AS_DatePickerTimeline1.MonthNameShort = AS_DatePickerTimeline1.CreateASDatePickerTimeline_MonthNameShort("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ.", "Σεπ", "Οκτ", "Νοε", "Δεκ")
    AS_DatePickerTimeline1.WeekNameShort =    AS_DatePickerTimeline1.CreateASDatePickerTimeline_WeekNameShort("Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ")
    Sleep(0)
    AS_DatePickerTimeline1.Refresh
 

Alexander Stolte

Expert
Licensed User
Longtime User
Update
  • 1.05
    • Add CustomDrawDay - You can make changes on one day without having to reload the entire week, with refresh
CustomDrawDay
Colors today red
B4X:
AS_DatePickerTimeline1.CustomDrawDay(DateTime.Now).xlbl_Date.TextColor = xui.Color_Red

But what if you use a day that is not yet filled because it is not in the LazyLoading range?
Check beforehand if your view is also initialized where you want to make changes.
B4X:
    Dim CustomDrawDay1 As ASDatePickerTimeline_CustomDrawDay = AS_DatePickerTimeline2.CustomDrawDay(DateTime.Now + DateTime.TicksPerDay*500)
    If CustomDrawDay1.xlbl_Date.IsInitialized = True Then
        CustomDrawDay1.xlbl_Date.TextColor = xui.Color_Red
    End If
 
Top