B4A Library WheelPicker

A wrap for this Github project. Posting the following:
1. B4A sample project
2. B4A library files - copy them to your additional library folder
3. The Java code - change it whichever way you want

Edit: Version 1.11 in post #31 of this thread

1.gif


Sample code:
B4X:
#Region  Project Attributes
    #ApplicationLabel: WheelPicker
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

#AdditionalRes: ..\wheelpicker_resource

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Private wp1 As WheelPicker
    Private wp2 As WheelPicker
  
    Dim mydaylist As List
    Dim mymonthlist As List   
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("main")
  
    wp1.Curved = True
    wp1.Cyclic = True
    wp1.CurtainColor = Colors.ARGB(50, 255, 255, 255)   
    wp1.Curtain = True
    wp1.ItemTextColor = Colors.White
    wp1.Atmospheric = True
    wp1.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp1.ItemTextSize = 40   
    wp1.SelectedItemPosition = 3             'it will start at Thursday  
    wp1.SelectedItemTextColor = Colors.Magenta
    wp1.VisibleItemCount = 4
    wp1.SameWidth = True                     'not sure what this is supposed to do
  
  
    mydaylist.Initialize
    mydaylist.AddAll(Array As String("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
    wp1.Data = mydaylist
  
  
    wp2.Curved = True
    wp2.Cyclic = True
    wp2.CurtainColor = Colors.ARGB(100, 255, 0, 0)   
    wp2.Curtain = True
    wp2.ItemTextColor = Colors.Yellow
    wp2.Atmospheric = True
    wp2.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp2.ItemTextSize = 40   
    wp2.SelectedItemPosition = 7             'it will start at August 
    wp2.SelectedItemTextColor = Colors.Cyan
    wp2.VisibleItemCount = 6
    wp2.SameWidth = True                     'not sure what this is supposed to do
  
  
    mymonthlist.Initialize
    mymonthlist.AddAll(Array As String("January", "February", "March", "April", "May", "June", "July", _
                                     "August", "September", "October", "November", "December"))
    wp2.Data = mymonthlist  
  
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub wp1_item_selected(position As Int)
  
    Log("wp1 position = " & position & "  value = " & mydaylist.Get(position))
  
End Sub


Sub wp2_item_selected(position As Int)
  
    Log("wp2 position = " & position & "  value = " & mymonthlist.Get(position))
  
End Sub

Library as it is at present:

WheelPicker
Author:
Github: AigeStudio, Wrapped by: Johan Schoeman
Version: 1
  • WheelPicker
    Events:
    • item_selected (position As Int)
    Fields:
    • ba As BA
    Methods:
    • BringToFront
    • DesignerCreateView (base As PanelWrapper, lw As LabelWrapper, props As Map)
    • Initialize (EventName As String)
    • Invalidate
    • Invalidate2 (arg0 As Rect)
    • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    • IsInitialized As Boolean
    • RemoveView
    • RequestFocus As Boolean
    • SendToBack
    • SetBackgroundImage (arg0 As Bitmap)
    • SetColorAnimated (arg0 As Int, arg1 As Int, arg2 As Int)
    • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    • SetLayoutAnimated (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int, arg4 As Int)
    • SetVisibleAnimated (arg0 As Int, arg1 As Boolean)
    • onItemSelected (picker As WheelPicker, data As Object, position As Int)
    Properties:
    • Atmospheric As Boolean [write only]
    • Background As Drawable
    • Color As Int [write only]
    • Curtain As Boolean [write only]
    • CurtainColor As Int [write only]
    • Curved As Boolean [write only]
    • Cyclic As Boolean [write only]
    • Data As List [write only]
    • Enabled As Boolean
    • Height As Int
    • Indicator As Boolean [write only]
    • ItemAlign As Int [write only]
    • ItemTextColor As Int [write only]
    • ItemTextSize As Int [write only]
    • Left As Int
    • Parent As Object [read only]
    • SameWidth As Boolean [write only]
    • SelectedItemPosition As Int [write only]
    • SelectedItemTextColor As Int [write only]
    • Tag As Object
    • Top As Int
    • Visible As Boolean
    • VisibleItemCount As Int [write only]
    • Width As Int
 

Attachments

  • TheJavaCode.zip
    15.7 KB · Views: 332
  • b4aWheelPicker.zip
    407.3 KB · Views: 496
  • WheelPickerLibFiles.zip
    17 KB · Views: 436
Last edited:

Mashiane

Expert
Licensed User
Longtime User
A wrap for this Github project. Posting the following:
1. B4A sample project
2. B4A library files - copy them to your additional library folder
3. The Java code - change it whichever way you want

View attachment 46160

Sample code:
B4X:
#Region  Project Attributes
    #ApplicationLabel: WheelPicker
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

#AdditionalRes: ..\wheelpicker_resource

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Private wp1 As WheelPicker
    Private wp2 As WheelPicker
  
    Dim mydaylist As List
    Dim mymonthlist As List   
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("main")
  
    wp1.Curved = True
    wp1.Cyclic = True
    wp1.CurtainColor = Colors.ARGB(50, 255, 255, 255)   
    wp1.Curtain = True
    wp1.ItemTextColor = Colors.White
    wp1.Atmospheric = True
    wp1.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp1.ItemTextSize = 40   
    wp1.SelectedItemPosition = 3             'it will start at Thursday  
    wp1.SelectedItemTextColor = Colors.Magenta
    wp1.VisibleItemCount = 4
    wp1.SameWidth = True                     'not sure what this is supposed to do
  
  
    mydaylist.Initialize
    mydaylist.AddAll(Array As String("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
    wp1.Data = mydaylist
  
  
    wp2.Curved = True
    wp2.Cyclic = True
    wp2.CurtainColor = Colors.ARGB(100, 255, 0, 0)   
    wp2.Curtain = True
    wp2.ItemTextColor = Colors.Yellow
    wp2.Atmospheric = True
    wp2.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp2.ItemTextSize = 40   
    wp2.SelectedItemPosition = 7             'it will start at August 
    wp2.SelectedItemTextColor = Colors.Cyan
    wp2.VisibleItemCount = 6
    wp2.SameWidth = True                     'not sure what this is supposed to do
  
  
    mymonthlist.Initialize
    mymonthlist.AddAll(Array As String("January", "February", "March", "April", "May", "June", "July", _
                                     "August", "September", "October", "November", "December"))
    wp2.Data = mymonthlist  
  
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub wp1_item_selected(position As Int)
  
    Log("wp1 position = " & position & "  value = " & mydaylist.Get(position))
  
End Sub


Sub wp2_item_selected(position As Int)
  
    Log("wp2 position = " & position & "  value = " & mymonthlist.Get(position))
  
End Sub

Library as it is at present:

WheelPicker
Author:
Github: AigeStudio, Wrapped by: Johan Schoeman
Version: 1
  • WheelPicker
    Events:
    • item_selected (position As Int)
    Fields:
    • ba As BA
    Methods:
    • BringToFront
    • DesignerCreateView (base As PanelWrapper, lw As LabelWrapper, props As Map)
    • Initialize (EventName As String)
    • Invalidate
    • Invalidate2 (arg0 As Rect)
    • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    • IsInitialized As Boolean
    • RemoveView
    • RequestFocus As Boolean
    • SendToBack
    • SetBackgroundImage (arg0 As Bitmap)
    • SetColorAnimated (arg0 As Int, arg1 As Int, arg2 As Int)
    • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
    • SetLayoutAnimated (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int, arg4 As Int)
    • SetVisibleAnimated (arg0 As Int, arg1 As Boolean)
    • onItemSelected (picker As WheelPicker, data As Object, position As Int)
    Properties:
    • Atmospheric As Boolean [write only]
    • Background As Drawable
    • Color As Int [write only]
    • Curtain As Boolean [write only]
    • CurtainColor As Int [write only]
    • Curved As Boolean [write only]
    • Cyclic As Boolean [write only]
    • Data As List [write only]
    • Enabled As Boolean
    • Height As Int
    • Indicator As Boolean [write only]
    • ItemAlign As Int [write only]
    • ItemTextColor As Int [write only]
    • ItemTextSize As Int [write only]
    • Left As Int
    • Parent As Object [read only]
    • SameWidth As Boolean [write only]
    • SelectedItemPosition As Int [write only]
    • SelectedItemTextColor As Int [write only]
    • Tag As Object
    • Top As Int
    • Visible As Boolean
    • VisibleItemCount As Int [write only]
    • Width As Int
You are the BOSS! Impressive... Why dont you write a book about writing b4a libraries? You have some valuable knowledge on this..
 

Johan Schoeman

Expert
Licensed User
Longtime User
Version 1.01 of library files attached. It adds the horizontal indicator bars (the green and cyan in the pic below)

Add this to your code to set the indicator bars:
B4X:
wp1.Indicator = True
wp1.IndicatorColor = Colors.Green
wp1.IndicatorSize = 5

1.png
 

Attachments

  • WheelPickerLibFilesV1_01.zip
    17.1 KB · Views: 202

Johan Schoeman

Expert
Licensed User
Longtime User
Well done! Would it be possible to extend this library such that it accepts sideways (horizontal) gestures?
For example by swiping left or right the user could switch to minutes, hours, days, months and years wheelpicker lists...!
It would be even nicer if parts of adjacent lists would be visible left and right of the wheel (e.g. make a roller-ball type of picker).
Without applying some major open heart surgery it can't be done with the Github project as it is at present. If you can find a suitable project with the features that you want we can try and wrap it.
 

Johan Schoeman

Expert
Licensed User
Longtime User
Would it be possible to add an event that reports the items that are passed during the gestures? The JAR file reveals that a "setOnWheelChangeListener" method is available; ditto: the GitHub project has a "getCurrentItemPosition" method.
I want to make a function for blind users that speaks each passed item and not only the selected item after the finger is lifted.
Rick, I will spend some time on it during the coming weekend and see if I can make some changes to it.
 

RomansUP

Member
Licensed User
Longtime User
Hi, Johan
I think that you made very nice library. Thank you very much
But it seems to me that I have catched a bug.
Look:
I made a List which contains 30 numbers of days (from 0 to 29). Then I put this list like a Data to WheelPicker.
When I try to set SelectedItemPosition more then 24 (for example 27) every time I get an error like this
----------------------
java.lang.ArrayIndexOutOfBoundsException: Current item position must in [0, 24), but current is 27
-----------------
I try it in different projects with different count of data - the same error.

Could you please remove this restriction?
 

Johan Schoeman

Expert
Licensed User
Longtime User
Hi, Johan
I think that you made very nice library. Thank you very much
But it seems to me that I have catched a bug.
Look:
I made a List which contains 30 numbers of days (from 0 to 29). Then I put this list like a Data to WheelPicker.
When I try to set SelectedItemPosition more then 24 (for example 27) every time I get an error like this
----------------------
java.lang.ArrayIndexOutOfBoundsException: Current item position must in [0, 24), but current is 27
-----------------
I try it in different projects with different count of data - the same error.

Could you please remove this restriction?
Try with the attached library files (V1.08) - it should allow you to add as many as you want
 

Attachments

  • WheelPicker_LibFiles_V1_08.zip
    18.7 KB · Views: 211

Johan Schoeman

Expert
Licensed User
Longtime User
Hi Johan, Nice work! Could you please add a separate WP_click event?
I want the user to deliberately tap on the wheelpicker to proceed with the selected item.
At present the WP_item_selected(position As Int) event forces to automatically select the item as soon as the wheel stops rolling. I don't want that to happen.
Thank you in advance!
Hi Syd, will see if I can do something about it this weekend. The original code does not support this option but will see if I can add something to it (such as for eg a long click)
 

Johan Schoeman

Expert
Licensed User
Longtime User
Thank you very much. It would be nice if you could solve it by means of a short click (not a long click).
I am a bit surprised that the original makers did not think about this. Especially when using the Wheelpicker as a Menu item selector, normally a user would scroll up and down until the desired item is shown. He/she would do this in one or more steps, especially after first giving the wheel a hard push and then fine-tuning it manually until the wanted item is show in the center of the wheel. As it is now, the item at which the wheel stops after rolling is immediately selected, but many times this will is not be the item that the user wants...

A solution could be to place a Panel over the Wheelpicker and then pass move events to the wheel and await a tap by the user on the panel, but this is not a very elegant solution.
Syd, try the attached. This event will be raised when you click on the "active" item:
B4X:
Sub wp1_index_clicked(position As Int)
   
    Log("clicked and position = " & position)
   
   
End Sub
 

Attachments

  • WheelPickerLibFiles_V_1_09.zip
    19.6 KB · Views: 203
  • b4aWheelPicker.zip
    416.8 KB · Views: 218

Johan Schoeman

Expert
Licensed User
Longtime User
@Johan Schoeman Is it possible to change the height of the items (or in other words: the spacing between the items)?
Here is the Java code for those who would like to change / add / amend / modify it
 

Attachments

  • TheJavaCode.zip
    13.9 KB · Views: 168

wimpie3

Well-Known Member
Licensed User
Longtime User
@Johan Schoeman It seems the height can be changed in the original library using the setItemSpace parameter. But this parameter has not been made public in your b4a library? (I just discovered you can also influence the space by giving more height to the object, so that helps!).

Edit: hmmmm, there also seems to be a bug in this library. I'm able to scroll the picker between two numbers in some cases and keep the picker in an illegal style with no selected row (index_changed fires with the new row, but item_selected is not fired in those cases). This happens when the total height is limited, I cannot reproduce this with a large height. Might be a bug in the original library...
 
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
Hello Johan,
Just to report that your new WP1_index_clicked(position As Int) event works fine.
However, when I call a Sub under this event I need to use CalSubDelayed(Me,"...") otherwise my App sometimes crashes after touching the Wheelpicker. It took some time to figure out that the Wheelpicker was causing the crashes.

The problem now seems to be solved here, but it may be worth examining why it happens (assuming that you can reproduce it; My app is very large and complicated).

PS
I have also occasionally noticed similar phenomena as Wimpie3 has reported above.
The Wheelpicker is now an integral part of my app...

There are a number of issues opened in the original project
https://github.com/AigeStudio/WheelPicker/issues
I will see if I can incorporate some of the suggested fixes.

The setImageSpace did not seem to do anything so I did not expose the method. One of the issues raised in the github project seems to offer a solution. I will try it out and if it works I will expose the method.
 

Johan Schoeman

Expert
Licensed User
Longtime User
@Johan Schoeman It seems the height can be changed in the original library using the setItemSpace parameter. But this parameter has not been made public in your b4a library? (I just discovered you can also influence the space by giving more height to the object, so that helps!).

Edit: hmmmm, there also seems to be a bug in this library. I'm able to scroll the picker between two numbers in some cases and keep the picker in an illegal style with no selected row (index_changed fires with the new row, but item_selected is not fired in those cases). This happens when the total height is limited, I cannot reproduce this with a large height. Might be a bug in the original library...

This is how the events are triggered (in the Github project):
1. wp1_item_selected: It gets fired once MotionEvent.ACTION_UP has executed and movement of the wheel has stopped (i.e it settled on a value)
2. wp1_index_changed: It gets fired during the execution of MotionEvent.ACTION_MOVE i.e while the wheel is in motion with or without your finger being in contact with the wheel.
3. wp1_index_clicked: This event gets fired from within method onTouchEevent by measuring the time difference between MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP as well a checking that the travelling distance of the wheel does not exceed a value of 15dip

I have modified and exposed method setItemSpace (fix in Github issues) - but it does not change the distance between the entries in the wheel. It changes the distance between the two horizontal bars. I will post an update lib that includes a fix for the drifting that occurs when the click event fires.
 

Johan Schoeman

Expert
Licensed User
Longtime User
Hello Johan,
Just to report that your new WP1_index_clicked(position As Int) event works fine.
However, when I call a Sub under this event I need to use CalSubDelayed(Me,"...") otherwise my App sometimes crashes after touching the Wheelpicker. It took some time to figure out that the Wheelpicker was causing the crashes.

The problem now seems to be solved here, but it may be worth examining why it happens (assuming that you can reproduce it; My app is very large and complicated).

PS
I have also occasionally noticed similar phenomena as Wimpie3 has reported above.
The Wheelpicker is now an integral part of my app...
Hi Syd, see post # 27. I have added a fix for the drift that occurs in the wheel when the click event that I have added for you takes place. I first want to look in to the call sub issue before I post the updated library files
 

Johan Schoeman

Expert
Licensed User
Longtime User
Hello Johan,
Just to report that your new WP1_index_clicked(position As Int) event works fine.
However, when I call a Sub under this event I need to use CalSubDelayed(Me,"...") otherwise my App sometimes crashes after touching the Wheelpicker. It took some time to figure out that the Wheelpicker was causing the crashes.

The problem now seems to be solved here, but it may be worth examining why it happens (assuming that you can reproduce it; My app is very large and complicated).

PS
I have also occasionally noticed similar phenomena as Wimpie3 has reported above.
The Wheelpicker is now an integral part of my app...
Here is the new library files:
1. fixed the crash (don't have to use CallSubDelayed any longer)
2. Fixed the drift that occurred when the click occured
3. Fixed and exposed wp1.ItemSpace (it spaces the horizontal bars further apart/ closer to one another)
 

Attachments

  • WheelPickerLibFiles_V1_10.zip
    19.7 KB · Views: 160

wimpie3

Well-Known Member
Licensed User
Longtime User
@Johan Schoeman Thanks for the update. ItemSpace is working fine, however, I still can put the wheel *between* two values without one value rolling back to the center. It doesn't happen every time but with some practice I can reproduce it.
 
Top