Android Question Carousel View

ykucuk

Well-Known Member
Licensed User
Longtime User
Hello, I would like to create a user interface (B4A and B4i) like the one in the attached image. I should be able to slide the panels to the left and right. The middle panel will be larger than the others. Can you help me with this?
 

Attachments

  • uisample.jpeg
    uisample.jpeg
    78.3 KB · Views: 198
Solution
Here it is. It turns out that on most standard screen aspect ratios only three panels can be shown.
This version works with landscape and portrait. I have added a opacity screen for visible images out of focus.
There is no problem with animation speed.

carousel.gif

William Lancee

Well-Known Member
Licensed User
Longtime User
B4XPages.. Here is a start, I put it in landscape, but you will see how to modify it for your needs. So far 100 lines.
You'll need a CustomListView in MainPage (anchored at all edges).

(I just started a photography hobby and this would be useful.)

B4X:
#Region Shared Files
#CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True
#End Region

'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=Project.zip

Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private CustomListView1 As CustomListView
    Private currentIndex As Int
    Private touchPanel As Panel
    Private startPointX As Float
    Private panelWidth As Float
End Sub

Public Sub Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    panelWidth = Root.Width / 3

    Sleep(10)
    Dim touchPanel As Panel
    touchPanel.Initialize("touchpnl")
    Root.AddView(touchPanel, 0, 0, Root.Width, Root.Height)
   
    For i = 0 To 5
        Dim pnl As B4XView = xui.CreatePanel("")
        pnl.SetColorAndBorder(xui.Color_White, 2dip, xui.Color_Black, 0)
        pnl.SetLayoutAnimated(0, 0, 0, (Root.width - 50) / 3, Root.Height)
       
        Log(Root.Width / 3)
       
        Dim lbl As Label: lbl.Initialize("")
        Dim lblx As B4XView = lbl
        lblx.SetTextAlignment("CENTER", "CENTER")
        lblx.SetColorAndBorder(xui.Color_RGb(220, 220, 255), 1dip, xui.color_black, 0)
        If i = 0 Or i = 5 Then
            lblx.Text = "Blank"
        Else
            lblx.Text = "XXXX " & i
        End If
        pnl.AddView(lblx, 30dip, 30dip, pnl.Width - 60dip, pnl.Height - 60dip)
        CustomListView1.Add(pnl, i)
    Next
    currentIndex = 1
    Dim pnl As B4XView = CustomListView1.GetPanel(currentIndex)
    Dim lblx As B4XView = pnl.GetView(0)
    lblx.SetLayoutAnimated(0, 0, 0, pnl.Width, pnl.height)
End Sub

Sub touchpnl_Touch(Action As Int, X As Float, Y As Float)
    Dim saveIndex As Int = currentIndex
    Select Action
        Case touchPanel.ACTION_DOWN
            startPointX = X
        Case touchPanel.ACTION_MOVE
        Case touchPanel.ACTION_UP
            Dim pnl As B4XView = CustomListView1.GetPanel(saveIndex)
            Dim lblx As B4XView = pnl.GetView(0)
            lblx.SetLayoutAnimated(0, 30dip, 30dip, pnl.Width - 60dip, pnl.Height - 60dip)
            If X > startPointX Then
                If currentIndex > 1 Then animateToRight Else currentIndex = currentIndex + 1
                currentIndex = currentIndex - 1
            Else If X < startPointX Then
                currentIndex = currentIndex + 1
                If currentIndex < CustomListView1.size - 1 Then animateToLeft Else currentIndex = currentIndex - 1
            End If
            Dim pnl As B4XView = CustomListView1.GetPanel(currentIndex)
            Dim lblx As B4XView = pnl.GetView(0)
            lblx.SetLayoutAnimated(0, 0, 0, pnl.Width, pnl.height)
    End Select
    Sleep(10)
End Sub

private Sub animateToLeft
    Dim startOffset As Int = CustomListView1.sv.ScrollViewOffsetX
    Dim targetOffset As Int =  startOffset + panelWidth
    Dim stepSize As Float = (targetOffset - startOffset) / 10
    Do While startOffset < targetOffset
        startOffset = startOffset + stepSize
        If startOffset > targetOffset Then Exit
        CustomListView1.sv.ScrollViewOffsetX = startOffset
        Sleep(10)
        stepSize = Max(5, stepSize - 1)
    Loop
    CustomListView1.sv.ScrollViewOffsetX = targetOffset
End Sub

private Sub animateToRight
    Dim startOffset As Int = CustomListView1.sv.ScrollViewOffsetX
    Dim targetOffset As Int =  startOffset - panelWidth
    Dim stepSize As Float = (targetOffset - startOffset) / 10
    Do While startOffset > targetOffset
        startOffset = startOffset + stepSize
        If startOffset < targetOffset Then Exit
        CustomListView1.sv.ScrollViewOffsetX = startOffset
        Sleep(10)
        stepSize = Min(-5, stepSize - 1)
    Loop
    CustomListView1.sv.ScrollViewOffsetX = targetOffset
