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: 435
  • b4aWheelPicker.zip
    407.3 KB · Views: 616
  • WheelPickerLibFiles.zip
    17 KB · Views: 566
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
@wimpie3, see if the attached lib files make it better. I could before spin the wheel and when I stopped it I saw on occasions that it would stop somewhere between two values. I have added a "fix" to the original code that eliminates this problem. I could also before (with a lot of effort) position/balance the wheel between two values (once in about 100 attempts) which I could not replicate thus far with the attached library files.
 

Attachments

  • WheelPickerLib_V_1.11.zip
    19.7 KB · Views: 298

Johan Schoeman

Expert
Licensed User
Longtime User
I am very pleased with Wheelpicker version 1.11.
I have one more request: Currently my Wheelpicker displayes text in the center. However if the text is too long then parts of the text drop-off at the left and right side, which is ugly. To avoid that, I am currently shortening too long texts. Would it be possible to make the wheelpicker only drop-off texts at the right hand side, such that every item in the WP list always starts with the first word of the text?
Syd, there is already
wp1.ItemAlign = 0 or 1 or 2
0 = center align
1 = left align
2 = right align

Does that not sort out your problem?
 

Johan Schoeman

Expert
Licensed User
Longtime User
Hi Johan,

No, I am already using 'center align', which I prefer over 'left align', because everything is centered nicely, especially in conjunction with: WP1.Curved = True. Left align does not look nice when using the curved mode.
I.e. my question was related to 'center align'.

An alternative could be if it is somehow possible to determine the maximum number of characters per item before characters start dropping-off to the left and the right. Any ideas?
No ideas at present Syd. Will have to go work through the original code and also browse the web to see if I can find a possible solution. Not promising any positive outcome but will look into it this coming weekend and see if I can find a solution
 

wimpie3

Well-Known Member
Licensed User
Longtime User
Can the font be changed for each wheel? It now seems to use the standard Android font.
 

Johan Schoeman

Expert
Licensed User
Longtime User
Can the font be changed for each wheel? It now seems to use the standard Android font.
Download the amended project from here
https://www.dropbox.com/s/qwxymx25xnxylbt/b4aWheelPickerTypeface.zip?dl=0

The library files that you will need is included in the B4A project folder. Copy them to your additional library folder (FontoMetrics.jar, FontoMetrics.xml, WheelPicker.jar, WheelPicker.xml). The Fontometrics library allows you to select 24 different fonts.

The WheelPicker library is V1.13

Project is too large to upload here.

You should see this when running the sample project and clicking on the button (bottom left):

pic1.png


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: ..\LibRes

#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.
   
    Dim t As Timer
   

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    
   
    Dim wp1position As Int  = 3
    Dim wp2position As Int  = 7
   
   
    Private Panel1 As Panel
    Private Button1 As Button
    Dim fm As FontoMetrics
   
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")
    t.Initialize("t", 2000)
    wp1.Initialize("wp1")
    fm.Initialize
   
'    wp2.Initialize("wp2")
'    Activity.AddView(wp2, 10%x, 50%y, 80%x, 40%y)
   
'    Panel1.Initialize("")
'    wp1.Initialize("wp1")
   
    Activity.AddView(wp1, 5%x, 5%y, 70%x, 70%x)
'    Panel1.AddView(wp1, Panel1.Left , Panel1.Top , Panel1.Width * 0.5, Panel1.Height * 0.5)
'    Panel1.Color = Colors.Blue
   
    wp1.Curved = True
    wp1.Cyclic = True
    wp1.CurtainColor = Colors.ARGB(50, 100, 100, 100)    
    wp1.Curtain = True
    wp1.SelectedItemTextColor = Colors.Red
    wp1.ItemTextColor = Colors.Black
    wp1.Atmospheric = False
    wp1.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp1.ItemTextSize = 35    
    wp1.SelectedItemPosition = wp1position             'it will start at Thursday   
    wp1.VisibleItemCount = 5
    wp1.SameWidth = True                     'not sure what this is supposed to do
    wp1.Indicator = True
    wp1.IndicatorColor = Colors.Yellow
    wp1.IndicatorSize = 9
    wp1.ItemSpace = 20
    wp1.Typeface = fm.pacifico
       
    mydaylist.Initialize
    For j = 0 To 200
        mydaylist.Add("" & j)
    Next
    '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 = wp2position             'it will start at August  
