B4A Library [B4X] [XUI] B4XLoadingIndicator - loading indicator

Latest version is included in XUI Views library.

This is a custom view that can be used as an alternative to indeterminate progress bars.
It is compatible with B4A, B4J and B4i.

Inspired by: https://github.com/81813780/AVLoadingIndicatorView

B4XLoadingIndicator.gif


Add with the designer and set the style:

SS-2018-04-23_11.40.16.png


Tips

- It will work properly in debug mode but will not be smooth. Should look good in release mode.
- You can change the duration of a single cycle. The default is 1000ms. For some of the types such as Arc 1 and Arc 2 it makes sense to change it to about 2000.
- See the code. Shouldn't be difficult to add more types of animations.
- In B4A you should add this code in Activity_Resume:
B4X:
Sub Activity_Resume
   For Each v As View In Activity.GetAllViewsRecursive
       If v.Tag Is B4XLoadingIndicator And v.Visible = True Then
           Dim x As B4XLoadingIndicator = v.Tag
           x.Show
       End If
   Next

The class which is compatible with B4A, B4i and B4J is included inside the attached B4A example.
 

Attachments

  • B4XLoadingIndicator.zip
    10.8 KB · Views: 2,544
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Wonderful :)
 

Indy

Active Member
Licensed User
Longtime User
Hi Erel,

I might have use for this as an alternative to the Progress Dialog. Do you have example code which can setup these without doing it in the designer?

Thanks
 

Swissmade

Well-Known Member
Licensed User
Longtime User
Very Nice thanks Erel
 

Star-Dust

Expert
Licensed User
Longtime User
I added three more indicators just to spite Erel. :p (I joke)
ezgif.com-crop.gif


here you find the code to insert:
B4X:
Private Sub Draw_ThreeCircles1b (Progress As Float)
    Dim MaxR As Float = (cvs.TargetRect.Width / 2 - 20dip) / 2
    Dim r As Float = 15dip + MaxR + MaxR * Sin(Progress * 1 * cPI)
    For i = 0 To 2
        Dim alpha As Int = i * 120 + Progress * 360
        cvs.DrawCircle(cvs.TargetRect.CenterX + r * SinD(alpha), cvs.TargetRect.CenterY + r * CosD(alpha), 7dip, clr, True, 1dip)
    Next
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.Centery,7dip,clr,True,1dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.Centery,r,clr,False,1dip)
End Sub


Private Sub Draw_ThreeCircles3 (Progress As Float)
    Dim r As Float = Min(cvs.TargetRect.Width,cvs.TargetRect.Height)/2-7dip
    Dim B As Boolean = False
     
    For i=0 To 9
        'Dim alpha As Int = i * 120 + Progress * 360
        Dim Alpha As Float = i*36
        'cvs.DrawCircle(cvs.TargetRect.CenterX + r * SinD(Alpha), cvs.TargetRect.CenterY + r * CosD(Alpha), 7dip, xui.Color_LightGray, True, 1dip)
        If Alpha>Progress*360 And B=False Then
            cvs.DrawCircle(cvs.TargetRect.CenterX + r * SinD((i-1)*36), cvs.TargetRect.CenterY + r * CosD((i-1)*36), 7dip,Bit.And(clr,0xAAffffff), True, 1dip)
            cvs.DrawCircle(cvs.TargetRect.CenterX + r * SinD(Alpha), cvs.TargetRect.CenterY + r * CosD(Alpha), 7dip,clr, True, 1dip)
            B=True
        Else
            cvs.DrawCircle(cvs.TargetRect.CenterX + r * SinD(Alpha), cvs.TargetRect.CenterY + r * CosD(Alpha), 7dip, Bit.And(clr,0x55ffffff), True, 1dip)
        End If
    Next

End Sub