End Sub

screenshot99.png
 

Attachments

  • startCarousel.zip
    14.5 KB · Views: 79
Upvote 0

ykucuk

Well-Known Member
Licensed User
Longtime User
B4XPages.. Here is a start, I put it in landscape, but you will see how to modify it for your needs. So far 100 lines.
You'll need a CustomListView in MainPage (anchored at all edges).

(I just started a photography hobby and this would be useful.)

B4X:
#Region Shared Files
#CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True
#End Region

'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=Project.zip

Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private CustomListView1 As CustomListView
    Private currentIndex As Int
    Private touchPanel As Panel
    Private startPointX As Float
    Private panelWidth As Float
End Sub

Public Sub Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    panelWidth = Root.Width / 3

    Sleep(10)
    Dim touchPanel As Panel
    touchPanel.Initialize("touchpnl")
    Root.AddView(touchPanel, 0, 0, Root.Width, Root.Height)
  
    For i = 0 To 5
        Dim pnl As B4XView = xui.CreatePanel("")
        pnl.SetColorAndBorder(xui.Color_White, 2dip, xui.Color_Black, 0)
        pnl.SetLayoutAnimated(0, 0, 0, (Root.width - 50) / 3, Root.Height)
      
        Log(Root.Width / 3)
      
        Dim lbl As Label: lbl.Initialize("")
        Dim lblx As B4XView = lbl
        lblx.SetTextAlignment("CENTER", "CENTER")
        lblx.SetColorAndBorder(xui.Color_RGb(220, 220, 255), 1dip, xui.color_black, 0)
        If i = 0 Or i = 5 Then
            lblx.Text = "Blank"
        Else
            lblx.Text = "XXXX " & i
        End If
        pnl.AddView(lblx, 30dip, 30dip, pnl.Width - 60dip, pnl.Height - 60dip)
        CustomListView1.Add(pnl, i)
    Next
    currentIndex = 1
    Dim pnl As B4XView = CustomListView1.GetPanel(currentIndex)
    Dim lblx As B4XView = pnl.GetView(0)
    lblx.SetLayoutAnimated(0, 0, 0, pnl.Width, pnl.height)
End Sub

Sub touchpnl_Touch(Action As Int, X As Float, Y As Float)
    Dim saveIndex As Int = currentIndex
    Select Action
        Case touchPanel.ACTION_DOWN
            startPointX = X
        Case touchPanel.ACTION_MOVE
        Case touchPanel.ACTION_UP
            Dim pnl As B4XView = CustomListView1.GetPanel(saveIndex)
            Dim lblx As B4XView = pnl.GetView(0)
            lblx.SetLayoutAnimated(0, 30dip, 30dip, pnl.Width - 60dip, pnl.Height - 60dip)
            If X > startPointX Then
                If currentIndex > 1 Then animateToRight Else currentIndex = currentIndex + 1
                currentIndex = currentIndex - 1
            Else If X < startPointX Then
                currentIndex = currentIndex + 1
                If currentIndex < CustomListView1.size - 1 Then animateToLeft Else currentIndex = currentIndex - 1
            End If
            Dim pnl As B4XView = CustomListView1.GetPanel(currentIndex)
            Dim lblx As B4XView = pnl.GetView(0)
            lblx.SetLayoutAnimated(0, 0, 0, pnl.Width, pnl.height)
    End Select
    Sleep(10)
End Sub

private Sub animateToLeft
    Dim startOffset As Int = CustomListView1.sv.ScrollViewOffsetX
    Dim targetOffset As Int =  startOffset + panelWidth
    Dim stepSize As Float = (targetOffset - startOffset) / 10
    Do While startOffset < targetOffset
        startOffset = startOffset + stepSize
        If startOffset > targetOffset Then Exit
        CustomListView1.sv.ScrollViewOffsetX = startOffset
        Sleep(10)
        stepSize = Max(5, stepSize - 1)
    Loop
    CustomListView1.sv.ScrollViewOffsetX = targetOffset
End Sub

private Sub animateToRight
    Dim startOffset As Int = CustomListView1.sv.ScrollViewOffsetX
    Dim targetOffset As Int =  startOffset - panelWidth
    Dim stepSize As Float = (targetOffset - startOffset) / 10
    Do While startOffset > targetOffset
        startOffset = startOffset + stepSize
        If startOffset < targetOffset Then Exit
        CustomListView1.sv.ScrollViewOffsetX = startOffset
        Sleep(10)
        stepSize = Min(-5, stepSize - 1)
    Loop
    CustomListView1.sv.ScrollViewOffsetX = targetOffset
End Sub

View attachment 139835
Thank you. I will try
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I took it a little further.

