Android Question How add value to an int within a time range (MS)

Douglas Farias

Expert
Licensed User
Hello everyone, this question may be simple for many of you, but I can't think very well about it, maybe I need some sleep :)

I have a panel and inside it is a centered label with a value ranging from 0 to 255 depending on the touch on the panel.

Ok, it's already working to touch the panel and show the value on the label, values from 0 to 255.

My question is as follows.
When the user drops his finger on the panel.
Case Activity.ACTION_UP

I need to go from the current value to the maximum value which is 255, but this speed should be based on an animation time.

An example:
At this point I am doing the following, when the user drops the panel finger I simply go from the current value to 255. If the user is at 50 I jump from 50 to 255.

I would like to do something like go from 50 to 255 at (x ms time)

I want to show the user something like (in 2000ms for example, 50 to 255 in 2000ms)
50
51
52
...
255

and not simply jump from 50 to 255.
How can I make this calculation based on an animation time?

make a counter, which adds values in an int up to 255 in a time interval X.

Any tips are welcome, I'm very bad at math.

Thanks.
 

emexes

Well-Known Member
Licensed User
I don't know if this is what you want, but for your example:

(in 2000ms for example, 50 to 255 in 2000ms)

B4X:
'global variables
    Dim CurrentCount As Int
    Dim tmr as Timer
    Dim CountLabel As Label

'start activity sub
    CurrentCount = 50
    CountLabel.Text = CurrentCount

'start count up to 255 bit
    Dim MillisecondsToGo As Int = 2000
    Dim CountToGo As Int = 255 - CurrentCount
    Dim MillisecondsPerCount As Int = MillisecondsToGo / CountToGo    'actual total time out by up to CountToGo ms but should close enough not be noticeable

    tmr.Initialize("tmr", MillisecondsPerCount)
    tmr.Enable = True

'timer tick sub

    If CurrentCount < 255 Then
        CurrentCount  = CurrentCount + 1
        CountLabel = CurrentCount
    End If

    If CurrentCount >= 255 Then
        tmr.Enable = False
    End If
 
Last edited:

emexes

Well-Known Member
Licensed User
The alternative calculation for animation is to base it on the frame rate eg 60 frames per second (fps) = increment CurrentCount by the residual 255 - 50 = 205 in 2000 ms = 120 frames, ie increment CurrentCount by 205 / 120 per frame = slightly over 1.0

Probably easiest to keep CurrentCount as a Float, and clamp it to 255 so that it doesn't skip over and display a higher number.
 

emexes

Well-Known Member
Licensed User
Please use [CODE]code here...[/CODE] tags when posting code.
For conversational coding I am happy with inline text, but... (grumble, grumble) yeah, you're probably more right than I am here :-/

Edit: ah, now I see that the forum editor kindly removed my indenting, so... ok, that'd make you way more right than I am... :)
 

canalrun

Well-Known Member
Licensed User
Hello everyone, this question may be simple for many of you, but I can't think very well about it, maybe I need some sleep :)

I have a panel and inside it is a centered label with a value ranging from 0 to 255 depending on the touch on the panel.
Thanks.

Here is an "old-school" solution that I used many years ago.

In the Action_Down Touch event enable a one second (or whatever time interval) timer.

In the timer tick event read the label text into an INT variable and increment by one. Write the new value to the label as text.

In the Action_Up Touch event disable the timer.

When the person is pressing down on the panel, the label will increment by one each second. The label will stop incrementing when the panel press is released.

You can get fancy: In the timer if the time is greater than five seconds, increment by two. This will speed up the label increment after five seconds off pressing the panel.

Barry.
 

Douglas Farias

Expert
Licensed User
I don't know if this is what you want, but for your example:

(in 2000ms for example, 50 to 255 in 2000ms)

B4X:
'global variables
    Dim CurrentCount As Int
    Dim tmr as Timer
    Dim CountLabel As Label

'start activity sub
    CurrentCount = 50
    CountLabel.Text = CurrentCount

'start count up to 255 bit
    Dim MillisecondsToGo As Int = 2000
    Dim CountToGo As Int = 255 - CurrentCount
    Dim MillisecondsPerCount As Int = MillisecondsToGo / CountToGo    'actual total time out by up to CountToGo ms but should close enough not be noticeable

    tmr.Initialize("tmr", MillisecondsPerCount)
    tmr.Enable = True

'timer tick sub

    If CurrentCount < 255 Then
        CurrentCount  = CurrentCount + 1
        CountLabel = CurrentCount
    End If

    If CurrentCount >= 255 Then
        tmr.Enable = False
    End If