Private Sub Draw_TenLines (Progress As Float)
    Dim r As Float = Min(cvs.TargetRect.Width,cvs.TargetRect.Height)/2
    Dim B As Boolean = False
    Dim Spess As Int = 6dip
     
    For i=0 To 9
        'Dim alpha As Int = i * 120 + Progress * 360
        Dim Alpha As Float = i*36
     
        If Alpha>Progress*360 And B=False Then
            cvs.DrawLine(cvs.TargetRect.CenterX + r * SinD((i-1)*36), cvs.TargetRect.CenterY + r * CosD((i-1)*36),cvs.TargetRect.CenterX + (r/2) * SinD((i-1)*36), cvs.TargetRect.CenterY + (r/2) * CosD((i-1)*36),Bit.And(clr,0xAAFFFFFF),Spess)
            cvs.DrawLine(cvs.TargetRect.CenterX + r * SinD(Alpha), cvs.TargetRect.CenterY + r * CosD(Alpha),cvs.TargetRect.CenterX + (r/2) * SinD(Alpha), cvs.TargetRect.CenterY + (r/2) * CosD(Alpha),clr,Spess)
            B=True
        Else
            cvs.DrawLine(cvs.TargetRect.CenterX + r * SinD(Alpha), cvs.TargetRect.CenterY + r * CosD(Alpha),cvs.TargetRect.CenterX + (r/2) * SinD(Alpha), cvs.TargetRect.CenterY + (r/2) * CosD(Alpha),Bit.And(clr,0x55FFFFFF),Spess)
        End If
    Next

End Sub

And obviously make the change in the design properties so that they are added to the list,
B4X:
#DesignerProperty: Key: IndicatorStyle, DisplayName: Style, FieldType: String, DefaultValue: Three Circles 1, List: Three Circles 1|Three Circles 1b|Three Circles 2|Three Circles 3|Single Circle|Five Lines 1|Ten Lines|Arc 1|Arc 2|PacMan

I'm also adding these, but I will not publish the sources, you too must squeeze the meninges :p
ezgif.com-optimize.gif
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User



are you sure? :cool:
Sure, as I am also sure that with a little commitment we can all contribute to the forum with a snippet of code :D

Then as my mother often said: Why do I have to do everything in this house? Do something yourself too
 

Peter Simpson

Expert
Licensed User
Longtime User
[QUOTE="Star-Dust, post: 588303, member:
Then as my mother often said: Why do I have to do everything in this house? Do something yourself too[/QUOTE]

So you did, you did the programming ;)...
 

Star-Dust

Expert
Licensed User
Longtime User
I have extended the indicators of progress with some other element. I attach the source code
Video2.gif


Update source code
 

Attachments

  • LoadingIndicator.zip
    12.1 KB · Views: 1,383
Last edited:

Alexander Stolte

Expert
Licensed User
Longtime User
Time for 3 "New" Animations. Thanks @Star-Dust for his "XArc" Animation, this new 3 ones, are based on this.

B4X:
Private Sub Draw_XArcv2 (Progress As Float)
    Dim r As Float = (Min(cvs.TargetRect.Width,cvs.TargetRect.Height)/2)-3.5dip
    Dim r2 As Float = 2*r/2.2
    Dim r3 As Float = 2*r/2.4
    Dim p As B4XPath
        
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r-1dip,xui.Color_Transparent,True,1dip)

    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r3,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r3-1dip,xui.Color_Transparent,True,1dip)
    
End Sub


Private Sub Draw_XArcv3 (Progress As Float)
    Dim r As Float = (Min(cvs.TargetRect.Width,cvs.TargetRect.Height)/2)-3.5dip
    Dim r2 As Float = 2*r/2.2
    Dim r3 As Float = 2*r/2.4
    Dim r4 As Float = 2*r/2.8
    Dim r5 As Float = 2*r/3.2
    Dim r6 As Float = 2*r/3.8
    Dim r7 As Float = 2*r/4.4
    Dim r8 As Float = 2*r/6
    Dim r9 As Float = 2*r/8
    Dim r10 As Float = 2*r/14
    Dim r11 As Float = 2*r/25
    Dim p As B4XPath
        
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r-1dip,xui.Color_Transparent,True,1dip)

    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r3,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r3-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r4,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r4-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r5,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r5-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r6,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r6-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r7,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r7-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r8,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r8-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r9,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r9-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r10,Progress*360,180)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r10-1dip,xui.Color_Transparent,True,1dip)
    
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r11,-Progress*360,180)
    cvs.DrawPath(p,clr,False,2dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r11-1dip,xui.Color_Transparent,True,1dip)
End Sub

