Android Tutorial SmartHost - Lesson 3 - Sliders

Sliders are a very useful and common control but are not part of the core B4A product. In this lesson we are going to build a slider control like the one shown in the screenshot.

To build a slider you need two pieces:
A) A background "image" to convey a sense of purpose to what the slider adjusts.
B) A slider handle which the user can drag to change the value.

Slider Background
Smarthost supports the following backgrounds for a slider bar.
  1. Image File (generates a nice result but hard to get one just right)
  2. Color - Gradient or solid
  3. Text\Emoji
  4. Transparency (for a different view underneath)

Slider Handle

The slider handle is a separate SmartHost and is not limited in what it can display and can also be animated if desired.

This is what we are going to build in this Lesson, a fully working ARGB view.
Lesson3_FullScreen_Shrunk.png


This lesson assumes that you have been through SmartHost - Lessons 1&2 and only newly introduced functions are covered at length.

Creating the Background
B4X:
'This code draws a red gradient across the page that is used to form the background of a slider bar.
'SliderScaleRed has already been dimmed in the Globals section

'Initialize the SmartHost and place it on the screen
SliderScaleRed.Initialize("SliderScaleRed", Me, Activity, "", 1)
SliderScaleRed.SetLayout(5%x, 10%y, 50%x, 10%y, 10%y, "")

'A description of the BackgroundGradient function was covered in SmartHost - Lesson 2
'In short we have a Left to Right gradient across the entire width of the SmartHost
SliderScaleRed.BackgroundGradient("HOST", Array As Int(MyColors.SetAlpha(Colors.red, 32), Colors.Red), 20, "LEFT_RIGHT" )

'Finally we add some Text. I could also add Icons if I wished such as Left and Right arrows
' and move them to the edges with LayerMove but I wanted to keep it simple.
'The LayerAddText function is discussed in SmartHost Lesson 1
SliderScaleRed.LayerAddText(SliderScaleRed.cLayerTitle, "Slide to adjust", Colors.Yellow, 70, Gravity.CENTER, False, Typeface.DEFAULT)

Creating the Slider Handle
B4X:
'SliderIconRed has already been dimmed in the Globals section
'Create a new SmartHost that is 10%y square and place it on top of the red gradient
SliderIconRed.Initialize("SliderIconRed", Me, Activity, "Slider", 1 )
SliderIconRed.SetLayout(45%x, 10%y, 10%y, 10%y, 10%y, "CC")

'LayerAddIcon has been covered at length in SmartHost - Lesson 1.
'We are using the Sun symbol as this seemed like a good choice for a brightness type control
'but any character could be used in any color and be animated if so desired.
SliderIconRed.LayerAddIcon("Icon1", Icons.Unicode.MiscSymbols.Black_Sun_With_Rays, Colors.Yellow, 100, Typeface.DEFAULT )

'We want to be able to drag the Slider handle left and right so we have to turn on drag and drop
'AllowDragDrop(1): Allows a SmartHost to be moved. A 1 limits its movement to the X axis only.
'RetainPosition(True): True indicates the SmartHost should remain in its dropped position.
SliderIconRed.DragAndDrop(1, True)

'The SmartHost movement is limited to the X axis. Now we must restrict it to the gradient area.
'LeftLimitX (SliderScaleRed.HostLeft): Limits leftward movement to the left edge of the gradient.
'RightLimitX (SliderScaleRed.HostRight): Limits rightward movement to the right edge of the gradient.
'TopLimitX (0): This value is ignored because Y movement is not restricted.
'BottomLimitX (0): This value is ignored because Y movement is not restricted.
SliderIconRed.DragAndDropLimits(SliderScaleRed.HostLeft, SliderScaleRed.HostRight, 0, 0)

'Enable the SmartHost Timer which we will use to do real-time updates of the panel color.
'Enable (True): Turns the timer of and on.
'Interval (25): Sets the Interval in ms that the Timer will fire.
'When the Timer fires a callback is placed to Eventname_Tick, in this case Slider_Tick
SliderIconRed.TimerEnable(True, 25)

Host Timer
Every SmartHost has a Timer defined that sits unused unless Enabled by the developer. Having a Timer defined within the SmartHost simplifies your code and keeps things cleaner. All you have to do is Enable the Timer, set the frequency and create the callback function with what you want it to do.

In this case I'm going to use the SmartHost Timer to do realtime updates of the panel that displays the selected ARGB values. If this were a numeric scale this would not be required.

The code below shows a simplified version of Sub Slider_Tick. I have removed the lines that update the Green, Blue and Transparent values as these are basically the same as the Red Slider.
B4X:
Sub Slider_Tick
    'Calculate the range of motion of the Slider Handle
    Dim RangeofMotion As Float = SliderScaleRed.HostWidth - SliderIconRed.HostWidth

    'Determine where we are along the Gradient as a number between 0 and 1
    Dim RedRatio As Float = (1 - (SliderScaleRed.HostRight - SliderIconRed.HostRight) / RangeofMotion)
    'Multiply the position value * 255 so the result can only be in the range 0 - 255
    Dim RedVal As Int = 255 * RedRatio

    'Finally update the panel color with the new value.
    pnl.Color = Colors.ARGB(TransparentVal, RedVal, GreenVal, BlueVal)
End Sub

Transparent Slider
For the Transparent slider I chose to demonstrate that the same principles can be used for a vertical slider. The big difference in creating the vertical slider is that you create the slider in the same way and then rotate the SmartHost by 90 degrees once it has been completed.

