Android Tutorial Android SlidingPanels - Simple way to create sliding layouts

This is an old tutorial. There are now simpler and better ways to achieve this effect.

For example: https://www.b4x.com/android/forum/threads/tabstripviewpager-better-viewpager.63975/

Sliding layouts are cool.

Using the Animation library it is not difficult to animate single views and panels that hold other views.
The following code module and example project makes it even simpler to create a layout that is made of a number of panels. Whenever the current visible panel is changed, the current panel slides out and the new panel slides in.
As Panels can load layout files, you can create complex layouts by loading a layout file to each panel.

slidingpanels_1.png


The project is made of two components. The Main activity and the SlidingPanels code module.
You should add the SlidingPanels code module to your project and add a reference to the Animation library.

The main activity code is commented and explains the several integration points required.

Animations look much better on real devices than on the slow emulator.
Even if you are not interested in sliding layouts it is recommended to go over the code. It demonstrates the power of custom types which enable you to easily group many objects.
As code modules cannot hold references to Activity objects (like views), the calling activity passes the type with all the required data each time it calls a method (passing the data is done by passing a single pointer, there is no overhead here).

Questions and comments are always welcomed.
 

Attachments

  • SlidingPanels.zip
    6.9 KB · Views: 9,839
Last edited:

isr

Member
Licensed User
Longtime User
Please ignore my post above. I've overcome the compiling error and am making progress on modifying the SlidingPanels code for my purpose. Thank you, Erel, for this great resource.
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
I am looking for a help to know how to implement the sliding panels in a diffent way.

My app have 3 main panels that are parents for all other controls i need

Panel 1 Panel 2
(left) (Right)

[ Panel 3 (botton) ]

I dont want to use the gesture to swap between the panel, I need to control that programatically. I am already using the AHViewPager to change the whole screen above to another panels.

Those 3 panels have buttons, with functions that are based on the context of the operation (it is a POS software). So if you click on the button i need to change the Panel 3 panel to other panel with other buttons (i know i could change the buttons instead, however i want to slide effect to make pretty)

Then in the panel 3 i can click on a button that can change panel 1 or panel 2 to another panel using the sliding style.

This can happen to any of the panels, I have always another possible panel that can be used in place.

I wanted to somehow give to the slidingpanel code the parent panel and the set of panels that needs to be swapped by sliding it.

Can someone give me a orientation on how to achieve this?

Many thanks,

Eduardo
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
Thanks to reply,

OK, but the code seems to always put the panels on the right most position of the screen to make the sliding. And i need that the animation be on the boundary of each of the 3 panels that i have. What i need to do to limit the efect to a region of the screen, that will correspond to these 3 panels.

Not sure i am clear or not, but these 3 panel are regions of screen for me. Each one containing controls. Those are like placeholders. Then I need to switch panels to change those controls, but i want to do this switching by sliding effect.
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
Erel,

After some hours to understand I am geting closer to what I want.

I have changed the Sliding demo and transformed to a class. The touch event is not handled.

B4X:
'Class module
Sub Class_Globals
   Type SlidingData (firstTime As Boolean, currentPanel As Int, Panels() As Panel, LeftAnimations() As Animation, RightAnimations() As Animation, targetPanel As Int)
   Private FtmrAnimation As Timer
   Private Fsd As SlidingData
   Private FSlidingDuration As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize (PlaceHolder As Panel, Panels() As Panel, SlidingDuration As Int)
   Fsd.Initialize
   Fsd.Panels = Panels
   
   For i = 0 To Fsd.Panels.Length - 1
      PlaceHolder.AddView(Fsd.Panels(i), PlaceHolder.Left, PlaceHolder.Top, PlaceHolder.Width, PlaceHolder.Height)
   Next
   
   FSlidingDuration = SlidingDuration
   FtmrAnimation.Initialize("tmrAnimation", 2)
   Dim a(2) As Animation
   Fsd.LeftAnimations = a
   Dim a(2) As Animation
   Fsd.RightAnimations = a
   'Initialize the animation objects. We need two objects for each direction as both the current panel and the new panel are animated.
   For i = 0 To 1
      Fsd.leftAnimations(i).InitializeTranslate("animation" & i, 0, 0, -100%x, 0)
      Fsd.leftAnimations(i).Duration = FSlidingDuration
      Fsd.rightAnimations(i).InitializeTranslate("animation" & i, 0, 0, 100%x, 0)
      Fsd.rightAnimations(i).Duration = FSlidingDuration
   Next
   For i = 0 To Fsd.Panels.Length - 1
      Fsd.Panels(i).Left = 100%x 'Move the panels right of the screen
   Next
   Fsd.firstTime = True
End Sub