Thank you.
I followed your example, but unfortunately it works slower than it should, it has a speed of 2000 ms set, but it takes about 7 seconds.
Here is my code

B4X:
#Region  Project Attributes
    #ApplicationLabel: Panel Example
    #VersionCode: 1
    #VersionName: 1.0
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: True
#End Region

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

Sub Process_Globals
    Private timer As Timer
End Sub

Sub Globals
    Private pTest As Panel
    Private force As Int = 255
    Private minValue As Int = 0
    Private maxValue As Int = 255
    Private lbForce As Label
  
  
    Dim CurrentCount As Int
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
  
    timer.Initialize("timer", 1000)

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub



Sub pTest_Touch (Action As Int, X As Float, Y As Float)
  
    Select Action
      
        Case Activity.ACTION_DOWN, Activity.ACTION_MOVE
            force = y / pTest.Height * 255
            If force <= minValue Then force = 0
            If force >= maxValue Then force = 255
            lbForce.Text = maxValue - force 'FORÇA TEXTO
          
      
        Case Activity.ACTION_UP 
            CurrentCount = lbForce.Text

            Dim MillisecondsToGo As Int = 2000
            Dim CountToGo As Int = 255 - CurrentCount
            Dim MillisecondsPerCount As Int = MillisecondsToGo / CountToGo

            timer.Interval = MillisecondsPerCount
            timer.Enabled = True
          
          
      
    End Select
  

      
      
      
End Sub


Sub timer_Tick
    If CurrentCount < 255 Then
        CurrentCount  = CurrentCount + 1
        lbForce.Text = CurrentCount
    End If

    If CurrentCount >= 255 Then
        timer.Enabled = False
    End If
End Sub
what am I doing wrong?
on my example the TOP is = 255 and the BOTTOM is = 0, you can move the finger and see the current value on the label.
 

Attachments

emexes

Well-Known Member
Licensed User
Thank you.
I followed your example, but unfortunately it works slower than it should, it has a speed of 2000 ms set, but it takes about 7 seconds.
Here is my code
Looks ok.
what am I doing wrong?
Possibly nothing, but I can't think what (or what not ;-)
Good question. Log the three numbers after calculating the interval:
B4X:
Log(MillisecondsToGo & " " & CountToGo & " " & MillisecondsPerCount)
and perhaps the timer events:
B4X:
Sub timer_Tick
    Log("timer " & CurrentCount & " " & DateTime.Now)
 

Brandsum

Well-Known Member
Licensed User
Try this
B4X:
Sub Process_Globals
    Dim initVal = 50, maxVal = 255 As Int
    Dim running As Boolean = False
End Sub

Sub Activity_Touch (Action As Int, X As Float, Y As Float)
    Select Action
        Case Activity.ACTION_DOWN
            running = False
            increase(initVal,maxVal,2000)
        Case Activity.ACTION_UP
            running = False
            decrease(maxVal,initVal,2000)
    End Select
End Sub