Private Sub Draw_XArcv4 (Progress As Float)
    Dim r As Float = (Min(cvs.TargetRect.Width,cvs.TargetRect.Height)/2)-3.5dip
    Dim r2 As Float = 2*r/2.7
    Dim p As B4XPath
        
    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r,-Progress*360 -180,120)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r-1dip,xui.Color_Transparent,True,1dip)

    p.InitializeArc(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2,Progress*360,120)
    cvs.DrawPath(p,clr,False,6dip)
    cvs.DrawCircle(cvs.TargetRect.CenterX,cvs.TargetRect.CenterY,r2-1dip,xui.Color_Transparent,True,1dip)

End Sub

loadingview.gif
 

Mehrzad238

Active Member
I just created 5 new styles for this class and did not know where to share them, so I'm just gonna share them here:



B4X:
Private Sub Draw_HeartBeat(Progress As Float)
    Dim width As Float = cvs.TargetRect.Width
'    Dim height As Float = cvs.TargetRect.Height
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim segmentWidth As Float = width / 4 ' Divide canvas into 4 segments for repeating pattern
    Dim p As B4XPath
    p.Initialize(0, centerY)

    ' Calculate the offset to move the pattern leftward
    Dim offsetX As Float = Progress * segmentWidth

    ' Draw multiple segments to ensure the canvas is filled
    For x = -segmentWidth To width + segmentWidth Step 1
        Dim relativeX As Float = (x + offsetX) Mod segmentWidth
        Dim normalizedX As Float = relativeX / segmentWidth ' 0 to 1 within a segment
        Dim y As Float = centerY

        ' Define heartbeat pattern within one segment
        If normalizedX < 0.2 Then
            ' Flat line before spike
            y = centerY
        Else If normalizedX < 0.3 Then
            ' Small dip (P wave)
            y = centerY + 10dip * SinD((normalizedX - 0.2) * 1800) ' Smooth dip
        Else If normalizedX < 0.4 Then
            ' Sharp spike up (QRS complex)
            y = centerY - 30dip * (1 - Abs((normalizedX - 0.35) / 0.05))
        Else If normalizedX < 0.5 Then
            ' Sharp spike down
            y = centerY + 20dip * (1 - Abs((normalizedX - 0.45) / 0.05))
        Else If normalizedX < 0.6 Then
            ' Small rise (T wave)
            y = centerY - 10dip * SinD((normalizedX - 0.5) * 1800)
        Else
            ' Flat line
            y = centerY
        End If

        ' Add point to path
        If x = -segmentWidth Then
            p.Initialize(x, y)
        Else
            p.LineTo(x, y)
        End If
    Next

    ' Draw the heartbeat line
    cvs.DrawPath(p, clr, False, 2dip)
End Sub

Private Sub Draw_FourDotsSquare(Progress As Float)
    Dim r As Float = Min(cvs.TargetRect.Width, cvs.TargetRect.Height) / 2 - 8dip
    Dim corners(4) As Float
    corners(0) = 0    ' Top-left
    corners(1) = 90   ' Top-right
    corners(2) = 180  ' Bottom-right
    corners(3) = 270  ' Bottom-left
    For i = 0 To 3
        Dim angle As Float = corners(i) + Progress * 360
        angle = angle Mod 360
        Dim x, y As Float
        If angle < 90 Then
            x = r * (1 - angle / 90)
            y = -r
        Else If angle < 180 Then
            x = -r
            y = -r + (angle - 90) / 90 * 2 * r
        Else If angle < 270 Then
            x = -r + (angle - 180) / 90 * 2 * r
            y = r
        Else
            x = r
            y = r - (angle - 270) / 90 * 2 * r
        End If
        cvs.DrawCircle(cvs.TargetRect.CenterX + x, cvs.TargetRect.CenterY + y, 7dip, clr, True, 1dip)
    Next
End Sub