The principle is that the CLV is loaded in a panel that is wider and flatter than the portrait screen, so that only part of it can be seen.
The scrolling is done programmatically based on directional swipes (there is an invisible touch panel on top of the screen).
The changes are animations that change the size of the image and position of the CLV. The steps start fast and slow down.

recording.gif


On the device it is a lot smoother.

The attached B4A project in B4XPages shows that it works well. I put in only one real picture, to save space. The other panels demonstrate
how it works. In your project they would be loaded with images, like panel 1.
 

Attachments

  • SlideShow.zip
    362.1 KB · Views: 94
Upvote 1

ykucuk

Well-Known Member
Licensed User
Longtime User
Hello William, thank you very much for your help. I need your help on that issues.

When I click on a panel, it often jumps to the next or previous panel. How can I prevent this from happening? If I could get a message box indicating which panel I'm on when I click on it, it would be sufficient.

Could you please assist me with these issues?
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
This approach wasn't meant for landscape mode. The panel in focus is constrained by the height of the screen.
How would you handle the off-focus panels?

Post your project as a .zip, and I'll take a look at what you've done.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Remember the principle. A CLV that is wider than the screen. For landscape that means that about 3 to 5 panels will be visible, depending on your images and the screen width. What do you want these extra panels to be and where?

Let's assume..
1. you want the image in focus to be in the center
2. you want the non-focus panels to be visible if possible
3. you want the size of these panels to be smaller depending on distance from the center
- to simulate a circular carousel

This requires a bit of additional work. I'll give it a go today.

Steps
1. compute the number of frames per screen
2. compute the frame width, so that the frame cutoff is pleasing (1/3 of frame visible or experiment)
3. compute the width of the partly hidden panel that's wider than the screen
4. load the CLV with images
5. on swipe event (from touch panel full screen overlay) animate CLV
6. during left/right animation, scale down the images progressively from the center

And hope that the speed of animation is still acceptable.
If not, the scaling animation effect may have to be abandoned.
Or replaced by varying opacity overlays.




carousScreen.png
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Here it is. It turns out that on most standard screen aspect ratios only three panels can be shown.
This version works with landscape and portrait. I have added a opacity screen for visible images out of focus.
There is no problem with animation speed.

carousel.gif
 

Attachments

  • carouselV2.zip
    362.6 KB · Views: 84
Upvote 0
Solution

ykucuk

Well-Known Member
Licensed User
Longtime User
Thats great. Thank you so much. Last question how can i get which panel clicked ? When i click its sliding.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
If you mean click on the left or right instead of a swipe, then..
You have to differentiate a swipe from a click.
Simply put a threshold on the swipe distance below which it is a click.

B4X:
Sub touchpnl_Touch(Action As Int, X As Float, Y As Float)
    Dim threshold As Float = frameWidth / 5   'or even smaller
    Select Action
        Case touchPanel.ACTION_DOWN
            startPointX = X
        Case touchPanel.ACTION_MOVE
        Case touchPanel.ACTION_UP
            If X > (startPointX + threshold) Then
                currentIndex = currentIndex - 1
                If currentIndex > 1 Then animateToRight Else currentIndex = currentIndex + 1
            Else If X < (startPointX - threshold) Then
                currentIndex = currentIndex + 1
                If currentIndex < CustomListView1.size - 2 Then animateToLeft Else currentIndex = currentIndex - 1
           Else
               'a click - use X to determine where on the screen
               'X could be right third of screen or center third or left third
            End If
    End Select
    Sleep(10)
End Sub

If you you have other questions, please mark this as solved and start a new thread.
 
Last edited:
Upvote 1

ykucuk

Well-Known Member
Licensed User
Longtime User
If you mean click on the left or right instead of a swipe, then..
You have to differentiate a swipe from a click.
Simply put a threshold on the swipe distance below which it is a click.

B4X:
Sub touchpnl_Touch(Action As Int, X As Float, Y As Float)
    Dim threshold As Float = frameWidth / 5   'or even smaller
    Select Action
        Case touchPanel.ACTION_DOWN
            startPointX = X
        Case touchPanel.ACTION_MOVE
        Case touchPanel.ACTION_UP
            If X > (startPointX + threshold) Then
                currentIndex = currentIndex - 1
                If currentIndex > 1 Then animateToRight Else currentIndex = currentIndex + 1
            Else If X < (startPointX - threshold) Then
                currentIndex = currentIndex + 1
                If currentIndex < CustomListView1.size - 2 Then animateToLeft Else currentIndex = currentIndex - 1
           Else
               'a click - use X to determine where on the screen
               'X could be right third of screen or center third or left third
            End If
    End Select
    Sleep(10)
End Sub

If you you have other questions, please mark this as solved and start a new thread.
Let me explain.

Imagine that all panels are button for different products. When user click on panel (bird image) i should show a message box about which product choosen.
 
Upvote 0
Top