B4X:
'Rotate the SmartHost by 90 degrees (and everything inside it)
'Degrees (-90): Degrees to rotate the SmartHost. Use negative numbers for anti-clockwise
'PivotX (-50): Moves the X axis pivot point left 50%. ie the left edge.
'PivotY (-50): Moves the Y axis pivot point down 50%. ie the bottom edge.
'A pivot point of 0,0 is the exact center of the SmartHost. Using -50 and -50 moves the pivot point to the bottom left corner. This was just what made sense to me but there are multiple ways of doing this.
SliderScaleTransparent.Rotate(-90, -50, -50)

Once the SmartHost has been rotated it can get a little confusing as the terms Left, Top, Width, Height no longer apply in their original sense. Instead I used SliderScaleRed.HostTop to refer to the Top edge of the Transparent gradient and SliderScaleBlue.HostBottom to refer to the Bottom edge of the Transparent gradient.

Note: Use SmartHost.Host???? for host positions. SmartHost.Icon??? for icon positions. A SmartHost can also return the values for the Right and Bottom edges without having to calculate those separately.


Other Slider BackGrounds
In the Lesson files I have created two additional slider backgrounds. The first uses a long skinny bitmap image from the Assets folder. Loading the bitmap is very simple use SliderImageScale.BackgroundImage and load a Bitmap into it as shown below.
Lesson3_OtherSliders.png

B4X:
SliderImageScale.BackgroundImage(LoadBitmapSample(File.DirAssets, "SliderImage.png", SliderImageScale.HostWidth, SliderImageScale.HostHeight) )

The second example shows part of the versatility of a SmartHost. While it looks a Bitmap it is a combination of a background gradient and the Unicode vertical bar character. We'll take a look at the code as it introduces some new principles.
B4X:
Dim SliderMarkers As SmartHost

'This is familiar but there is one nuance.
'I am using 2 stacks (one for text layers and one for Icon layers)
'When using 2 stacks percentages are measured in reference to the host dimensions, not the Icon.
SliderMarkers.Initialize("SliderMarkers", Me, Activity, "", 2)

'Note that the Icon positioning is "CL", Center Left. You'll see why in a minute.
SliderMarkers.SetLayout(5%x, 85%y, 50%x, 5%x, 5%x, "CL")

'Note the array of colors can be as many as you want. Using three gives a pleasing shadow effect.
SliderMarkers.BackgroundGradient("HOST", Array As Int(Colors.LightGray, Colors.DarkGray, Colors.LightGray), 20 , "LEFT_RIGHT")
SliderMarkers.LayerAddText(SliderMarkers.cLayerTitle, " or you could use any Font Icons", Colors.Yellow, 70, Gravity.CENTER, False, Typeface.DEFAULT)

'Now it gets interesting.
'I've decided I want to add some scale markings to the SmartHost for effect.
'I'm going to make 11 scale markings. Using an odd number let's me start and end with the large vertical bar.
'So I create a loop from 0 - 10 (11 entries, a SmartHost can have up to 16 layers)
For I = 0 To 10
    If I Mod 2 = 0 Then
        'Even numbered layers will be a full size vertical bar.
        SliderMarkers.LayerAddIcon("Layer" & I, 0xFF5C, Colors.Black, 100, Typeface.DEFAULT)
    Else
        'Odd numbered layers will be a 1/2 size vertical bar.
        SliderMarkers.LayerAddIcon("Layer" & I, 0xFF5C, Colors.Black, 50, Typeface.DEFAULT)
    End If

    'Now we have our 11 markers all stacked up on the left edge ("CL")
    'All we have to do now is distribute them evenly.
    'So we just move each Icon Layer to the right by I * (100/11).  The 100 is 100% of the Host Width.
    SliderMarkers.LayerMove(I, 0, I * (100/11), 0, 0)

    'If you uncomment the line below you will see Icon borders drawn around each layer
    'This is just a troubleshooting technique for use in the development process.
    'SliderMarkers.DeveloperShowIconBorder(I, 0)
Next

With this basic structure in place changing gradients, colors, markings, sizes, text etc become simple changes with no new artwork required.

One last thing to think about. Remember that each layer is it's own entity and can be manipulated independently of any other layer. If we add the following one line of code to the loop:
B4X:
'Layer (I): The name or number of the Layer to change.
'FromDegrees (0): Starting position in degrees.
'ToDegrees (360): Ending position in degrees.
'PivotX (0): The X pivot point. 0 is the horizontal center of the layer.
'PivotY (0): The Y pivot point. 0 is the vertical center of the layer.
'Duration (500 - I * 10): The time in ms that it takes to complete one animation cycle
'RepeatMode (SliderMarkers.cRepeatRestart): Either .cRepeatRestart or .cRepeatReverse
'RepeatCount (SliderMarkers.cRepeatForever): Number of repetitions of the animation.
'Delay (2500 + I * 10): Idle time in ms between animation cycles.
SliderMarkers.LayerAnimateRotate(I, 0, 360, 0, 0, 500 - I * 10, SliderMarkers.cRepeatRestart, SliderMarkers.cRepeatForever, 2500 + I * 10)
We generate an effect where each of the markings does a 360 degree rotation every 2500 ms. By staggering the duration of the effect but keeping duration + delay constant the animation remains in sync. This simply demonstrates the flexibility of a SmartHost and that you have to think differently about it's capabilities and limitations.

Demo files attached. Make sure you download the most recent version of the SmartHost Library as I fixed a bug in the DragandDrop code while developing this lesson.
 

Attachments

  • Lesson3.zip
    7.6 KB · Views: 229
Last edited:
Top