Sub ChangePanel(left As Boolean)
   If left Then         
      If Fsd.firstTime = False Then 'remove current panel if such exists (it will not be the case on the first call).
         Fsd.leftAnimations(0).Start(Fsd.panels(Fsd.currentPanel)) 'Animate current panel and move it out
      Else
         Fsd.firstTime = False
      End If
      Fsd.leftAnimations(1).Start(Fsd.panels((Fsd.currentPanel + 1) Mod Fsd.Panels.Length)) 'Animate new panel
      Fsd.currentPanel = (Fsd.currentPanel + 1) Mod Fsd.Panels.Length
   Else
      Dim leftPanel As Int
      leftPanel = (Fsd.currentPanel + Fsd.Panels.Length - 1) Mod Fsd.Panels.Length
      Fsd.panels(leftPanel).left = -100%x
      Fsd.rightAnimations(0).Start(Fsd.panels(Fsd.currentPanel))
      Fsd.rightAnimations(1).Start(Fsd.panels(leftPanel))
      Fsd.currentPanel = leftPanel
   End If
End Sub

Sub AnimationEnd
   Fsd.panels(Fsd.currentPanel).Left = 0 'Set the position of the new panel
   For i = 0 To Fsd.panels.Length - 1
      If i <> Fsd.currentPanel Then Fsd.panels(i).Left = 100%x 'Move all other panels right of the screen.
   Next
End Sub

'JumpToPanel can be used to navigate to a different panel which is not adjacent to the current one.
Sub JumpToPanel (Target As Int)
   Fsd.targetPanel = Target
   For i = 0 To 1
      Fsd.leftAnimations(i).Duration = FSlidingDuration / 2
      Fsd.rightAnimations(i).Duration = FSlidingDuration / 2
   Next
   ContinueJumping
End Sub

Private Sub Animation1_AnimationEnd
   'This event is raised when the animation finishes. You should call SlidingPanels.AnimationEnd from this sub.
   AnimationEnd
   If Fsd.targetPanel >= 0 Then 
      FtmrAnimation.Enabled = True
      Return 'we are still animating...
   End If
End Sub

Private Sub tmrAnimation_Tick
   FtmrAnimation.Enabled = False
   ContinueJumping
End Sub
Private Sub ContinueJumping
   If Fsd.targetPanel < 0 OR Fsd.targetPanel = Fsd.currentPanel Then 
      Fsd.targetPanel = -1
      Animation1_AnimationEnd
      For i = 0 To 1
         Fsd.leftAnimations(i).Duration = FSlidingDuration
         Fsd.rightAnimations(i).Duration = FSlidingDuration
      Next
      Return
   End If
   ChangePanel(Fsd.targetPanel > Fsd.currentPanel)
End Sub

From Main using the code below. I am not showing the code that load the layout to each panel. I am just changing the color of the panel.
B4X:
Sub Globals
   Dim Panels(2) As Panel
   Dim sp As ySlidingPanels
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Panels(0).Initialize("")
   Panels(0).Color = Colors.Gray
   Panels(1).Initialize("")
   Panels(1).Color = Colors.Yellow
   sp.Initialize(Activity, PanelNumPad, Panels, 300)

from main I call:

sp.ChangePanel(True)

when needed to change the panels, in this case going to the left.

With these changes I can create a slidingpanel class for each placeholder (panels that i use to define regions on the screen) and call when needed based on the context. It makes the layout very flexible. You will see that not much was changed in the code. Just put all together and changed the initialize.

the remaining issue is that the first run of this code there is a setup of the panels positioning and this is displayed, looking strange. So probably I will make the panel.visible=false and after the setup bring it visible again, after that it works fine.
 

BasicBert

Member
Licensed User
Longtime User
I love the sliding panels code, but it is sometimes difficult to understand.
I have managed to incorporate the democode into my own project, and it's working fine now.
Most of the time I am using the JumpToPanel() sub which jumps to the selected panel.
It works fine also, but when jumping from e.g. panel(0) to panel(3) with JumpToPanel(3), it slides from panel(0), to panel(1), then to panel(2) and finally to panel(3) and stops.
I understand that this was designed to work like that and it is surely a usefull and pretty way in many apps. But...
I would like to change from the current panel(0) directly to panel(3) (or any other panel I select) so sliding out panel(0) and sliding in panel(3) in the above example.

Please, can you tell me how I can get this to work this way?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
The simplest solution is to change the duration and make the jumping faster:
B4X:
Sub JumpToPanel (Target As Int)
   sd.targetPanel = Target
   For i = 0 To 1
      sd.leftAnimations(i).Duration = SlidingDuration / 2 'change to a few milliseconds instead
      sd.rightAnimations(i).Duration = SlidingDuration / 2
   Next
   ContinueJumping
End Sub
 

BasicBert

Member
Licensed User
Longtime User
Erel,

thanks for your reply.
I'll see if I can do something like this.
It means that I will have to jump fast to one panel before the target and then jump in "normal" speed to the target.
I'll study a bit on this.
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
Hi there,

Please, I wonder if someone could help me with this:

I am using the sliding panels the way it is, switching between panels.

But I am need something different. I want to have each "screen" of the application in different panel, that is fine but when that panel is set to be the active panel for the user it can be bigger in width than the screen, like 3 or 4 times wider. Then using the sliding to move continuously from one side to the other of this panel, the user can stop any point. And the app also could set positions to show.

