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:

Informatix

Expert
Licensed User
Longtime User
Hi Informatix

I want share (facebook, twitter) a image showed in a image view, this image is download from a website. So im using a button with a popup menu in the ULV.

The popup menu is ok. The problem is retrieve a reference to the Imageview in the ClickedPanel in ULV. I´m using the tag property of button to store the ItemID but i dont know how can i access the ClickedPanel in ULV.
Since you have the ItemID, I don't understand what you need. Get the image corresponding to this ItemID (probably from the cache if your image comes from the web) and share it. You don't need to access the ImageView (and as views are recycled, that would be a bad idea anyway).
Note that you can put any useful information in the Tag property of your button, so if the ItemID is not the most useful information to retrieve your image, choose another.
 

Davin

Member
Licensed User
Longtime User
just some question.. i really think its possible using your lib.

what i wanna make is apps like 9gag viewer. and what i can think of is :

1. load top 10 image by json query to a php script.
2. if almost reach bottom load the next 10.
3. the display will be like 9gag viewer. image on top. and some button below the image, and another image, same botton again.. and so on.
is it really possible make this using your lib ?

thanks
 

Informatix

Expert
Licensed User
Longtime User
just some question.. i really think its possible using your lib.

what i wanna make is apps like 9gag viewer. and what i can think of is :

1. load top 10 image by json query to a php script.
2. if almost reach bottom load the next 10.
3. the display will be like 9gag viewer. image on top. and some button below the image, and another image, same botton again.. and so on.
is it really possible make this using your lib ?

thanks
To do this, I'm not sure you really need the ULV. I think you can do that with free classes/libs. Did you search on the forum?
 

Davin

Member
Licensed User
Longtime User
To do this, I'm not sure you really need the ULV. I think you can do that with free classes/libs. Did you search on the forum?
yes sir. i use some other libs. but problem is. after load like 30++ image. the apps crash. because memory low something.

well maybe i havent search and try more :(
 

b4auser1

Well-Known Member
Licensed User
Longtime User
Hi Informatix,

I checked ULV (MyFirstList1.b4a) on Android 5.0.1 and found the error message in LOG:
java.lang.NoSuchFieldException: mFastScroller
From the internet: "Found the solution be comparing AbsListView of Lollipop with previous versions and found out the the keyword/name for getting declared feild is changed to mFastScroll from mFastScroller.."
Please correct if it's affordable. Thank you.
 

Informatix

Expert
Licensed User
Longtime User
Hi Informatix,

I checked ULV (MyFirstList1.b4a) on Android 5.0.1 and found the error message in LOG:
java.lang.NoSuchFieldException: mFastScroller
From the internet: "Found the solution be comparing AbsListView of Lollipop with previous versions and found out the the keyword/name for getting declared feild is changed to mFastScroll from mFastScroller.."
Please correct if it's affordable. Thank you.
Please read the post #458.
 

MarcoRome

Expert
Licensed User
Longtime User
Hi Informatix... is it as an expandable ListView with text ??

Example:

image-immagine1-548F_54D35932.png


Thank you in advance
Marco
 

walterf25

Expert
Licensed User
Longtime User
Any way to change the divider line color, or minimize the height of the divider line?

Thanks,
Walter
I found a way to change the divider line color and the height.
B4X:
Sub SetDivider(lv As UltimateListView, Color As Int, Height As Int)
   Dim r As Reflector
   r.Target = lv
   Dim CD As ColorDrawable
   CD.Initialize(Color, 0)
   r.RunMethod4("setDivider", Array As Object(CD), Array As String("android.graphics.drawable.Drawable"))
   r.RunMethod2("setDividerHeight", Height, "java.lang.int")
End Sub

But now i have another question, is there a way to access the parent panel so that i can change the background color, If I add a 9 patch image to the layoutpanel inside the content layout sub, I can see the the background is always black, and i would like to change it to white, i tried by setting the activity's color to white, but it doesn't help, the only way i figured out to change the background color is by setting the theme to "Theme.Light" in the manifest editor, but i don't really like the fact that it makes the activity title's height thinner, and it shows a different scrolling bar.

B4X:
SetApplicationAttribute(android:theme, "@android:style/Theme.Light")

Thanks, hope you can answer my question.

Walter
 

Informatix

Expert
Licensed User
Longtime User
I found a way to change the divider line color and the height.
B4X:
Sub SetDivider(lv As UltimateListView, Color As Int, Height As Int)
   Dim r As Reflector
   r.Target = lv
   Dim CD As ColorDrawable
   CD.Initialize(Color, 0)
   r.RunMethod4("setDivider", Array As Object(CD), Array As String("android.graphics.drawable.Drawable"))
   r.RunMethod2("setDividerHeight", Height, "java.lang.int")
End Sub

But now i have another question, is there a way to access the parent panel so that i can change the background color, If I add a 9 patch image to the layoutpanel inside the content layout sub, I can see the the background is always black, and i would like to change it to white, i tried by setting the activity's color to white, but it doesn't help, the only way i figured out to change the background color is by setting the theme to "Theme.Light" in the manifest editor, but i don't really like the fact that it makes the activity title's height thinner, and it shows a different scrolling bar.

B4X:
SetApplicationAttribute(android:theme, "@android:style/Theme.Light")

Thanks, hope you can answer my question.

Walter
All your questions (divider and background) are answered in the User's Guide, in the Appearance chapter. There's no need to use the Reflection library or edit the manifest.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Fred,

While adding ripple effect to the Cellpanel i got the following error.

B4X:
Convert byte code - optimized dex.      Error
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lcom/andexert/library/RippleView$1;
    at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:122)
    at com.android.dx.dex.file.DexFile.add(DexFile.java:161)
    at com.android.dx.command.dexer.Main.processClass(Main.java:732)
    at com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)
    at com.android.dx.command.dexer.Main.access$300(Main.java:82)
    at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)
    at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
    at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
    at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
    at com.android.dx.command.dexer.Main.processOne(Main.java:632)
    at com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)
    at com.android.dx.command.dexer.Main.runMonoDex(Main.java:279)
    at com.android.dx.command.dexer.Main.run(Main.java:245)
    at com.android.dx.command.dexer.Main.main(Main.java:214)
    at com.android.dx.command.Main.main(Main.java:106)
