B4i Library [class] Spinner

I wrote this class to try to simplify porting a B4A app to B4i. The app uses Spinners, and I was frustrated by the lack of a suitable replacement. I tried Pickers, but they take up too much space. Also, a lot of fiddly changes/conditional compilation is required to handle differences between B4A and B4i, in particular differences in trivial things like the way you set the text size.

So, I wrote this class to mimic the B4A Spinner programming interface and hide a lot of the differences between B4a and B4i, thus reducing the number of changes/conditional compilation required. It's a CustomView, so can be set up in the Designer or created programmatically. The attached sample project contains examples of both.

Internally it's implemented as a Label which when clicked displays an action sheet for the user to make their selection.

The class expects the same _ItemClick callback as the B4A Spinner, and implements all of the B4A Spinner methods EXCEPT for the following:
  • Background
  • DropdownBackgroundColor
  • DropdownTextColor
  • Invalidate
  • Invalidate2
  • Invalidate3
  • Prompt
  • SetBackgroundImage
  • SetColorAnimated
  • SetVisibleAnimated
The following methods have been added:
  • SetCallbackModule - By default the class assumes that the callback routine is in the Main module. If it isn't you must call SetCallbackModule to set the module it is in. eg spr.SetCallbackModule(Me)
  • View - returns the underlying Label used in the Spinner class. Useful for changing it's attributes directly
  • GetBase - if the Spinner was created in the Designer then this returns the Base Panel containing the Spinner. If the Spinner was created programmatically then this return the underlying Label used in the Spinner class. Useful for adding the Spinner to a parent view. eg:
B4X:
myPanel.Addview (spr.GetBase, 0, 0, 20, 10)
  • SetBorder - Set the border of the underlying label
  • TextAlignment - attribute to get/set the alignment of the text in the underlying label.
I hope this is of some use.

Hugh

2015-12-08 Updated with V0.10
2016-04-20 Updated with V0.11
2016-07-06 Updated with V0.20
 

Attachments

  • Spinner0.20.zip
    6.8 KB · Views: 142
Last edited:

JohnC

Expert
Licensed User
Longtime User
Thanks for sharing! I'll try it out on my next project.
 

JonPM

Well-Known Member
Licensed User
Longtime User
Thanks for this. Have you published an app with this yet? I know Apple can be picky with non-native UI elements sometimes
 

Hugh Thomas

Member
Licensed User
Longtime User
Yes. If you search for "groupcalc" in the App Store you will find GroupCalc Free and GroupCalc Pro. Both make extensive use of the "Spinner" class in the Keystone screen. The reason I implemented the Spinner class as an Action Sheet rather than emulating the "look" of an Android Spinner was that I wanted it to look like an iOS App, not a ported Android App.

Likewise if you search for "groupcalc" in the Google Play store you'll find Android versions of both version of GroupCalc apps. They are build from the same sources as the iOS version (although I'm more familiar with #ifdef than I'd like ;^)).

In writing and porting these apps I implemented a number of other cross platform classes and useful routines which I plan to make available when I get the time to clean them up. This include a CheckBox class (implemented using a Switch), a FileDialog class, and various routines such as IsTablet, GetOsVersion, GetModel, GetSoftKeyboardHeight.

Hugh
 

Arf

Well-Known Member
Licensed User
Longtime User
I have two questions. I have a single 'settings' page with 6 spinners on it. There are arrows to scroll between 3 pages of settings in my app.
In the B4A version I just call Spinner.Clear when I move to a new page, and populate the spinner with the next bunch of options I want to.

Using your class, when I do Spinner.Clear, the contents of the array I used to populate the spinner is erased as well.
So question 1 is, is there a way I can prevent that from happening?

Then, if I set the spinner.Visible = false for spinners I am not using on a particular page, they seem to stay visible.
So question 2 is - Is there something else I need to do to make them disappear?

Thanks
 

Arf

Well-Known Member
Licensed User
Longtime User
Fixed, I made a new version of the AddAll function.

B4X:
public Sub AddAll (items As List)   
    itemList = items
End Sub

public Sub AddAll_Copied (items As List)   
    Dim nulist As List
    nulist.Initialize
    nulist.AddAll(items)
    itemList = nulist
End Sub
 

Hugh Thomas

Member
Licensed User
Longtime User
Fixed, I made a new version of the AddAll function.

Thanks, I'll posted an update to the class with this fix shortly.