Private Sub Draw_NewtonCradle(Progress As Float)
    Dim ballRadius As Float = 7dip
    Dim spacing As Float = 2 * ballRadius ' Balls touch when at rest
    Dim maxOffset As Float = 10dip ' Maximum linear offset for first/last balls
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY + 20dip ' Suspend balls slightly below center
    Dim ballX(5) As Float
    Dim ballY(5) As Float

    ' First ball (index 0) moves left and back (0 to 0.3)
    If Progress < 0.3 Then
        Dim moveProgress As Float = Progress / 0.3 ' 0 to 1 over 0 to 0.3
        If moveProgress <= 0.5 Then
            ballX(0) = centerX - 2 * spacing - maxOffset * (moveProgress * 2) ' Move left
        Else
            ballX(0) = centerX - 2 * spacing - maxOffset * (2 - moveProgress * 2) ' Move back
        End If
    Else
        ballX(0) = centerX - 2 * spacing ' Back to original position
    End If
    ballY(0) = baseY

    ' Last ball (index 4) moves right and back (0.3 to 1.0)
    If Progress >= 0.3 Then
        Dim moveProgress As Float = (Progress - 0.3) / 0.7 ' 0 to 1 over 0.3 to 1.0
        If moveProgress <= 0.5 Then
            ballX(4) = centerX + 2 * spacing + maxOffset * (moveProgress * 2) ' Move right
        Else
            ballX(4) = centerX + 2 * spacing + maxOffset * (2 - moveProgress * 2) ' Move back
        End If
    Else
        ballX(4) = centerX + 2 * spacing ' Original position
    End If
    ballY(4) = baseY

    ' Middle balls (indices 1, 2, 3) are stationary
    For i = 1 To 3
        ballX(i) = centerX + (i - 2) * spacing
        ballY(i) = baseY
    Next

    ' Draw the 5 balls
    For i = 0 To 4
        cvs.DrawCircle(ballX(i), ballY(i), ballRadius, clr, True, 1dip)
    Next
End Sub

Private Sub Draw_BouncingDots(Progress As Float)
    Dim smallRadius As Float = 7dip ' Radius for stationary dots
    Dim largeRadius As Float = 10dip ' Radius for bouncing dots
    Dim spacing As Float = 2 * largeRadius ' Spacing between dots (based on larger dots)
    Dim maxBounce As Float = 15dip ' Maximum vertical bounce distance
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY ' Align dots vertically at center
    Dim dotX(6) As Float
    Dim dotY(6) As Float

    ' Calculate positions for 6 dots
    For i = 0 To 5
        dotX(i) = centerX + (i - 2.5) * spacing ' Center the dots horizontally
        dotY(i) = baseY
    Next

    ' Second dot (index 1) bounces during 0 to 0.5
    If Progress < 0.5 Then
        Dim bounceProgress As Float = Progress * 2 ' 0 to 1 over 0 to 0.5
        dotY(1) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Fifth dot (index 4) bounces during 0.5 to 1.0
    If Progress >= 0.5 Then
        Dim bounceProgress As Float = (Progress - 0.5) * 2 ' 0 to 1 over 0.5 to 1.0
        dotY(4) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Draw the 6 dots
    For i = 0 To 5
        If i = 1 Or i = 4 Then
            cvs.DrawCircle(dotX(i), dotY(i), largeRadius, clr, True, 1dip)
        Else
            cvs.DrawCircle(dotX(i), dotY(i), smallRadius, clr, True, 1dip)
        End If
    Next
End Sub

Private Sub Draw_BouncingDots2 (Progress As Float)
    Dim ballRadius As Float = 7dip
    Dim spacing As Float = 2 * ballRadius ' Dots touch when at rest
    Dim maxBounce As Float = 15dip ' Maximum vertical bounce distance
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY ' Align dots vertically at center
    Dim dotX(6) As Float
    Dim dotY(6) As Float

    ' Calculate positions for 6 dots
    For i = 0 To 5
        dotX(i) = centerX + (i - 2.5) * spacing ' Center the dots horizontally
        dotY(i) = baseY
    Next

    ' Determine which dot is bouncing based on Progress
    Dim phase As Float = Progress * 6 ' 0 to 6 over the cycle
    Dim currentDot As Int = Floor(phase) ' Current dot index (0 to 5)
    Dim bounceProgress As Float = phase - currentDot ' 0 to 1 within the current phase

    ' Bounce the current dot
    If currentDot >= 0 And currentDot < 6 Then
        dotY(currentDot) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Draw the 6 dots
    For i = 0 To 5
        cvs.DrawCircle(dotX(i), dotY(i), ballRadius, clr, True, 1dip)
    Next
