Android Question CLV in a 2 wide grid layout

Kevin Hartin

Active Member
Licensed User
I am building a Kiosk app for our Web site https://bookingmy.travel , which presents various tourism products on the web in a 2 or 3 wide grid format. For the kiosk app I want to settle on a 2 wide format and currently have a CLV working happily in a 1 wide format. Lazy loading is something I will be employing in the near future to better display large numbers of list items.

After seeing a Preoptimised CLV example https://www.b4x.com/android/forum/t...extension-for-xcustomlistview.115289/#content I have put two identical "Cards" across, but they share the same index when the CLV is selected.

Is it possible to use the CLV in a manner that loads the "cards" two across then down, as I'd like them to scroll together, but returns an index that allows me to identify which Product has been clicked?

Thanks,
Kev
 
Last edited:

Kevin Hartin

Active Member
Licensed User
Check this: https://www.b4x.com/android/forum/threads/double-column-customlistview.115954/#post-724715

Don't use PCLV unless you must (have a list with 10k+ items).
That works well for populating the two CLVs with alternating records of the SQL query, however the scrolling is throwing an error as follows;

ERROR:
[I][B]clvProducts1_ScrollChanged:46[/B][/I]
[B][I]new movement
CLVs.Size[/I][/B][I][B]:2[/B][/I]
Error occurred on line: 481 (ConsumerPage)
java.lang.NullPointerException
    at com.bookingmy.travel.consumer.consumerpage._handlescrollchanged(consumerpage.java:783)
    at com.bookingmy.travel.consumer.consumerpage._clvproducts1_scrollchanged(consumerpage.java:732)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:509)
    at anywheresoftware.b4a.keywords.Common.CallSubNew2(Common.java:464)
    at b4j.example.customlistview._scrollhandler(customlistview.java:981)
    at b4j.example.customlistview._sv_vscrollchanged(customlistview.java:1047)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.BA$1.run(BA.java:234)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)

The relevent lines of code are as follows;
Code:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private clvProducts1 As CustomListView
    Private clvProducts2 As CustomListView
    Private CLVs As List
    Type LastMovedType (CLV As CustomListView, Time As Long)
    Private LastMoved As LastMovedType
End Sub

Public Sub Initialize As Object
    LastMoved.Initialize
    Return Me
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    CLVs = Array(clvProducts1,clvProducts2)
    Root.LoadLayout("Consumer2")
End Sub

Sub clvProducts1_ScrollChanged (Offset As Int)
    [B][I]Log("clvProducts1_ScrollChanged:"&Offset)[/I][/B]
    HandleScrollChanged(Sender, Offset)
End Sub

Sub clvProducts2_ScrollChanged (Offset As Int)
    Log("clvProducts2_ScrollChanged:"&Offset)
    HandleScrollChanged(Sender, Offset)
End Sub

Sub HandleScrollChanged (CLV As CustomListView, offset As Int)
    If LastMoved.Time + 100 < DateTime.Now Then
        [I][B]Log("new movement")[/B][/I]
[B][I]        [/I][/B]LastMoved.Time = DateTime.Now
        LastMoved.CLV = CLV
    Else if LastMoved.CLV <> CLV Then
        Log("different CLV")
        Return
    End If
    For Each c As CustomListView In CLVs
        [I][B]Log("[I][B]CLVs.Size:"&[I][B]CLVs.Size[/B][/I][/B][/I])[/B][/I]
[B][I]       [/I][/B] If c <> LastMoved.CLV Then
            [U][B]c.sv.ScrollViewOffsetY = offset[/B][/U]
        End If
    Next
End Sub

The error is thrown at the line c.sv.ScrollViewOffsetY = offset which seems to have all sorts of issues with the sv as when I try to log the Tag of the CLV using sv.Tag it throws a similar error.

FYI, I am using B4J to prototype my latest changes before porting it to B4A.

Thanks,
Kev
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
Based on Erel's answer, you are better off making a small project and uploading it, especially when you post a lot of code that is hard to follow and reference layouts without knowing what the layouts contain.
Slightly off topic: instead of 2 xCLVs have you considered one customlistview with 2 columns since the scrolling is synchronous. Instead of using the item click, you use a label or image click invoking the Sender in a given item. Based on which view was clicked, you do your thing. Here is an example:
B4X:
Sub lbl_click 'all 2 labels in each row hold the bitmap names have lbl as event name in designer
     Dim v As Label=Sender
     MyPictureName=v.Text       'MyPictureName is a public variable
    ' Here Start an Activity or B4XPage to display an image or something
 End Sub
 
Upvote 0
Top