'    wp2.SelectedItemTextColor = Colors.Cyan
'    wp2.VisibleItemCount = 6
'    wp2.SameWidth = True                     'not sure what this is supposed to do
'    wp2.Indicator = True
'    wp2.IndicatorColor = Colors.Cyan
'    wp2.IndicatorSize = 7   
'
'    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
   
    't.Enabled = True

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   
    't.Enabled = False

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

Sub t_tick
   
    wp2.SelectedItemPosition = Rnd(0,12)

   
End Sub

Sub wp1_index_changed (currentindex As Int)
   
    'YOU NEED TO ADD CODE HERE TO TEST FOR AN OVERSCROLL WHEN CYCLIC IS SET TO FALSE
    'eg if currentindex = 0 at present and the immediate next value is for eg 6 then the user is dragging down too far
    'eg if currentindex = 6 at present and the immediate next value is for eg 0 the the used is dragging up too far
    'correct scrolling sequence should be currentindex values changing from 0 to number of items -1 or from number of items -1 to 0
    'HOPE YOU FOLLOW WHAT I AM TRYING TO EXPLAIN HERE
   
    If wp1position <> currentindex Then
       Log("wp1 current index = " & currentindex)
       wp1position = currentindex
    End If  
      
End Sub

Sub wp1_index_clicked(position As Int)
   
    Log("clicked and position = " & position)
    Wait(100)

End Sub

'Sub wp2_index_changed (currentindex As Int)
'   
'    If wp2position <> currentindex Then
'       Log("wp2 current index = " & currentindex)
'       wp2position = currentindex
'    End If  
'   
'End Sub

Sub Button1_Click
   
For i = 0 To 1                        'RUN THIS TWICE WHEN YOU CHANGE THE CONTENT - IT IS A FIX FOR NOW BUT HAVE NOT
                                    'MANAGED TO TRAP WHY IT DOES NOT WORK WHEN IT IS EXECUTED ONLY ONCE
    mydaylist.Clear
    mydaylist.AddAll(Array As String("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
   
    wp1.Curved = True
    wp1.Cyclic = True
    'wp1.CurtainColor = Colors.ARGB(50, 255, 255, 255)    
    wp1.Curtain = True
    wp1.SelectedItemTextColor = Colors.Yellow
    wp1.ItemTextColor = Colors.Red
    wp1.Atmospheric = True
    wp1.ItemAlign = 0                        '0 = center, 1 = left, 2 = right
    wp1.ItemTextSize = 40    
    wp1.VisibleItemCount = 3
    wp1.SameWidth = True                     'not sure what this is supposed to do
    wp1.Indicator = True
    wp1.IndicatorColor = Colors.Green
    wp1.IndicatorSize = 3
   
    wp1.Typeface = fm.pacifico
   
    wp1.Data = mydaylist
    wp1.SelectedItemPosition = 1             'it will start at Tuesday  
    wp1.Invalidate
   
Next
   
End Sub

Sub Wait(MilliSekunden As Int)
    Dim Ti As Long
    Ti = DateTime.Now + MilliSekunden
    Do While DateTime.Now < Ti
        DoEvents
    Loop
End Sub
 

wimpie3

Well-Known Member
Licensed User
Longtime User
Thanks. Did you use FontoMetrics just as an example? Can I use my own font? If I'm correct FontoMetrics provices 24 fonts by default, but I'd like to use my own.
 
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
Thanks. Did you use FontoMetrics just as an example? Can I use my own font? If I'm correct FontoMetrics provices 24 fonts by default, but I'd like to use my own.
You can make use of your own fonts too. Put your .ttf files inside the /Files folder of the B4A project, add them to the Files tab of the IDE and then use the following code:
B4X:
    Dim mytypeface As Typeface
    mytypeface = Typeface.LoadFromAssets("Open 24 Display St.ttf")
    'wp1.Typeface = fm.pacifico
    wp1.Typeface = mytypeface

In the above example I have a font named Open 24 Display St.ttf inside the /Files folder of my B4A project. It gives this:

2.png
 

JOTHA

Well-Known Member
Licensed User
Longtime User
Hello Johan Schoeman,

... great Job!
I'll test it ...
 

dottorjeckill

New Member
Licensed User
Longtime User
Hi Mr. Schoeman,

i've a problem with your library. When i compile and execute your samples there isn't any problem. The library is the version 1.13, i updated also JDK and the ide is the 7.01.

I've inserted the control into the activity (from the designer), and loaded only the activity, no other code. Compiled without errors and when i send it to device, during the activity load i've this error :

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
main_activity_create (java line: 333)
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:166)
at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
at b4a.example.main._activity_create(main.java:333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:186)
at b4a.example.main.afterFirstLayout(main.java:102)
at b4a.example.main.access$000(main.java:17)
at b4a.example.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:64)
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:158)
... 17 more
Caused by: android.content.res.Resources$NotFoundException: String array resource ID #0x0
at android.content.res.Resources.getStringArray(Resources.java:385)
at com.aigestudio.wheelpicker.WheelPicker.<init>(WheelPicker.java:284)
at com.aigestudio.wheelpicker.WheelPicker.<init>(WheelPicker.java:276)
at wheelpickerwrapper.wheelpickerWrapper._initialize(wheelpickerWrapper.java:64)
... 21 more