End Sub

Do not forget to add the style in DesignerProperty.

B4X:
#DesignerProperty: Key: IndicatorStyle, DisplayName: Style, FieldType: String, DefaultValue: Three Circles 1, List: Three Circles 1|Three Circles 2|NewtonCradle |Three Circles 3|FourDotsSquare |Single Circle|Follow Circles|Follow Circles 2|Five Lines 1|Five Ball|Ten Lines|Ten Circles|Arc 1|Arc 2|X Arc|Heartbeat |PacMan|Square|BouncingDots2 |BouncingDots |Square Rounded
 

Attachments

  • ezgif-75b6aea8185d19 (1).gif
    ezgif-75b6aea8185d19 (1).gif
    387.8 KB · Views: 53
Last edited:

Mehrzad238

Active Member
I just created 5 new styles for this class and did not know where to share them, so I'm just gonna share them here:



B4X:
Private Sub Draw_HeartBeat(Progress As Float)
    Dim width As Float = cvs.TargetRect.Width
'    Dim height As Float = cvs.TargetRect.Height
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim segmentWidth As Float = width / 4 ' Divide canvas into 4 segments for repeating pattern
    Dim p As B4XPath
    p.Initialize(0, centerY)

    ' Calculate the offset to move the pattern leftward
    Dim offsetX As Float = Progress * segmentWidth

    ' Draw multiple segments to ensure the canvas is filled
    For x = -segmentWidth To width + segmentWidth Step 1
        Dim relativeX As Float = (x + offsetX) Mod segmentWidth
        Dim normalizedX As Float = relativeX / segmentWidth ' 0 to 1 within a segment
        Dim y As Float = centerY

        ' Define heartbeat pattern within one segment
        If normalizedX < 0.2 Then
            ' Flat line before spike
            y = centerY
        Else If normalizedX < 0.3 Then
            ' Small dip (P wave)
            y = centerY + 10dip * SinD((normalizedX - 0.2) * 1800) ' Smooth dip
        Else If normalizedX < 0.4 Then
            ' Sharp spike up (QRS complex)
            y = centerY - 30dip * (1 - Abs((normalizedX - 0.35) / 0.05))
        Else If normalizedX < 0.5 Then
            ' Sharp spike down
            y = centerY + 20dip * (1 - Abs((normalizedX - 0.45) / 0.05))
        Else If normalizedX < 0.6 Then
            ' Small rise (T wave)
            y = centerY - 10dip * SinD((normalizedX - 0.5) * 1800)
        Else
            ' Flat line
            y = centerY
        End If

        ' Add point to path
        If x = -segmentWidth Then
            p.Initialize(x, y)
        Else
            p.LineTo(x, y)
        End If
    Next

    ' Draw the heartbeat line
    cvs.DrawPath(p, clr, False, 2dip)
End Sub

Private Sub Draw_FourDotsSquare(Progress As Float)
    Dim r As Float = Min(cvs.TargetRect.Width, cvs.TargetRect.Height) / 2 - 8dip
    Dim corners(4) As Float
    corners(0) = 0    ' Top-left
    corners(1) = 90   ' Top-right
    corners(2) = 180  ' Bottom-right
    corners(3) = 270  ' Bottom-left
    For i = 0 To 3
        Dim angle As Float = corners(i) + Progress * 360
        angle = angle Mod 360
        Dim x, y As Float
        If angle < 90 Then
            x = r * (1 - angle / 90)
            y = -r
        Else If angle < 180 Then
            x = -r
            y = -r + (angle - 90) / 90 * 2 * r
        Else If angle < 270 Then
            x = -r + (angle - 180) / 90 * 2 * r
            y = r
        Else
            x = r
            y = r - (angle - 270) / 90 * 2 * r
        End If
        cvs.DrawCircle(cvs.TargetRect.CenterX + x, cvs.TargetRect.CenterY + y, 7dip, clr, True, 1dip)
    Next
End Sub

