Android Question Resize child panels within a ScrollView

DavidRa

New Member
Licensed User
I have a ScrollView for the main window of an app, and I have created a layout for the child items which is about 60dip high. When I init the app, I load a series of these layouts into panels, then add the panels to the ScrollView. In each case I have to explicitly set the top margin to be the appropriate height (for the Xth panel, (X-1) * 60dip) so that the panels appear to be in a list (this could be issue one in a long list of issues, so please be gentle).

When I tap on an item in the list, I would like to resize that panel - because I'd like to display more information. My intent is eventually to show and hide extra fields in the layout rather than trying to switch layouts for a particular panel. To that end I have the following handler:

B4X:
' Event handler for main activity panels
Sub Panel_Click (Sender as Object)
  Dim P as Panel : P = Sender
  ToastMessageShow("Resizing " & P.Tag)
  If (P.Height = 60dip) Then
    P.Height = 90dip
  Else
    P.Height = 60dip
  End If
End Sub
Tapping the panel does correctly show the Toast (debugging) message, but the panel height does not appear to change at all. Even if it ended up "behind" the next panel in the scrollview, I'd expect to see the bottom-aligned labels disappear or move. No exception appears in the LogCat output.

Assistance appreciated (though I cannot post the full project code until much later today - about 8 hours from timestamp of this post).
 

eurojam

Well-Known Member
Licensed User
and you should move the following panels down if you don't want to hide them. something like this:
B4X:
  Dim P As Panel : P = Sender
  ToastMessageShow("Resizing " & P.Tag, True)
  Dim m As Int
  If (P.Height = 60dip) Then
  P.Height = 90dip
   m = 30dip
  Else
  P.Height = 60dip
   m = (-1)*30dip   
   
  End If
  
If i < 5 Then '5 is the last panel for example
      For i = P.Tag+1 To 5 'number of panels
         Dim panelmove As Panel
         panelmove =  Scrollview1.Panel.GetView(i)
         panelmove.Top = panelmove.Top + m
      Next   
  End If
 

DavidRa

New Member
Licensed User
Thanks - I'll try both of these tonight (oh what a dreaded comment to make). It seems a bit of a kludge to have to manually update each panel's location, and I'm guessing that will also mean updating the panel height within the ScrollView.

Does a ListView make any of this ... easier? I should have asked - am I even using the right objects? Or is this just one of those things where XAML and flow layout just "got it right" and Android is a little bit more manual?
 

udg

Expert
Licensed User
If I understood you correctly, an option could be a distinct superimposed panel made up of the complete layout and showed on original sv panel tap. When done with the new panel, a tap on it will destroy it and the sv will come back in full view.
that way no resizing is necessary at all.

udg
 

DavidRa

New Member
Licensed User
OK I've tested adding P.BringToFront(). I do see a change in the value of P.Height, but the layout only alters by about 2dip (even if I triple the height), so I'm going to assume it's probably not the best approach. I could go for the super-imposed larger panel (nice idea BTW), but I think functionally I'd prefer to be able to have more than one item expanded, so I'm going to dig into CustomListView. Since I'm not exactly a pro developer (I'm an infrastructure guy) it's going to take a little while :)

Edit: It didn't take quite as long as I thought it might, but I converted to CustomListView and have successfully got the resizing to work (though the layout itself needs work it seems).

For those following along at home:
B4X:
Sub Panel_Click (Sender as Object)
  Dim P as Panel = Sender
  Dim iX as Int
  iX = clv.GetItemFromView(Sender)
  clv.RemoveAt(iX)
  P.RemoveView()                ' Otherwise, CRASH, this was not expected :)
  If P.Height = REGULAR Then    ' My kingdom for ternary expressions ...
    P.Height = EXPANDED         ' Constant
  Else
    P.Height = REGULAR          ' Constant
  End If
  clv.InsertAt(iX, P, P.Height, P.Tag)
End Sub
 
Last edited:

DavidRa

