B4A Library [Lib] UltimateListView

I've been working on this project for a long time and I'm very proud to release the version 4 today.

The UltimateListView is, as its pompous name says, THE ListView.

  • It can handle very long lists. This is a screenshot of a list with 245813 items, all different:

    verylonglist.jpg


  • It can mix different layouts (and they can be changed dynamically). You can use it as an expandable ListView:

    layouts.jpg


  • It has a low memory footprint and is very fast (this report comes from the Performance demo where the list has to display 128901 distinct words read from a database and the used device is a Huawei Honor single core 1.4 Ghz):

    performance.png


  • It can scroll in both directions thanks to its swipe detector:

    tables.jpg


  • The swipe detector can also be used to implement a swipe-to-dismiss or a swipe-to-reveal:

    swipedetector.png
  • You can easily add editors to your table to change its content:

    celledit.jpg


  • You can animate the items when they are added, removed, replaced or when the list is scrolled (with your own custom animation):

    animationclap.png


  • It can stack items from the bottom:

    stackfrombottom.png


  • It supports drag & drop operations (internal & external):

    dragndrop.png


  • You can synchronize lists with different item heights:

    grid.jpg
The examples will show you how to implement a Pull-to-Refresh, create sticky headers or combine several lists to make a wheel. One of the examples is an improved version of my File Explorer class.

All texts and images can be loaded asynchronously (from Internet, from a database or from a local folder), so you can scroll even if the data are not fully loaded.

The list has its own state manager.

Since September 2018, ULV is available for free. You can still donate for it if you wish.
To send the money, just click on the Donate button below (the amount to enter is in euros):


Note that UltimateListView is not a wrapper around the work of someone else. It is 100% my own code and it is based upon the standard Java ListView of Android.

The UltimateListView does not work with Android versions < 2. It cannot work with B4J or B4i.

Current version: 4.50

DOWNLOAD HERE:
 
Last edited:

itgirl

Active Member
Licensed User
Longtime User
well this is all the code relevant to [pull to refresh] implement
B4X:
Sub ClearListViewActions
If ULV.IsInitialized = True Then
           ULV.ClearContent
           ULV.ClearMemoryCache
           ULV.CloseCache(True)
           ULV.ReopenDiskCache
End If

           Videos_Counter = 0
           SortedList.Initialize
           SortedList.Clear
           imagesforpager.Clear

If vp.IsInitialized = True Then
vp.ClearDiskCache
vp.ClearMemoryCache
End If
End Sub

Sub ULV_Scrolled (FirstVisibleItem As Int, VisibleItemCount As Int, TotalItemCount As Int, IsAtTop As Boolean, IsAtBottom As Boolean)
    'The scrollbar is invisible when the refresher item is visible
    If FirstVisibleItem = 0 Then
        If ScrollbarStyle <> ULV.SCROLLBAR_INVISIBLE Then
            ScrollbarStyle = ULV.SCROLLBAR_INVISIBLE
            ULV.SetScrollbarStyle(ScrollbarStyle)
        End If
    Else If ScrollbarStyle <> ULV.SCROLLBAR_OUTSIDE_OVERLAY Then
        ScrollbarStyle = ULV.SCROLLBAR_OUTSIDE_OVERLAY
        ULV.SetScrollbarStyle(ScrollbarStyle)
    End If

End Sub


Sub Refresher_LayoutCreator(LayoutName As String, LayoutPanel As Panel)
    'The "refresher" item contains an imageview, a progress bar and a label
    'It displays an arrow when the item is revealed and a spinning circle while loading
    Dim IV As ImageView
    IV.Initialize("")
    LayoutPanel.AddView(IV, 10dip, 0, 50dip, 50dip)

    Dim prb As ProgressBar
    prb.Initialize("")
    prb.Indeterminate = True
    LayoutPanel.AddView(prb, IV.Left, IV.Top, IV.Width, IV.Height)


       
    Dim lbl As Label
    lbl.Initialize("")
    lbl.Color = Colors.Transparent
    lbl.TextColor = Labels_Color
    lbl.TextSize = 14
    lbl.Gravity = Gravity.CENTER_HORIZONTAL + Gravity.top
    LayoutPanel.AddView(lbl, 0, 0, LayoutPanel.Width, 28dip)
   