Private Sub Draw_NewtonCradle(Progress As Float)
    Dim ballRadius As Float = 7dip
    Dim spacing As Float = 2 * ballRadius ' Balls touch when at rest
    Dim maxOffset As Float = 10dip ' Maximum linear offset for first/last balls
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY + 20dip ' Suspend balls slightly below center
    Dim ballX(5) As Float
    Dim ballY(5) As Float

    ' First ball (index 0) moves left and back (0 to 0.3)
    If Progress < 0.3 Then
        Dim moveProgress As Float = Progress / 0.3 ' 0 to 1 over 0 to 0.3
        If moveProgress <= 0.5 Then
            ballX(0) = centerX - 2 * spacing - maxOffset * (moveProgress * 2) ' Move left
        Else
            ballX(0) = centerX - 2 * spacing - maxOffset * (2 - moveProgress * 2) ' Move back
        End If
    Else
        ballX(0) = centerX - 2 * spacing ' Back to original position
    End If
    ballY(0) = baseY

    ' Last ball (index 4) moves right and back (0.3 to 1.0)
    If Progress >= 0.3 Then
        Dim moveProgress As Float = (Progress - 0.3) / 0.7 ' 0 to 1 over 0.3 to 1.0
        If moveProgress <= 0.5 Then
            ballX(4) = centerX + 2 * spacing + maxOffset * (moveProgress * 2) ' Move right
        Else
            ballX(4) = centerX + 2 * spacing + maxOffset * (2 - moveProgress * 2) ' Move back
        End If
    Else
        ballX(4) = centerX + 2 * spacing ' Original position
    End If
    ballY(4) = baseY

    ' Middle balls (indices 1, 2, 3) are stationary
    For i = 1 To 3
        ballX(i) = centerX + (i - 2) * spacing
        ballY(i) = baseY
    Next

    ' Draw the 5 balls
    For i = 0 To 4
        cvs.DrawCircle(ballX(i), ballY(i), ballRadius, clr, True, 1dip)
    Next
End Sub

Private Sub Draw_BouncingDots(Progress As Float)
    Dim smallRadius As Float = 7dip ' Radius for stationary dots
    Dim largeRadius As Float = 10dip ' Radius for bouncing dots
    Dim spacing As Float = 2 * largeRadius ' Spacing between dots (based on larger dots)
    Dim maxBounce As Float = 15dip ' Maximum vertical bounce distance
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY ' Align dots vertically at center
    Dim dotX(6) As Float
    Dim dotY(6) As Float

    ' Calculate positions for 6 dots
    For i = 0 To 5
        dotX(i) = centerX + (i - 2.5) * spacing ' Center the dots horizontally
        dotY(i) = baseY
    Next

    ' Second dot (index 1) bounces during 0 to 0.5
    If Progress < 0.5 Then
        Dim bounceProgress As Float = Progress * 2 ' 0 to 1 over 0 to 0.5
        dotY(1) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Fifth dot (index 4) bounces during 0.5 to 1.0
    If Progress >= 0.5 Then
        Dim bounceProgress As Float = (Progress - 0.5) * 2 ' 0 to 1 over 0.5 to 1.0
        dotY(4) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Draw the 6 dots
    For i = 0 To 5
        If i = 1 Or i = 4 Then
            cvs.DrawCircle(dotX(i), dotY(i), largeRadius, clr, True, 1dip)
        Else
            cvs.DrawCircle(dotX(i), dotY(i), smallRadius, clr, True, 1dip)
        End If
    Next
End Sub

Private Sub Draw_BouncingDots2 (Progress As Float)
    Dim ballRadius As Float = 7dip
    Dim spacing As Float = 2 * ballRadius ' Dots touch when at rest
    Dim maxBounce As Float = 15dip ' Maximum vertical bounce distance
    Dim centerX As Float = cvs.TargetRect.CenterX
    Dim centerY As Float = cvs.TargetRect.CenterY
    Dim baseY As Float = centerY ' Align dots vertically at center
    Dim dotX(6) As Float
    Dim dotY(6) As Float

    ' Calculate positions for 6 dots
    For i = 0 To 5
        dotX(i) = centerX + (i - 2.5) * spacing ' Center the dots horizontally
        dotY(i) = baseY
    Next

    ' Determine which dot is bouncing based on Progress
    Dim phase As Float = Progress * 6 ' 0 to 6 over the cycle
    Dim currentDot As Int = Floor(phase) ' Current dot index (0 to 5)
    Dim bounceProgress As Float = phase - currentDot ' 0 to 1 within the current phase

    ' Bounce the current dot
    If currentDot >= 0 And currentDot < 6 Then
        dotY(currentDot) = baseY - maxBounce * SinD(bounceProgress * 180) ' Bounce up
    End If

    ' Draw the 6 dots
    For i = 0 To 5
        cvs.DrawCircle(dotX(i), dotY(i), ballRadius, clr, True, 1dip)
    Next
