Android Question [Solved] [B4X] How to create a smooth in/out zoom for an image?

fredo

Well-Known Member
Licensed User
Longtime User
For an app that should run on Android and iOS an animation effect is needed.

A fullscreen image shall get an alternating zoom in/out animation. It is expected that after a continuous zoom-in the image stands for a short time and then zooms out again continuously.

This is solved in principle by means of a timer and "SetLayoutAnimated", but it still has the unpleasant side effect that the zoom of the image jumps.

What has to be done to get a smooth zoom in/out that works on Android and iOS alike?
B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: true   
    #IncludeTitle: false   
#End Region

Sub Process_Globals
    Private imagename1 As String = "shot-by-cerqueira-0o_GEzyargo-unsplash.jpg"
    Private xui As XUI
    
    Private ImageScaleAtStart As Float = 1.1
    Private ImageScaleAtZoom As Float = 1.2
    Private MovePaneBigTimer As Timer
    Private MovePaneBigTimerInterval As Int = 3000
    Private MovePaneBigZoomIn As Boolean = True
    
End Sub

Sub Globals
    Private BigImageView1 As B4XView
    Private MasterBack As B4XView
    Private MovePaneBig As B4XView
    Private InfoLabel1 As B4XView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout1")
    CallSubDelayed(Me, "FormFill")
End Sub

Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub

' ---------------------------------------

Sub FillImageToView(bmp As B4XBitmap, ImageView As B4XView)
    ' Erel --> https://www.b4x.com/android/forum/threads/b4x-xui-fill-and-fit-images-without-distortion.86627/#content
    Dim bmpRatio As Float = bmp.Width / bmp.Height
    Dim viewRatio As Float = ImageView.Width / ImageView.Height
    If viewRatio > bmpRatio Then
        Dim NewHeight As Int = bmp.Width / viewRatio
        bmp = bmp.Crop(0, bmp.Height / 2 - NewHeight / 2, bmp.Width, NewHeight)
    Else if viewRatio < bmpRatio Then
        Dim NewWidth As Int = bmp.Height * viewRatio
        bmp = bmp.Crop(bmp.Width / 2 - NewWidth / 2, 0, NewWidth, bmp.Height)
    End If
    Dim scale As Float = 1
    #if B4i
    scale = GetDeviceLayoutValues.NonnormalizedScale
    #End If
    ImageView.SetBitmap(bmp.Resize(ImageView.Width * scale, ImageView.Height * scale, True))
End Sub

Sub FormFill
    
    InfoLabel1.Text = "FormFill"
    
    Dim bmp As B4XBitmap = xui.LoadBitmap(File.DirAssets, imagename1)
    FillImageToView(bmp, BigImageView1)
    MovePaneBigCalcSize(ImageScaleAtStart)
    
    MovePaneBigTimer.Initialize("MovePaneBigTimer", MovePaneBigTimerInterval)
    MovePaneBigTimer.Enabled = True
End Sub

Sub MovePaneBigTimer_Tick
    If MovePaneBigZoomIn Then
        MovePaneBigCalcSize(ImageScaleAtZoom)
    Else
        MovePaneBigCalcSize(ImageScaleAtStart)
    End If
    MovePaneBigZoomIn = Not(MovePaneBigZoomIn)
End Sub

Sub MovePaneBigCalcSize(ScaleFac As Float)
    Dim NewW As Int = MovePaneBig.Width *ScaleFac
    Dim NewH As Int = MovePaneBig.Height *ScaleFac
    Dim NewL As Int = (MovePaneBig.Width -NewW) /2
    Dim NewT As Int = (MovePaneBig.Height -NewH) /2
    
    InfoLabel1.Text = $"SetLayoutAnimated with ScaleFac = $1.2{ScaleFac}"$
        
    BigImageView1.SetLayoutAnimated(MovePaneBigTimerInterval,  NewL, NewT, NewW, NewH)
    'Sleep(MovePaneBigTimerInterval +10)
    'Sleep(10)
    
End Sub


 

Attachments

  • animtest01.zip
    81.9 KB · Views: 283

Erel

B4X founder
Staff member
Licensed User
Longtime User
Designer script:
B4X:
ImageView1.Width = 140%x
ImageView1.Height = 140%y
ImageView1.HorizontalCenter = 50%x
ImageView1.VerticalCenter = 50%y

Code:
B4X:
Sub Process_Globals
    Private xui As XUI 
    Private ImageLoopIndex As Int
End Sub

Sub Globals
    Private InfoLabel1 As B4XView
    Private ImageView1 As B4XView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout1")
    FillImageToView(xui.LoadBitmap(File.DirAssets, "shot-by-cerqueira-0o_GEzyargo-unsplash.jpg"), ImageView1)
    #if B4A
    Dim iv As ImageView = ImageView1
    iv.Gravity = Gravity.FILL
    #End If
End Sub

Sub ImageLoop
    ImageLoopIndex = ImageLoopIndex + 1
    Dim MyIndex As Int = ImageLoopIndex
    Dim Scale As Float = 1
    Dim delta As Float = 0.005 '<---- this defines the rate
    Dim BaseWidth As Int = Activity.Width
    Dim BaseHeight As Int = Activity.Height
    Do While MyIndex = ImageLoopIndex
        If Scale >= 1.4 Then
            delta = -Abs(delta)
        Else If Scale <= 1 Then
            delta = Abs(delta)
        End If
        Scale = Scale + delta
        ImageView1.SetLayoutAnimated(0, BaseWidth / 2 - BaseWidth * Scale / 2, BaseHeight / 2 - BaseHeight * Scale / 2, BaseWidth * Scale, BaseHeight * Scale)
        Sleep(16)
    Loop
End Sub


Sub Activity_Resume
    ImageLoop
End Sub
 

Attachments

  • animtest01.zip
    81.6 KB · Views: 328
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
Addendum:
After the solution was transferred to the large project, it did not work as in the test project.

After some time the cause could be localized in my technical arrogance.

I had assumed that only some parts of the code would have to be copied and pasted. But after desperately comparing the differences, this part was discovered, which is essential for the function:

B4X:
#if B4A
     Dim iv As ImageView = ImageView1
     iv.Gravity = Gravity.FILL
 #End If

So, TIL: "Look and think first, then copy/paste."
 
Upvote 0
Top