End Sub
Sub Refresher_ContentFiller(LayoutName As String, LayoutPanel As Panel)
    'Repositions the views
    For Each V As View In LayoutPanel
        If LayoutPanel.Height < V.Height Then
            V.Top = LayoutPanel.Height - V.Height
        Else
            V.Top = (LayoutPanel.Height - V.Height) / 2
        End If
    Next

    'Updates the icon and the text
    Dim IV As ImageView = LayoutPanel.GetView(0)
    Dim prb As ProgressBar = LayoutPanel.GetView(1)
    Dim lbl As Label = LayoutPanel.GetView(2)
    If RefreshState = RSTATE_PULLING Then
        IV.SetBackgroundImage(ArrowDown)
        IV.Gravity = Gravity.FILL
        prb.Visible = False
        lbl.Text = GetLang.GetResourceString("pulldown1")
    Else If RefreshState = RSTATE_READY Then
        IV.SetBackgroundImage(ArrowUp)
        IV.Gravity = Gravity.FILL
        prb.Visible = False
        lbl.Text = GetLang.GetResourceString("pulldown2")
    Else
        IV.Background = Null
        prb.Visible = True
        lbl.Text = GetLang.GetResourceString("pulldown3")
    End If
End Sub
Sub ULV_Touch(Action As Int, X As Int, Y As Int, MotionEvent As Object) As Boolean

    If RefreshState <> RSTATE_WAITING Then
        'The scrolling is blocked until the user releases the list or the operation is cancelled
        If Action = Activity.ACTION_MOVE Then
            Return True
        Else
            If RefreshState = RSTATE_PULLING OR Action = 3 Then
                'No refresh
                UpdateRefreshItem(0, RSTATE_WAITING)
                ULV.JumpTo(1, False)
            Else
                'Starts loading (the list is disabled)
                ULV.Enabled = False
                UpdateRefreshItem(75dip, RSTATE_LOADING)
                LoadingTimer.Enabled = True

            End If
        End If
    End If
   

    Return False
   
End Sub
Sub UpdateRefreshItem(Height As Int, NewRefreshState As Int)
    'Sets the new refresh state
    RefreshState = NewRefreshState

    If ULV.GetFirstVisiblePosition = 0 Then
        Try
            'Gets the first visible panel and changes its height
            Dim jULV As JavaObject = ULV
            Dim jPnl As JavaObject = jULV.RunMethod("getChildAt", Array As Object(0))
            Dim jLP As JavaObject = jPnl.RunMethod("getLayoutParams", Null)
            jLP.SetField("height", Height)
            jPnl.RunMethod("setLayoutParams", Array As Object(jLP))

            'Repositions the views and updates the text
            Refresher_ContentFiller("", jPnl)
        Catch
            Log(LastException.Message)
        End Try
    End If
End Sub
Sub LoadingTimer_Tick
    'Stops the timer
    LoadingTimer.Enabled = False
    ClearListViewActions
    'Adds a few items at the beginning
    Dim GetUrl As HttpJob
    GetUrl.Initialize("GetUrl", Me)
    GetUrl.Download(CurrentUrl)
    GetUrl.GetRequest .Timeout  = 30000

    'Resets the list
    UpdateRefreshItem(0, RSTATE_WAITING)
    ULV.JumpTo(1, False)
End Sub

and this is how in Initializes ULV

B4X:
    'Initializes the BitmapProcessor class
    BP.Initialize
    BP.MinTiltAngle = -25 'The thumbnails will have a random rotation
    BP.MaxTiltAngle = 25  'angle between -25 and +25 degrees

    'Initializes the ULV
    ULV.Initialize(100, 50, "", "ULV")
    ULV.DividerHeight = 0
    ULV.FastScroller(False)
    ULV.SetPadding(0, 0, 0, 0)
    ULV.NumberOfAsyncLoaders = 2
    ULV.SetStyle(ULV.STYLE_HOLO_LIGHT)
    ULV.OverscrollMaximum = 160dip
    ULV.AddLayout("Refresher", "Refresher_LayoutCreator", "", 0, False)
    ULV.SetLoadImageCallbacks("Bmp_Placeholder", "", "Bmp_PostLoad", "Bmp_LoadingError")
    ULV.AddLayout("Bitmap2Lines", "Item_LayoutCreator", "Item_Filler",100dip, False)
    ULV.AddLayout("ExtendedItem", "Item_LayoutCreator", "Item_Filler", 100%x + 70dip, False)
    ULV.AddLayout("SiteSeparator", "SiteSeparator_LayoutCreator", "SiteSeparator_Filler", 35dip, False)
    Activ.AddView(ULV, 0, 0, 100%x, Activ.Height)
    Animator.Initialize(ULV,"Animator")
    'AlphaAnimator.Initialize(ULV, "AlphaAnimator")
    ULV.AnimationCleaner = True
    ULV.Color = ULVcolors
    Dim Image44 As Bitmap
        Image44.Initialize(File.DirAssets,"MyBG.png")
        Image44 = LoadBitmapSample(File.DirAssets,"MyBG.png",100%x,100%y)
    ULV.SetBackgroundImage(Image44,Gravity.CENTER)
   
    'Initializes the refresh state
    RefreshState = RSTATE_WAITING
    'Loads the status icons
    ArrowDown.Initialize(File.DirAssets, "arrow_down.png")
    ArrowUp.Initialize(File.DirAssets, "arrow_up.png")
    LoadingTimer.Initialize("LoadingTimer", 2000)
 