End Sub

Do not forget to add the style in DesignerProperty.

B4X:
#DesignerProperty: Key: IndicatorStyle, DisplayName: Style, FieldType: String, DefaultValue: Three Circles 1, List: Three Circles 1|Three Circles 2|NewtonCradle |Three Circles 3|FourDotsSquare |Single Circle|Follow Circles|Follow Circles 2|Five Lines 1|Five Ball|Ten Lines|Ten Circles|Arc 1|Arc 2|X Arc|Heartbeat |PacMan|Square|BouncingDots2 |BouncingDots |Square Rounded
The names of styles are
  • NewtonCradle
  • Heartbeat
  • BouncingDots
  • BouncingDots2
  • FourDotsSquare
 

Theera

Expert
Licensed User
Longtime User
I have tried to do as StarDust's strategy. It'sOK. Thank you all of you.
B4X:
Private Sub Draw_ThaiFlag (Progress As Float)
    ' Thai flag colors
    Dim redColor As Int = 0xFFED1C24    ' แดง
    Dim whiteColor As Int = 0xFFFFFFFF   ' ขาว
    Dim blueColor As Int = 0xFF0032A0    ' น้ำเงิน
    
    ' Flag dimensions
    Dim flagWidth As Float = cvs.TargetRect.Width * 0.8
    Dim flagHeight As Float = flagWidth * 2/3    ' Thai flag ratio is 2:3
    
    ' Flag position
    Dim leftX As Float = cvs.TargetRect.CenterX - flagWidth/2
    Dim topY As Float = cvs.TargetRect.CenterY - flagHeight/2
    
    ' Stripe heights (Thai flag has 5 horizontal stripes with ratio 1:1:2:1:1)
    Dim unitHeight As Float = flagHeight / 6
    
    ' Wave parameters
    Dim waveAmplitude As Float = unitHeight * 0.4  ' ขนาดของคลื่น
    Dim waveFrequency As Float = 2                ' ความถี่ของคลื่น
    Dim wavePhase As Float = Progress * cPI * 2    ' เฟสของคลื่นเคลื่อนที่ตามเวลา
    
    ' Draw flag with wave effect
    For x = 0 To flagWidth Step 1dip
        ' Calculate wave offset for this x position
        Dim waveY As Float = Sin(wavePhase + x * waveFrequency / flagWidth * cPI) * waveAmplitude
        
        ' Draw each stripe as a vertical line with wave offset
        ' Red stripe at top (1/6)
        cvs.DrawLine(leftX + x, topY + waveY, leftX + x, topY + unitHeight + waveY, redColor, 1dip)
        
        ' White stripe (1/6)
        cvs.DrawLine(leftX + x, topY + unitHeight + waveY, leftX + x, topY + unitHeight * 2 + waveY, whiteColor, 1dip)
        
        ' Blue stripe (2/6)
        cvs.DrawLine(leftX + x, topY + unitHeight * 2 + waveY, leftX + x, topY + unitHeight * 4 + waveY, blueColor, 1dip)
        
        ' White stripe (1/6)
        cvs.DrawLine(leftX + x, topY + unitHeight * 4 + waveY, leftX + x, topY + unitHeight * 5 + waveY, whiteColor, 1dip)
        
        ' Red stripe at bottom (1/6)
        cvs.DrawLine(leftX + x, topY + unitHeight * 5 + waveY, leftX + x, topY + unitHeight * 6 + waveY, redColor, 1dip)
    Next
    
    ' Draw pole
    Dim poleWidth As Float = 6dip
    myRect AsB4XRect
    myRect.Initialize(leftX - poleWidth, topY - 10dip, poleWidth, flagHeight + 20dip)
    cvs.DrawRect(myRect, 0xFF8B4513, True, 5dip)
End Sub
 
Top