Then, if I set the spinner.Visible = false for spinners I am not using on a particular page, they seem to stay visible.
So question 2 is - Is there something else I need to do to make them disappear?

No, setting spr.visible should work. I do this in my app and it works fine. All setting spr.visible does is set the visibility of the underlying label, so I can't see why it wouldn't work. If you get the value of spr.visible after setting it to FALSE, does it return the value FALSE?

Hugh
 

Arf

Well-Known Member
Licensed User
Longtime User
I discovered that the spinner that was remaining visible was actually because I had created multiple spinners, I forgot that the scope of a Page is not destroyed when exiting a page (Process_Global rather than Global, as in B4A). So I found if I removed the spinner views before exiting the page, I could re-enter without having the problem I encountered. So all working now :)
 

Hugh Thomas

Member
Licensed User
Longtime User
I've updated the base note with an updated version, v0.10.

Changes included are:
  • Fix problem in spr.AddAll(). Was saving a reference to the passed list, not making a copy.
  • Enabled flag not enforced correctly. Also update the Enable that the Spinner is greyed-out when Disabled.
  • Removed SetLayoutAnimated. This was listed Not Supported in the comments, but a version of this method was inadvertently left in.
  • Minor improvements to the example app
Hugh
 

cirollo

Active Member
Licensed User
Longtime User
Hi! I'm getting an error with this...

B4X:
'Adds a single item to the Spinner
public Sub Add (item As String)
   itemList.Add(item)
End Sub

when trying to add items to a spinner without using addall....

ciro
 

Hugh Thomas

Member
Licensed User
Longtime User
Ciro,

I've added a new version (V0.11) to the base note of this thread, containing a fix for this problem.

Hugh
 

cirollo

Active Member
Licensed User
Longtime User
Hi hugh! thank you I'll try ASAP...

by the way, I'm having some troubles on the item_click event of the spinner...It seems that is never triggered....

this is my code, do you find something wrong?

B4X:
Sub SpTipoTrasf_ItemClick (Position As Int, Value As Object)
   Msgbox(SpTipoTrasf.SelectedIndex," ")
   If SpTipoTrasf.SelectedIndex=0 Then
     TxtFtpHost.Enabled=False
     TxtFtpPort.Enabled=False
     TxtFtpUser.Enabled=False
     TxtFtpPwd.Enabled=False
   Else
     TxtFtpHost.Enabled=True
     TxtFtpPort.Enabled=True
     TxtFtpUser.Enabled=True
     TxtFtpPwd.Enabled=True   
   End If
End Sub
 

Hugh Thomas

Member
Licensed User
Longtime User
Ciro,

Your callback routine looks ok. Is it located in the main module? By default the class assumes that the callback routine is in the main module. If it is in another module then you have to call SetCallbackModule to tell the class which module contains the callback routine.

Hugh
 

Sanxion

Active Member
Licensed User
Longtime User
I understand that the two methods: DropDownBackgroundColor and DropDownTextColor are not implemented but I am assuming they can be changed from the default White (Background) and Blue (text) that they are set to at the moment?
 
Last edited:

Hugh Thomas

Member
Licensed User
Longtime User
Hi Saxion,

I'm not aware of any way of setting the action sheet's background and text colors using the standard ActionSheet interface. There may be ways of doing "under the hood", but I don't know how to do that.

Hugh
 

Hugh Thomas

Member
Licensed User
Longtime User
I've updated to the base note in this thread with V0.20. This version adds CustomView functionality, so you can now set up the Spinner in the Designer.

You can still create Spinners programmatically, but if you've been using one of the previous versions note the following changes in this release:
  • In earlier versions spr.Initialize() had one parameter - the EventName. In this version you also need to provide the CallBack module, eg:
B4X:
spr.Initialize(Me,"spr")
  • In earlier versions you would use spr.View to get the underlying Label if you wanted to change its attributes directly, or to add it to a parent view. In this release the underlying label will be within a base Panel if the Spinner was created in the Designer, so I've introduced an additional method called GetBase. If the Spinner was created in the Designer then GetBase returns the base panel that was created by the Designer to contain the CustomView. If the Spinner was created programmatically then GetBase returns the underlying label. So regardless of how the Spinner was created you can do the following:
B4X:
myPanel.AddView(spr.GetBase, 0, 0, 40, 20)
If you want to access the underlying label in order to set its attributes you can still use spr.View, which will always return the underlying label, regardless of whether it's within a base panel or not.
Hugh
 
Top