Informatix

Expert
Licensed User
Longtime User
well this is all the code relevant to [pull to refresh] implement
B4X:
Sub ClearListViewActions
If ULV.IsInitialized = True Then
           ULV.ClearContent
           ULV.ClearMemoryCache
           ULV.CloseCache(True)
           ULV.ReopenDiskCache
End If

           Videos_Counter = 0
           SortedList.Initialize
           SortedList.Clear
           imagesforpager.Clear

If vp.IsInitialized = True Then
vp.ClearDiskCache
vp.ClearMemoryCache
End If
End Sub

Sub ULV_Scrolled (FirstVisibleItem As Int, VisibleItemCount As Int, TotalItemCount As Int, IsAtTop As Boolean, IsAtBottom As Boolean)
    'The scrollbar is invisible when the refresher item is visible
    If FirstVisibleItem = 0 Then
        If ScrollbarStyle <> ULV.SCROLLBAR_INVISIBLE Then
            ScrollbarStyle = ULV.SCROLLBAR_INVISIBLE
            ULV.SetScrollbarStyle(ScrollbarStyle)
        End If
    Else If ScrollbarStyle <> ULV.SCROLLBAR_OUTSIDE_OVERLAY Then
        ScrollbarStyle = ULV.SCROLLBAR_OUTSIDE_OVERLAY
        ULV.SetScrollbarStyle(ScrollbarStyle)
    End If

End Sub


Sub Refresher_LayoutCreator(LayoutName As String, LayoutPanel As Panel)
    'The "refresher" item contains an imageview, a progress bar and a label
    'It displays an arrow when the item is revealed and a spinning circle while loading
    Dim IV As ImageView
    IV.Initialize("")
    LayoutPanel.AddView(IV, 10dip, 0, 50dip, 50dip)

    Dim prb As ProgressBar
    prb.Initialize("")
    prb.Indeterminate = True
    LayoutPanel.AddView(prb, IV.Left, IV.Top, IV.Width, IV.Height)


      
    Dim lbl As Label
    lbl.Initialize("")
    lbl.Color = Colors.Transparent
    lbl.TextColor = Labels_Color
    lbl.TextSize = 14
    lbl.Gravity = Gravity.CENTER_HORIZONTAL + Gravity.top
    LayoutPanel.AddView(lbl, 0, 0, LayoutPanel.Width, 28dip)
  
End Sub
Sub Refresher_ContentFiller(LayoutName As String, LayoutPanel As Panel)
    'Repositions the views
    For Each V As View In LayoutPanel
        If LayoutPanel.Height < V.Height Then
            V.Top = LayoutPanel.Height - V.Height
        Else
            V.Top = (LayoutPanel.Height - V.Height) / 2
        End If
    Next

    'Updates the icon and the text
    Dim IV As ImageView = LayoutPanel.GetView(0)
    Dim prb As ProgressBar = LayoutPanel.GetView(1)
    Dim lbl As Label = LayoutPanel.GetView(2)
    If RefreshState = RSTATE_PULLING Then
        IV.SetBackgroundImage(ArrowDown)
        IV.Gravity = Gravity.FILL
        prb.Visible = False
        lbl.Text = GetLang.GetResourceString("pulldown1")
    Else If RefreshState = RSTATE_READY Then
        IV.SetBackgroundImage(ArrowUp)
        IV.Gravity = Gravity.FILL
        prb.Visible = False
        lbl.Text = GetLang.GetResourceString("pulldown2")
    Else
        IV.Background = Null
        prb.Visible = True
        lbl.Text = GetLang.GetResourceString("pulldown3")
    End If
