B4A Library MSDynamicGridView Library

shashkiranr

Active Member
Licensed User
Longtime User
Hi @thedesolatesoul ,

Here is the below code. It is added in the layout creator of the ULV.

B4X:
Sub ULV_TYPE_Technologies_LayoutCreator(LayoutName As String, LayoutPanel As Panel)
    Log("*** tech "&LayoutName.SubString(17))
    Dim card As MSCardView
    card.Initialize("")
    card.MaxElevation = 4dip
    card.Elevation = 2dip
    card.Radius = 2dip
    LayoutPanel.AddView(card, 10dip, 0, LayoutPanel.Width-20dip, LayoutPanel.Height)
   
    Dim tech As Technologies_Content = List_Variables_Functions.Type_Technologies_List.Get(LayoutName.SubString(21))
   
    Dim lbltitle As Label
    lbltitle.Initialize("")
    lbltitle.color = Colors.Transparent
    lbltitle.textcolor = Colors.RGB(66,66,66)
    lbltitle.textsize = List_Variables_Functions.textsizeall
    lbltitle.Gravity =  Gravity.left
    lbltitle.Typeface = Typeface.DEFAULT_BOLD
    card.Panel.AddView(lbltitle, 5dip, 5dip, LayoutPanel.Width - 10dip, OriginalHeight)
    lbltitle.Height = StrUtil.MeasureMultilineTextHeight(lbltitle,tech.title)
    Dim r As Reflector
    r.Target = lbltitle
    r.RunMethod2("setMaxLines", 1, "java.lang.int")
    r.RunMethod2("setHorizontallyScrolling", False, "java.lang.boolean") 
   
        Dim GridPanel As Panel
        GridPanel.Initialize("")
        card.Panel.AddView(GridPanel,5dip,lbltitle.Height+5dip,card.Panel.Width,card.Panel.Height)
        Dim GridViewtech As MSDynamicGridView 
        Dim GridAdaptertech As MSDynamicAdapter 
        Dim NumCols As Int 
        NumCols  = Activity.Width/110dip
        GridViewtech.Initialize("GView")
        GridViewtech.NumColumns = NumCols
        GridViewtech.Selection = -1
        GridViewtech.EditModeEnabled = False
        GridAdaptertech.Initialize("GA",NumCols, 110dip,110dip)
        GridPanel.AddView(GridViewtech,0,0,GridPanel.Width,GridPanel.Height)
        GridViewtech.Adapter = GridAdaptertech.GetAdapter
        GridPanel.Tag = tech.title
       
        For i = 0 To tech.images.Length-1
            GridAdaptertech.Add(tech.title)
        Next

End Sub

Regards,
SK
 

thedesolatesoul

Expert
Licensed User
Longtime User
Thanks.
Just a few notes about this code.
Height of card = LayoutPanel.Height
Height of gridpanel = card.panel.height
Height of GridViewtech = gridpanel.Height
So if LayoutPanel.Height is known then we can find the height of GridViewTech. I cant remember in ULV if you have to provide the height of the layout, so LayoutPanel.Height will be known. So it may be possible to indirectly calculate the height of gridpanel.height.

I believe the issue arises because of the cardview panel is set to -1 i.e. FILL_PARENT so any views below it will probably not give you the correct height.

Currently I dont know of a way to get the height at runtime after its set to fill_parent or wrap_content.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi @thedesolatesoul ,

Yes you are right. I also tried to use wrap content so that the card view automatically adjusts after the gridview is added but it didnt work either.

Thank you for your kind attention.

Regards,
SK
 

thedesolatesoul

Expert
Licensed User
Longtime User
I'm still not convinced using a grid is the best idea, unless you know exactly how many items you have (as you cannot use scrolling).
For e.g. there each item is 110dipx110dip and NumCols = 100%x/110dip
So if you have NumItems images, your gridview height will be:
NumRows = Ceil(NumItems / NumCols)
GridHeight = NumRows * 110dip (This is the height of the grid required when there will be no scrolling and all items are visible)
 

jotaele

Member
Licensed User
Longtime User

I was looking your code of the example of the grid2.zip and, if I am not wrong, you must NO load the images in this event.

B4X:
Sub DA_GetLayout(Position As Int, ItemID As Long, ItemTag As String) As Panel
   Dim p As Panel
   p.Initialize("")
   Log("ItemTag: " & ItemTag)
   Dim iv As ImageView
   Dim bmp As Bitmap
   bmp.Initialize(File.DirAssets, ItemTag)
   iv.Initialize("iv")
   iv.Gravity = Gravity.Fill 'ajustar imagem
   iv.Bitmap = bmp

'   p.AddView(iv, 1dip, 1dip,(100%x/NumCols)-2dip,(100%x/NumCols)-2dip)
   p.AddView(iv, 1dip, 1dip,(Panel1.Width/NumCols)-2dip,(Panel1.Width/NumCols)-2dip)
   
   Return p
End Sub

The code can be more simple and faster. Only load the layout:

B4X:
   Dim p As Panel
   p.Initialize("")
   Dim iv As ImageView
   iv.Initialize("iv")
   iv.Gravity = Gravity.Fill 'ajustar imagem
   p.AddView(iv, 1dip, 1dip,(Panel1.Width/NumCols)-2dip,(Panel1.Width/NumCols)-2dip)
   Return p

End Sub

Correctme if I am wrong.
 

thedesolatesoul

Expert
Licensed User
Longtime User
I was looking your code of the example of the grid2.zip and, if I am not wrong, you must NO load the images in this event.
This is an interesting point.
If all of your images are the same then you can load it in GetLayout, if they are all different based on Item then you should load it in GetContent.
The way most recycleable views work is that they will reuse the layouts generated in GetLayout, if they cant find one, then they create a new one and call GetLayout. This means that if you only load the bitmaps in GetLayout sometimes you would see duplicates depending on how the device is handling the layouts.
Btw...thanks for your donation
 