I tried also to copy and paste your code in my project (so without adding the control on the designer but dynamically created) and the error is the same on the Initialize line.

I attached my test project so you can see and i hope you can repeat the problem.

Thanks in advance.

Cristiano.
 

Attachments

  • TESTB4A.zip
    409 KB · Views: 230

DonManfred

Expert
Licensed User
Longtime User
I attached my test project so you can see and i hope you can repeat the problem.
You did forget to add the Resourcefolder i guess. See the folder wheelpicker_resource inside the example.
You need to add this folder to your project. And the #additionalres-line too for sure....
 

Johan Schoeman

Expert
Licensed User
Longtime User

Johan Schoeman

Expert
Licensed User
Longtime User
can i get current selected item??? it is write only, but i need read it????
You can use the index returned in

B4X:
Sub wp1_index_changed (currentindex As Int)
  
    'YOU NEED TO ADD CODE HERE TO TEST FOR AN OVERSCROLL WHEN CYCLIC IS SET TO FALSE
    'eg if currentindex = 0 at present and the immediate next value is for eg 6 then the user is dragging down too far
    'eg if currentindex = 6 at present and the immediate next value is for eg 0 the the used is dragging up too far
    'correct scrolling sequence should be currentindex values changing from 0 to number of items -1 or from number of items -1 to 0
    'HOPE YOU FOLLOW WHAT I AM TRYING TO EXPLAIN HERE
  
    If wp1position <> currentindex Then
       Log("wp1 current index = " & currentindex)
       wp1position = currentindex
    End If 
     
End Sub

....and then look it up in the list that you passed to the library
 

Johan Schoeman

Expert
Licensed User
Longtime User
Yes, I already found this wheel, but I was hoping that you could add a parameter to this WheelPicker, something like "WP1.orientation = [0 or 1]" or WP1.orientation = ["Horizontal" or "Vertical")
Syd, unfortunately this one comes in VERTICAL only - unless someone wants to go add a whole lot of code to the original project to accommodate HORIZONTAL.
 

stanks

Active Member
Licensed User
Longtime User
any posibility to add long click to selected item? any posibility to add image to items? i know for your git hub hor/vert view wheel but that one doesn't have click methods and have images

thanks
 
Top