End Sub
Sub ULV_Touch(Action As Int, X As Int, Y As Int, MotionEvent As Object) As Boolean

    If RefreshState <> RSTATE_WAITING Then
        'The scrolling is blocked until the user releases the list or the operation is cancelled
        If Action = Activity.ACTION_MOVE Then
            Return True
        Else
            If RefreshState = RSTATE_PULLING OR Action = 3 Then
                'No refresh
                UpdateRefreshItem(0, RSTATE_WAITING)
                ULV.JumpTo(1, False)
            Else
                'Starts loading (the list is disabled)
                ULV.Enabled = False
                UpdateRefreshItem(75dip, RSTATE_LOADING)
                LoadingTimer.Enabled = True

            End If
        End If
    End If
  

    Return False
  
End Sub
Sub UpdateRefreshItem(Height As Int, NewRefreshState As Int)
    'Sets the new refresh state
    RefreshState = NewRefreshState

    If ULV.GetFirstVisiblePosition = 0 Then
        Try
            'Gets the first visible panel and changes its height
            Dim jULV As JavaObject = ULV
            Dim jPnl As JavaObject = jULV.RunMethod("getChildAt", Array As Object(0))
            Dim jLP As JavaObject = jPnl.RunMethod("getLayoutParams", Null)
            jLP.SetField("height", Height)
            jPnl.RunMethod("setLayoutParams", Array As Object(jLP))

            'Repositions the views and updates the text
            Refresher_ContentFiller("", jPnl)
        Catch
            Log(LastException.Message)
        End Try
    End If
End Sub
Sub LoadingTimer_Tick
    'Stops the timer
    LoadingTimer.Enabled = False
    ClearListViewActions
    'Adds a few items at the beginning
    Dim GetUrl As HttpJob
    GetUrl.Initialize("GetUrl", Me)
    GetUrl.Download(CurrentUrl)
    GetUrl.GetRequest .Timeout  = 30000

    'Resets the list
    UpdateRefreshItem(0, RSTATE_WAITING)
    ULV.JumpTo(1, False)
End Sub

and this is how in Initializes ULV

B4X:
    'Initializes the BitmapProcessor class
    BP.Initialize
    BP.MinTiltAngle = -25 'The thumbnails will have a random rotation
    BP.MaxTiltAngle = 25  'angle between -25 and +25 degrees

    'Initializes the ULV
    ULV.Initialize(100, 50, "", "ULV")
    ULV.DividerHeight = 0
    ULV.FastScroller(False)
    ULV.SetPadding(0, 0, 0, 0)
    ULV.NumberOfAsyncLoaders = 2
    ULV.SetStyle(ULV.STYLE_HOLO_LIGHT)
    ULV.OverscrollMaximum = 160dip
    ULV.AddLayout("Refresher", "Refresher_LayoutCreator", "", 0, False)
    ULV.SetLoadImageCallbacks("Bmp_Placeholder", "", "Bmp_PostLoad", "Bmp_LoadingError")
    ULV.AddLayout("Bitmap2Lines", "Item_LayoutCreator", "Item_Filler",100dip, False)
    ULV.AddLayout("ExtendedItem", "Item_LayoutCreator", "Item_Filler", 100%x + 70dip, False)
    ULV.AddLayout("SiteSeparator", "SiteSeparator_LayoutCreator", "SiteSeparator_Filler", 35dip, False)
    Activ.AddView(ULV, 0, 0, 100%x, Activ.Height)
    Animator.Initialize(ULV,"Animator")
    'AlphaAnimator.Initialize(ULV, "AlphaAnimator")
    ULV.AnimationCleaner = True
    ULV.Color = ULVcolors
    Dim Image44 As Bitmap
        Image44.Initialize(File.DirAssets,"MyBG.png")
        Image44 = LoadBitmapSample(File.DirAssets,"MyBG.png",100%x,100%y)
    ULV.SetBackgroundImage(Image44,Gravity.CENTER)
  
    'Initializes the refresh state
    RefreshState = RSTATE_WAITING
    'Loads the status icons
    ArrowDown.Initialize(File.DirAssets, "arrow_down.png")
    ArrowUp.Initialize(File.DirAssets, "arrow_up.png")
    LoadingTimer.Initialize("LoadingTimer", 2000)
Why did you keep the timer ? It is used in the demo to simulate the loading of data. It is completely useless for a normal use.
 

itgirl

Active Member
Licensed User
Longtime User
Why did you keep the timer ? It is used in the demo to simulate the loading of data. It is completely useless for a normal use.
i know lol but when i remove the timer it hangs for a 2 seconds from httpjob i think and it doesn't show the changes to the txt in refresher this way i can delay the job for 2 secs . you think this is the problem ?
 

Informatix