jotaele

Member
Licensed User
Longtime User

Thanks for the explanation.
 

asales

Expert
Licensed User
Longtime User
Hi @thedesolatesoul

I want to make a grid with images and colored panels (without images) in same grid. See image0.

This is my code (B4A 5. See the example in attached):

B4X:
Sub GridImages
    DynamicGrid.Initialize("DG")
    DynamicAdapter.Initialize("DA", NumCols, pnlGrid.Width/NumCols, pnlGrid.Width/NumCols)
   
    DynamicGrid.NumColumns = NumCols
   
    DynamicGrid.EditModeEnabled = False 'No drag/drop
    DynamicGrid.WobbleInEditMode = False
   
    pnlGrid.AddView(DynamicGrid, 0, 0, pnlGrid.Width, pnlGrid.Height)
   
    GridItems.Initialize

    'LOAD IMAGES   
    For i = 0 To qtimg - 1
        Dim ItemString As String = i & ".jpg"
        GridItems.Add(ItemString)
        DynamicAdapter.Add(ItemString)       
    Next
   
    'CREATE PANELS
    For i = 0 To 9
        Dim ItemString As String = "[C:B]"
        GridItems.Add(ItemString)
        DynamicAdapter.Add(ItemString)
    Next   

    DynamicGrid.Adapter = DynamicAdapter.GetAdapter
End Sub   

Sub DA_GetLayout(Position As Int, ItemID As Long, ItemTag As String) As Panel
    Dim p As Panel
    p.Initialize("")

    If ItemTag.Contains("[C:B]") = False Then
        Dim iv As ImageView
        iv.Initialize("iv")
        iv.Gravity = Gravity.Fill
        p.AddView(iv, 1dip, 1dip,(pnlGrid.Width/NumCols)-2dip,(pnlGrid.Width/NumCols)-2dip)
    End If

    Return p
End Sub

Sub DA_GetContent(Position As Int, ItemID As Long, ItemTag As String, ContentPanel As Panel) As Panel

    'PANEL + IMAGEVIEW
    If ItemTag.Contains("[C:B]") = False Then
        Dim Bitmap1 As Bitmap
        Bitmap1.Initialize(File.DirAssets ,GridItems.Get(ItemID))   
       
        Dim iv1 As ImageView = ContentPanel.GetView(0)
        iv1.Bitmap = Bitmap1
    Else
        'ONLY COLORED PANEL
        If Position Mod 2 = 0 Then
            ContentPanel.Color = Colors.Green
        Else
            ContentPanel.Color = Colors.Yellow
        End If
    End If   

    Return ContentPanel
End Sub

I have this problems:
- the first 8 cells it's ok, but the others is not (the images is show again). See image1 and image2.
- if I scrolling the grid in certain point I get this error:
B4X:
main_da_getcontent (java line: 352)
java.lang.RuntimeException: Object should first be initialized (View).
    at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:50)
    at b4a.example.msgrid1.main._da_getcontent(main.java:352)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at com.maximussoft.gridviews.B4ADynamicGridAdapter.getView(B4ADynamicGridAdapter.java:66)
    at android.widget.AbsListView.obtainView(AbsListView.java:2240)
    at android.widget.GridView.makeAndAddView(GridView.java:1345)
    at android.widget.GridView.makeRow(GridView.java:345)
    at android.widget.GridView.fillUp(GridView.java:386)
    at android.widget.GridView.fillGap(GridView.java:262)
    at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5143)
    at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4254)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
    at android.view.Choreographer.doCallbacks(Choreographer.java:574)
    at android.view.Choreographer.doFrame(Choreographer.java:543)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5214)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:814)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:630)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: Object should first be initialized (View).

I tried, but I don't know how to make the app works.

Thanks in advance for any tip.

 

Attachments

  • msgrid1.zip
    317.3 KB · Views: 363

thedesolatesoul

Expert
Licensed User
Longtime User
Hi @AS2
Sorry for the delay in replying, (there will be more in the future)
I think I know what the problem is but Im having some issues with my device connecting to my PC so I cant test it out yet.
This is probably related to post #53, and this is something i havent tested.
As layouts are re-used, so GetLayout is not always called for everytime you scroll and the items cycle out. This means it is better to have the same layout for all the items, but in GetContent you can set the imageview visibility to false.
I'll see if i can post how to do it once i test it.
 

thedesolatesoul

Expert
Licensed User
Longtime User
Hey,
So I made some minimal changes to your project, hopefully you will understand how it goes.
Change1.
In DA_GetLayout we always create the full layout even the imageview. This is so that even though the grid items will look different they have to share the same layout.
Change2.
In DA_GetContent I moved the line:
Dim iv1 As ImageView = ContentPanel.GetView(0)
to the top, since we always have an imageview in the layout so we can always get it.
Change3.
If we only want to show the colored panel, then we can make iv1.Visible = False.
Change4.
This one I didnt anticipate, is a side effect of Change3. We need to set iv1.Visible = True in the other If branch. Otherwise the re-used layout will use the previously set properties when you scroll.

To summarize:
1. In DA_GetLayout you will want to build the full layout even if you dont use all of it (and we can hide the views we dont want in DA_GetContent).
2. In DA_GetContent try to be exhaustive i.e. set the properties in all the branches for completeness otherwise you might see 'leakage' of these properties into other items.

Thanks.
 

Attachments

  • msgrid1.2.zip
    317.3 KB · Views: 498
Cookies are required to use this site. You must accept them to continue using the site. Learn more…