My idea is to organize data input, many fields, like in window phone 8 in a continuous panel and make easy for the user to navigate on the form.

I was thinking on the scroll view and the horizontal bar, but i am afraid of adding such control since I will have a lot of other controls and effects on top of it and not sure how it will behave with the events in the future.

The other option could be the animation, if I understood it right.
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
I have created a "infinitepanel" class (could not find better name) to have a big width panel that i want to slide.

I am getting the touch event and based on an example from Erel, messuring the start of the touch and actual to see which direction, and using the FParent.ACTION_MOVE action.

What i am doing is to change the .Left property of the panel

B4X:
Sub OnPanel_Touch (Action As Int, X As Float, Y As Float) As Boolean 'Return True to consume the event
    Select Action
        Case FParent.ACTION_DOWN
            FStartX = X
        Case FParent.ACTION_UP
            If Abs(X - FStartX) > cMOVEMENT_THRESHOLD Then
                Swipe(X < FStartX)
            End If
      Case FParent.ACTION_MOVE
            If Abs(X - FStartX) > cMOVEMENT_THRESHOLD Then
            End If
         If X < FStartX Then
            FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left - 10dip
         Else
            FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left + 10dip
         End If
    End Select
    Return True        
End Sub

it comes some questions:

1 - it slides, with that 10dip it shakes a little but works... what is the difference on changing the .left property and using animation? I see the same effect happening: the panel moves and all its children. What is the real difference?

2 - how can i make the moving be more fast, since sliding on my code goes always in the same steps, it would be nice to have that keep rolling effect when it is slides fast. I have no idea right now where to start

If somone has any ideas it would be much appreciated!

Many Thanks

Eduardo Elias
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
I have improved the code above:

B4X:
Private Sub OnPanel_Touch (Action As Int, X As Float, Y As Float) As Boolean 'Return True to consume the event
    Select Action
        Case FParent.ACTION_DOWN
            FStartX = X
         FTimer.Enabled = False
        Case FParent.ACTION_UP
            If Abs(X - FStartX) > cMOVEMENT_THRESHOLD Then
                Swipe(X < FStartX)
            End If
      Case FParent.ACTION_MOVE
            If Abs(X - FStartX) > cMOVEMENT_THRESHOLD Then
            End If
         If X < FStartX Then
            FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left - 10dip
         Else
            FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left + 10dip
         End If
    End Select
    Return True        
End Sub

Private Sub Swipe(Left As Boolean)
   FSlideLeft = Left
   FTimer.Enabled = True
End Sub
      
Private Sub Timer_Tick
   If FSlideLeft Then
      FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left - 5dip
   Else
      FCurrentPanel.Panel.Left = FCurrentPanel.Panel.Left + 5dip
   End If
End Sub

and added a timer, it is starting to look good.

Is there a problem using this way?

My problems now are:

- moving not shake, maybe reducing the 10dpi?
- the automatic stop of the timer after some ms. What i see commonly is a gradually stop
- any problems using this way, any impact over overall android? I am testing in android 4 in a tablet and works nice.

Thanks!

Eduardo Elias
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
What is the purpose of the Timer?

To generate the events to move the panel x steps to the left, making the sliding effect....

I know there is the animate lib to do that. But i was tempted to this way and worked nicelly, however i do not understand the problems. I was not aware of the fact left and right coordinantes of the panels could be negative and panels can be much bigger then the view area in android. So I tested and learned from that.

Is there a potential problem of using a timer to simulate the same effect of animate library?

Anyways I could not reproduce the same behavior when you slide quickly with the finger (swipe in english?) over the view, like in the listview or scroll view and have that effect of keep going until reduces speed and stop.

The result of this work should like the image attached. Where we see that the application is based on a panel that is wider that the screen and moves from one side to other. However I will use a list of pages like that.

Eduardo
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
here is the image i mentioned the last post
 

Attachments

  • windows8screen.jpg
    windows8screen.jpg
    70.4 KB · Views: 481

EduardoElias

Well-Known Member
Licensed User
Longtime User
You can use HorizontalScrollView to create such UI.

It is funny, I was in my own crazy virtual mind travel for this... and a solution is already provided... thank you. this is the cost of learning.
 

roarnold

Active Member
Licensed User
Longtime User
Sliding Panels

Erel,

I am having a problem following the code. Anyway I have five files
that I would like to present, one in each panel.
Can you point out where I accomplish this. I tried adding panels via
designer but have no way to assign the file .jpg
to them. I will remove these panels as I assume your code builds them.
I need to understand where the .jpg files
connect to the panels in your code.

Appreciate your help in advance.
Ron
 

roarnold

Active Member
Licensed User
Longtime User
Erel,

So the code does not create the panels in the code presently? I have the jpg files in the file list and assume I can reference them from Dir Assets.

I think I am missing the connection piece meaning how to get the info into the panels, if possible in your code. I am trying to not utilize designer if possible.

Thanks,
Ron
 
Top