Expert
Licensed User
Longtime User
i know lol but when i remove the timer it hangs for a 2 seconds from httpjob i think and it doesn't show the changes to the txt in refresher this way i can delay the job for 2 secs . you think this is the problem ?
You have to debug your code. Without the code, I cannot do it for you. First, remove all the loading stuff. Do you still encounter the NullPointerException ?
 

itgirl

Active Member
Licensed User
Longtime User
You have to debug your code. Without the code, I cannot do it for you. First, remove all the loading stuff. Do you still encounter the NullPointerException ?
No without the loading stuff i don't get any errors , i think the problem is with [UpdateRefreshItem] sub but also it has a [Try] so it should give me an idea of what's going on but no luck. I'll try to debug it and get back to you , hopefully the error will comeup because some times it does and some times it doesn't
 

itgirl

Active Member
Licensed User
Longtime User
Hello Informatix after alot of debuging i was able to figure little bit about this problem , infact the error is even in the official [Scroll] example in the ULV examples,,
the way to reproduce the error by simply ... pausing the activity while it's being in RSTATE_WAITING. so the problem is in the activity pause code

B4X:
Sub Activity_Pause (UserClosed As Boolean)
   'Stops the timer and resets the list
   If RefreshState <> RSTATE_WAITING Then
     LoadingTimer.Enabled = False
     UpdateRefreshItem(0, RSTATE_WAITING)
     ULV.JumpTo(1, False)
     ULV.Enabled = True
   End If
End Sub

as i told you before it was so random error but now i can reproduce it easily by pulling down the panel and and keep it pulled then i simply pause the activity and the error comes up ...


[EDIT]
even if the code in activity pause is removed the error still coming up :( hopefully you can shed a light on what's going on!!
 

Informatix

Expert
Licensed User
Longtime User
Hello Informatix after alot of debuging i was able to figure little bit about this problem , infact the error is even in the official [Scroll] example in the ULV examples,,
the way to reproduce the error by simply ... pausing the activity while it's being in RSTATE_WAITING. so the problem is in the activity pause code

B4X:
Sub Activity_Pause (UserClosed As Boolean)
   'Stops the timer and resets the list
   If RefreshState <> RSTATE_WAITING Then
     LoadingTimer.Enabled = False
     UpdateRefreshItem(0, RSTATE_WAITING)
     ULV.JumpTo(1, False)
     ULV.Enabled = True
   End If
End Sub

as i told you before it was so random error but now i can reproduce it easily by pulling down the panel and and keep it pulled then i simply pause the activity and the error comes up ...


[EDIT]
even if the code in activity pause is removed the error still coming up :( hopefully you can shed a light on what's going on!!
Thanks for the report. I'm going to check that.
 

Informatix

Expert
Licensed User
Longtime User
Hello Informatix after alot of debuging i was able to figure little bit about this problem , infact the error is even in the official [Scroll] example in the ULV examples,,
the way to reproduce the error by simply ... pausing the activity while it's being in RSTATE_WAITING. so the problem is in the activity pause code

B4X:
Sub Activity_Pause (UserClosed As Boolean)
   'Stops the timer and resets the list
   If RefreshState <> RSTATE_WAITING Then
     LoadingTimer.Enabled = False
     UpdateRefreshItem(0, RSTATE_WAITING)
     ULV.JumpTo(1, False)
     ULV.Enabled = True
   End If
End Sub

as i told you before it was so random error but now i can reproduce it easily by pulling down the panel and and keep it pulled then i simply pause the activity and the error comes up ...


[EDIT]
even if the code in activity pause is removed the error still coming up :( hopefully you can shed a light on what's going on!!
I finally found a way to reproduce the problem: you have to start pulling, then go to pause (e.g. by taping the home button) with the finger still on screen.
 

itgirl

Active Member
Licensed User
Longtime User
I finally found a way to reproduce the problem: you have to start pulling, then go to pause (e.g. by taping the home button) with the finger still on screen.
that's exactly what i was doing .

thank you so much for the help ;)
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi All,

For every item_Clicked, the internal selected items is updated. Is there a way to disable this so that the internal selected items is updated only for an Item_LongClick

Regards,
SK
 

Informatix

Expert
Licensed User
Longtime User
IMPORTANT
I'd like to receive questions from licensed users ONLY BY EMAIL please. It's a nightmare to manage my exchanges with you in this forum (I lost 1/2 hour recently to find an answer I gave a few months ago while it takes me only a few seconds in my email software). I'd like to keep this thread for announcements and questions of unlicensed users.
 
Top