Sub increase(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (tonum - fromnum)
    running = True
    Do While fromnum < tonum And running
        Activity.Title = fromnum
        fromnum = fromnum + interval
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub

Sub decrease(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (fromnum - tonum)
    running = True
    Do While fromnum > tonum And running
        Activity.Title = fromnum
        fromnum = fromnum - interval
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub
 

Douglas Farias

Expert
Licensed User
Hi @Brandsum
i m tryed your code on my example.

B4X:
        Case Activity.ACTION_UP
            initVal = valorMaximo - forca
            Log(initVal)
            Log(maxVal)
            running = False
            increase(initVal,maxVal,2000) 'NOTE THE 2000 HERE
the logs are
initVal = 163
maxVal = 255

i m trying to increase this value of 163 to 255 in 2000ms
i m using your sub(increase), without changes, and this is much fast, more then 2000ms
it looks have 20ms really fast, this is ignoring the 2000ms.
 

JordiCP

Well-Known Member
Licensed User
Shouldn't it be? :rolleyes:
B4X:
Sub increase(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (tonum - fromnum)
    running = True
    Do While fromnum < tonum And running
        Activity.Title = fromnum
        fromnum = fromnum + 1                '<--  HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub

Sub decrease(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (fromnum - tonum)
    running = True
    Do While fromnum > tonum And running
        Activity.Title = fromnum
        fromnum = fromnum - 1                 '<-- HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub
 

Brandsum

Well-Known Member
Licensed User
Shouldn't it be? :rolleyes:
B4X:
Sub increase(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (tonum - fromnum)
    running = True
    Do While fromnum < tonum And running
        Activity.Title = fromnum
        fromnum = fromnum + 1                '<--  HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub

Sub decrease(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (fromnum - tonum)
    running = True
    Do While fromnum > tonum And running
        Activity.Title = fromnum
        fromnum = fromnum - 1                 '<-- HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub
No it will take much longer than 2 sec.
 

Brandsum

Well-Known Member
Licensed User
Hi @Brandsum
i m tryed your code on my example.

B4X:
        Case Activity.ACTION_UP
            initVal = valorMaximo - forca
            Log(initVal)
            Log(maxVal)
            running = False
            increase(initVal,maxVal,2000) 'NOTE THE 2000 HERE
the logs are
initVal = 163
maxVal = 255

i m trying to increase this value of 163 to 255 in 2000ms
i m using your sub(increase), without changes, and this is much fast, more then 2000ms
it looks have 20ms really fast, this is ignoring the 2000ms.
Ok let me check.
 

Douglas Farias

Expert
Licensed User
Shouldn't it be? :rolleyes:
B4X:
Sub increase(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (tonum - fromnum)
    running = True
    Do While fromnum < tonum And running
        Activity.Title = fromnum
        fromnum = fromnum + 1                '<--  HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub

Sub decrease(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (fromnum - tonum)
    running = True
    Do While fromnum > tonum And running
        Activity.Title = fromnum
        fromnum = fromnum - 1                 '<-- HERE
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub
tested here and works fine for low values, now i m trying the decrease sub.
if i ACTION_UP and the current value is 50, it works fine 50 to 0 in 2000 ms
but if the value is 255 and need go to 0 this take a long time to go to 0, more then 2000ms, i will make a video to show.
 

Douglas Farias

Expert
Licensed User

Here is the result.
i m using
B4X:
Sub decrease(fromnum As Int, tonum As Int, within As Long)
    Dim interval As Int = within / (fromnum - tonum)
    running = True
    Do While fromnum > tonum And running
        lbForca.Text = fromnum
        fromnum = fromnum - 1
        Sleep(interval)
    Loop
    Activity.Title = tonum
    running = False
End Sub

and to move the line on the video i m using
pLinha.SetLayoutAnimated(2000,pLinha.Left,pVibrador.Height - pLinha.Height - 2dip,pLinha.Width, pLinha.Height)
 

Brandsum

Well-Known Member
Licensed User
Now it's accurate as its based on android valueanimator object.
B4X:
Sub Process_Globals
    Dim initVal = 50, maxVal = 255 As Int
    Dim duration = 2000 As Long
    Dim valueanimator,animatorvalue As JavaObject
End Sub

Sub Activity_Create(FirstTime As Boolean)
    valueanimator.InitializeStatic("android.animation.ValueAnimator")
    valueanimator=valueanimator.RunMethodJO("ofInt",Array(Array As Int(initVal,maxVal)))
    valueanimator.RunMethodJO("setDuration",Array(duration))
    
    Dim event As Object = valueanimator.CreateEvent("android.animation.ValueAnimator.AnimatorUpdateListener","Received","")
    valueanimator.RunMethod("addUpdateListener",Array(event))
End Sub


Private Sub Received_Event (MethodName As String, Args() As Object) As Object
    Select MethodName
        Case "onAnimationUpdate"
            animatorvalue = Args(0)
            Activity.Title = animatorvalue.RunMethod("getAnimatedValue",Null)
    End Select
    
End Sub

Sub Activity_Touch (Action As Int, X As Float, Y As Float)
    Select Action
        Case Activity.ACTION_DOWN
            valueanimator.RunMethod("start",Null)
        Case Activity.ACTION_UP
            valueanimator.RunMethod("reverse",Null)
    End Select
End Sub
 

JordiCP

Well-Known Member
Licensed User
Jordi's is fixed 1 step that's why it takes longer.
Where is the dislike button?;)

I stand that the original solution with step=interval is still incorrect.
For instance, if we choose fromnum=0, tonum=100 and within=2000, the calculated interval will be 20msec
If we added 'interval' to 'fromnum' each time, the loop would only be executed 5 times (0->20, 20->40, 40->60, 60->80 and 80->100) with a 20msec sleep each one, so it would be executed in about 100msec.

The reason why it works slower with step=1 when interval is low may be due to other causes, such as other tasks adding a bit of overhead during the sleep period, as for instance happens in debug mode.


Now it's accurate as its based on android valueanimator object.
Really elegant :)
 

sorex

Expert
Licensed User
he could also just have used a timer and just keep track of that moving line's Y position and calculate the percentage of the panel it's at and 'scale' that to 0-255.
 
Top