New Member
Licensed User
Right so I've been muddling through - but I can't get the newly inserted panels to reflow / resize their internal content. If I insert the panels at the small size (60dip) and resize up, the child elements all stay in position relative to the small size. If I insert at the large size, all the content always stays at the right locatons and sizes for THAT panel size.
I expect I'm missing something obvious.
Here's the code that inserts at a particular size:
B4X:
Sub FillMainScroll
  Dim X As Int
  Dim p As Panel
  Dim l As Label
  Dim tag As String
  For X = 0 To 14 ' This is a dummy loop, data is to be pulled from DB once the layouts work
    tag = "MyObj " & X
    p.Initialize("MyObj")
    clvMyObjs.Add(p, Constants.MyObj_PanelLarge, tag)
    p.Height = Constants.MyObj_PanelLarge
    p.LoadLayout("layoutMyObjItem")
    p.Tag = tag
    For Each V As View In p.GetAllViewsRecursive
      If V Is Label Then
        l = V
        If l.tag = "MyObjName" Then
          l.Text = "MyObj " & X
        End If
        If l.tag = "LastUpdate" Then l.Text = "Last Updated " & DateTime.GetDayOfMonth(DateTime.Now) & " " & DateTime_Months(DateTime.GetMonth(DateTime.Now)-1) & " " & DateTime.GetYear(DateTime.Now)
      End If
      If V Is Panel AND V.tag = "MyObjStatus" Then
        Select (True)
          Case (X Mod 3 = 0): V.Color = Constants.Color_Offline
          Case (X Mod 3 = 1): V.Color = Constants.Color_Online
          Case (X Mod 3 = 2): V.Color = Constants.Color_Partial
        End Select
      End If
    Next
  Next
End Sub
That code seems to work perfectly regardless of the size I specify for clvMyObjs.Add and for p.Height.
When a panel is tapped, this Sub runs:
B4X:
Sub MyObj_Click
  Dim P As Panel = Sender
  Dim ix As Int
  ix = clvMyObjs.GetItemFromView(P)
  clvMyObjs.RemoveAt(ix)
  P.RemoveView()
  If P.Height = Constants.MyObj_PanelSmall Then
    clvMyObjs.InsertAt(ix, P, Constants.MyObj_PanelLarge, P.Tag)
    P.Height = Constants.MyObj_PanelLarge
    P.SetLayout (P.Left, P.Top, P.Width, Constants.MyObj_PanelLarge)
    For Each V As View In P.GetAllViewsRecursive
      If V.Tag = "Services" Then V.Visible = True
    Next
  Else
    clvMyObjs.InsertAt(ix, P, Constants.MyObj_PanelSmall, P.Tag)
    P.Height = Constants.MyObj_PanelSmall
    P.SetLayout (P.Left, P.Top, P.Width, Constants.MyObj_PanelSmall)
    For Each V As View In P.GetAllViewsRecursive
      If V.Tag = "Services" Then V.Visible = False
    Next
  End If
End Sub
In case it's relevant, I've also converted my layout for the dynamic items to use Designer Script:
B4X:
'All variants script
AutoScaleAll
pnlMyObj.SetLeftAndRight(0%x, 100%x)
pnlMyObj.SetTopAndBottom(0%y, 100%y)
pnlStatusColour.SetLeftAndRight(0dip, 10dip)
pnlStatusColour.SetTopAndBottom(0%y, 100%y)
lblMyObjName.SetLeftAndRight (20dip, 100%x)
lblMyObjName.SetTopAndBottom (5dip, 5dip+lblMyObjName.Height)
lblLastUpdate.SetLeftAndRight (20dip, 100%x)
lblLastUpdate.SetTopAndBottom (100%y-5dip-lblLastUpdate.Height, 100%y-5dip)
lblServices.SetLeftAndRight (30dip, 100%x-10dip)
lblServices.SetTopAndBottom (5dip + lblMyObjName.Bottom, 100%y-lblLastUpdate.Top-5dip)
TL;DR: Resized panel doesn't adjust positions and sizes of child views.
 
Top