1 error; aborting
    Optimized dexer failed. Switching to Standard dexer.

Regards,
SK
 

Informatix

Expert
Licensed User
Longtime User
Hi Fred,

While adding ripple effect to the Cellpanel i got the following error.

B4X:
Convert byte code - optimized dex.      Error
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lcom/andexert/library/RippleView$1;
    at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:122)
    at com.android.dx.dex.file.DexFile.add(DexFile.java:161)
    at com.android.dx.command.dexer.Main.processClass(Main.java:732)
    at com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)
    at com.android.dx.command.dexer.Main.access$300(Main.java:82)
    at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)
    at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
    at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
    at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
    at com.android.dx.command.dexer.Main.processOne(Main.java:632)
    at com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)
    at com.android.dx.command.dexer.Main.runMonoDex(Main.java:279)
    at com.android.dx.command.dexer.Main.run(Main.java:245)
    at com.android.dx.command.dexer.Main.main(Main.java:214)
    at com.android.dx.command.Main.main(Main.java:106)
1 error; aborting
    Optimized dexer failed. Switching to Standard dexer.

Regards,
SK
I don't know this error and I have no idea about it. Are you sure this is related to ULV? It seems you did not even compile succcessfully.
 

cimperia

Active Member
Licensed User
Longtime User
SK,
I think it means you have the same library RippleView twice under two different jar versions.
The build process checks the checksum of every jar and raises this error if the jar is found more than once and they have different checksums.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Cimperia,

Thank you for your reply. I checked with the standard ripple view example and also added the ripple view to the performance example of ULV and it works fine. only getting this error with my app. there is only one jar in the library files. I do not know where i am going wrong. i did a clean project but it didnt help.

Regards,
SK
 

cimperia

Active Member
Licensed User
Longtime User
SK,

I should have said that this error also means that the same class appears in two referenced jars.

This is the most common source of this error.

I suggest you do a search on this forum with "java.lang.IllegalArgumentException: already added" for further help.
 

itgirl

Active Member
Licensed User
Longtime User
Hello informatix , Im working on a project using your Lib from the images example and everything was fine until recently i tried to implement the [ Pull to refresh ] example you provided and after a long headache i was able to achieve it successfully and it's very nice looking but the problem is after i implemented this method i have been seeing an error repeatedly that i have not seen before the [pull to refresh] implementation , an also it's so random some times i get it sometimes not

B4X:
    Ignoring event: ulv_scrolled
    java.lang.NullPointerException
    at flm.b4a.ultimatelistview.UltimateListView.onTouchEvent(SourceFile:320)
    at android.view.View.dispatchTouchEvent(View.java:8107)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2129)
    at flm.b4a.ultimatelistview.UltimateListView.dispatchTouchEvent(SourceFile:504)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2280)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1615)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2549)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2228)
    at android.view.View.dispatchPointerEvent(View.java:8315)
    at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4597)
    at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4465)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4077)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4046)
    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4157)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4054)
    at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4214)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4077)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4046)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4054)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6404)
    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6308)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6279)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6244)
    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6484)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
    at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6457)
    at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6503)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
    at android.view.Choreographer.doCallbacks(Choreographer.java:603)
    at android.view.Choreographer.doFrame(Choreographer.java:571)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789
Message longer than Log limit (4000). Message was truncated.

any help would be appreciated , i really liked the [pull to refresh] and i don't wanna give it up to get rid of this error :(
 

Informatix

Expert
Licensed User
Longtime User
Hello informatix , Im working on a project using your Lib from the images example and everything was fine until recently i tried to implement the [ Pull to refresh ] example you provided and after a long headache i was able to achieve it successfully and it's very nice looking but the problem is after i implemented this method i have been seeing an error repeatedly that i have not seen before the [pull to refresh] implementation , an also it's so random some times i get it sometimes not

B4X:
    Ignoring event: ulv_scrolled
    java.lang.NullPointerException
    at flm.b4a.ultimatelistview.UltimateListView.onTouchEvent(SourceFile:320)
    at android.view.View.dispatchTouchEvent(View.java:8107)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2129)
    at flm.b4a.ultimatelistview.UltimateListView.dispatchTouchEvent(SourceFile:504)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2280)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1615)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2549)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2228)
    at android.view.View.dispatchPointerEvent(View.java:8315)
    at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4597)
    at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4465)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4077)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4046)
    at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4157)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4054)
    at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4214)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4077)
    at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4046)
    at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4054)
    at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4023)
    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6404)
    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6308)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6279)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6244)
    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6484)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
    at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6457)
    at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6503)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
    at android.view.Choreographer.doCallbacks(Choreographer.java:603)
    at android.view.Choreographer.doFrame(Choreographer.java:571)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789
Message longer than Log limit (4000). Message was truncated.

any help would be appreciated , i really liked the [pull to refresh] and i don't wanna give it up to get rid of this error :(
Without code, I cannot help.
 
Top