B4A Library AHViewPager library - Sliding panels now perfect

This library is a B4A implementation of the ViewPager object provided by the compatibility class from google. With this library it is possible to add sliding panels to your apps.

AHPageContainer - This object is a container for the pages of the AHViewPager. You should add Panels to this object.

AHViewPager - This is the main object which provides the sliding panels.

All the Tabs objects are deprecated now. You can use them but I don't enhance them anymore. For nice looking Tabs please use the DSTabLayout object of the DesignSupport library.
Alternatively you can use the TabStripViewPager.


Installation:
  • From V3.00 on the library requires B4A 6.0 or later.
  • This library depends on the Android Support library so you need to install the Android Support repository in the Extras section with SDK Manager.
  • Copy the AHViewPager.xml and AHViewPager.jar files to your additional libraries folder.
Example project:

For an example project for this library see the Design Support Library.

Your support:
Creating libraries and wrappers for existing library projects is a lot of work. The use of this library is totally free and you even don't need to mention in your app that you use it.
But if you use this library in your projects and you think it is useful to you please consider to make a donation:

Thanks very much for your support.

Version History:

1.00:
- initial version

1.01:
- Added AHViewPagerFixedTabs object for a fixed tab indicator
- Fixed a bug that it was impossible to get the canvas of a panel which was added to the container (It was impossible to display charts on a page)
- Example for AHViewPagerFixedTabs tab indicator

1.02: (Never released)
- Fixes problem with tab height (Line is now always on the bottom)

1.03:
- Fixes problem with Line sometimes not updating correctly on Android 4.0+
- Fix UppercaseTitle property

2.0:
- Complete Rewrite of the Swipey tabs code to fix some bugs with newer android versions.

2.01:
- New property for the AHViewPager object: PagingEnabled - Enables or disables paging for the ViewPager.

2.02:
- New events PageScrolled and PageScrollStateChanged (with SCROLLSTATE constants)
See post 227 for details

2.20:
- Use raiseEventfromUI() in most events
- New SupportTabs object
- New SupportTitles object
- Support for Designer (as a Custom View)
- some minor internal changes and bug fixes

2.21:
- Use raiseEvent() for PageCreated and PageDestroyed event again to prevent double UI refreshes
- Added @RaiseSynchronousEvents annotation to GotoPage() (to make it better compatible with rapid debugger.

3.00:
- Support for Designer Custom Properties.
- Uses maven repository to access support library. (B4A 6.0 or later required)

Attention: V2.20 has an API change which makes the ViewPager incompatible with older versions. The AHPageContainer parameter is removed from the Initialize() method. Initialize2() has the old signature. If you use Initialize() (or add the View to the Designer as a custom view) then you have to set the container object with ViewPager.PageContainer = <YourContainer>

The examples use the old Initialize method, so they are broken. I was too lazy to fix them because I recommend the tab indicator from the Design Support library for a nice looking Material Design app.
 

Attachments

  • screenshot-1336034831196.png
    screenshot-1336034831196.png
    10.1 KB · Views: 8,264
  • screenshot-1336034966953.png
    screenshot-1336034966953.png
    9.9 KB · Views: 7,533
  • AHViewPager2_21.zip
    39.8 KB · Views: 2,514
  • AHViewPager3_00.zip
    74.9 KB · Views: 2,466
Last edited:

FrenchDeveloper

Member
Licensed User
Longtime User
Hello and thank you very much for this great lib !

I just added this code at the end of Activity_Create in ScrollingTabs example :
B4X:
For i = 0 To 9
        Dim px As Panel
        px = PC.GetPageObject(i)
        LogColor(i & " - " & px.Width, Colors.Blue)        'line 66
Next
and I have a strange issue :
** Activity (main) Pause, UserClosed = false **
** Activity (main) Create, isFirst = true **
0 - 2560
1 - 2560
Error occurred on line: 66 (Main)
java.lang.NullPointerException: Attempt to read from field 'int android.view.ViewGroup$LayoutParams.width' on a null object reference
at anywheresoftware.b4a.objects.ViewWrapper.getWidth(ViewWrapper.java:140)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:708)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:337)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:247)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:134)
at example.tablayout.scrollingtabs.main.afterFirstLayout(main.java:102)
at example.tablayout.scrollingtabs.main.access$000(main.java:17)
at example.tablayout.scrollingtabs.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7331)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
** Activity (main) Resume **
Why does it happen when i = 2 and not before ?
 

Manuel Martinez

Member
Licensed User
Longtime User
Hello and thank you very much for this great lib !

I just added this code at the end of Activity_Create in ScrollingTabs example :
B4X:
For i = 0 To 9
        Dim px As Panel
        px = PC.GetPageObject(i)
        LogColor(i & " - " & px.Width, Colors.Blue)        'line 66
Next
and I have a strange issue :

Why does it happen when i = 2 and not before ?

I think is because the pages are not yet created, they are created and destroyed dynamically.

If you check the logs in the example, you can see that the library keep one after an one before the current page.

B4X:
Dim px As Panel
px = PC.GetPageObject(Position)
LogColor(Position & " - " & px.Width, Colors.Blue)

Put this code in the VP_PageCreated method to see the width of the page created.
 

FrenchDeveloper

Member
Licensed User
Longtime User
Thank you Manuel for your reply

I just realised it. Is there a way to prevent the library to destroy pages ? I need to pre load pages because it takes time.
 

FrenchDeveloper

Member
Licensed User
Longtime User
I found this way to prevent the library to destroy pages (I have 10 pages) :
B4X:
VP.OffscreenPageLimit = 10
but then, VP_PageCreated event is not raised anymore
 

Manuel Martinez

Member
Licensed User
Longtime User
I found this way to prevent the library to destroy pages (I have 10 pages) :
B4X:
VP.OffscreenPageLimit = 10
but then, VP_PageCreated event is not raised anymore

You are right, I guess it's because there is no more pages to create.

If you change VP.OffscreenPageLimit to 5, the page 6 is created after change to page 1.
 

yolira

Member
Licensed User
Longtime User
Hi, I get an error. Please can you help me?

B4A version: 6.80
Parsing code. (0.01s)
Compiling code. (1.00s)
Compiling layouts code. (0.00s)
Organizing libraries. (0.00s)
Generating R file. Error
AndroidManifest.xml:16: error: Error: No resource found that matches the given name (at 'theme' with value '@style/Theme.AppCompat').

Thanks
 

leitor79

Active Member
Licensed User
Longtime User
Hi,

I'm struggling with this from weeks ago. I've changed the behavior of my app several times (caching destroyed items, disabled scrolling, etc) in order to avoid issues but this one I don't understand:

B4X:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

The code goes like this:

B4X:
            Dim p As Panel
            If Paneles(iPeriodoActual).ContainsKey(iDiaActual) = True Then 'i have the panels cached in an array of maps
                p = Paneles(iPeriodoActual).Get(iDiaActual) 'if i have the item cached, i retrieve it
            Else
                p = CrearGrafica(iDiaActual, iPeriodoActual) 'if i don't have it cached, i create it
                Paneles(iPeriodoActual).Put(iDiaActual, p) 'and then i add it to the cache
            End If
            p.RemoveView 'either way, i use the remove view to prevent the luke skywalker issue (it has a father and it's alive). I know that this should not be needed when the panel is created, but as I keep getting the error I put it here, I think is does no harm if the panel is new.
            PC.AddPageAt(p, iDiaActual, 0) '<- error raises here


Thank you very much!



PS: I can't use the new control since I don't have (yet) the new b4a version.
 

FrenchDeveloper

Member
Licensed User
Longtime User
Hello,
I modified slightly the example in the first thread to add the viewpager to a panel instead to the activity. It works until views in the layout are anchored.
Anchored views disapear.
B4X:
    'Add the pager to a window
    Pnl_Window.Initialize("Pnl_Window")
    Activity.AddView(Pnl_Window, 10%x, 10%y, 80%x, 80%y)
    Pnl_Window.Color = Colors.Green
    Pnl_Window.AddView(Pager, 0%x, 0%y, -1, -1)

Thanks in advance for any help !
 

Attachments

  • AHViewPager and anchors.zip
    9.1 KB · Views: 451

Roberto P.

Well-Known Member
Licensed User
Longtime User
Hi everyone
with android 9, the library gives the following error. can you tell me the reason or you can update the library.

java.lang.RuntimeException: java.lang.IllegalArgumentException: Cannot set 'scaleX' to Float.NaN
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:170)
at anywheresoftware.b4a.objects.PanelWrapper.LoadLayout(PanelWrapper.java:134)


thank in advance
 

corwin42

Expert
Licensed User
Longtime User
Is there any reason to include the jetified resource? I thought every user should be able to create the files automatically with running the jetifier manually.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I thought every user should be able to create the files automatically with running the jetifier manually.
True.

However not all developers always read the instructions and as there were several developers who encountered the same error, it was easier for me to add the jetified resource.

In the long run the non-jetified resources (when relevant) will not be needed at all.
 

corwin42

Expert
Licensed User
Longtime User
I have no experience with RTL support but in AndroidX there is a new Viewpager (vierpager2) with direct RTL support.
I will try to update to this control but this will take some time...
 

cxbs

Active Member
Licensed User
Longtime User
Hello corwin42
Thank you very much for your library
Can I set up a circular display page?
I want to design a date display page. There are three pages in total
When the user moves to the left to the first page, the third page will be displayed if the user moves to the left again. Now I can only insert a new page through addpageat (datepage, "3", 0), then set CurrentPage = 1, and finally delete the third page.
thank you!
 

corwin42

Expert
Licensed User
Longtime User
The Android Viewpager does not initially support circular scrolling. There are some solutions out there but most times they use similar tricks than you youse. So I don't see the effort in including it into the library. It is a rarely used edge case.
 

Ilya G.

Active Member
Licensed User
Longtime User
Sometimes the following error appears in a very large project, what could it be related to?

B4X:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 5, found: 0 Pager id: b Pager class: class de.amberhome.viewpager.internal.CustomViewPager Problematic adapter: class de.amberhome.viewpager.AHPageContainer
    at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1143)
    at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
    at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChild(Unknown Source:26)
    at android.view.ViewGroup.measureChildren(Unknown Source:17)
    at anywheresoftware.b4a.BALayout.onMeasure(BALayout.java:81)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChildWithMargins(Unknown Source:42)
    at android.widget.FrameLayout.onMeasure(Unknown Source:82)
    at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:146)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChildWithMargins(Unknown Source:42)
    at android.widget.LinearLayout.measureChildBeforeLayout(Unknown Source:6)
    at android.widget.LinearLayout.measureVertical(Unknown Source:249)
    at android.widget.LinearLayout.onMeasure(Unknown Source:5)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChildWithMargins(Unknown Source:42)
    at android.widget.FrameLayout.onMeasure(Unknown Source:82)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChildWithMargins(Unknown Source:42)
    at android.widget.LinearLayout.measureChildBeforeLayout(Unknown Source:6)
    at android.widget.LinearLayout.measureVertical(Unknown Source:249)
    at android.widget.LinearLayout.onMeasure(Unknown Source:5)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewGroup.measureChildWithMargins(Unknown Source:42)
    at android.widget.FrameLayout.onMeasure(Unknown Source:82)
    at com.android.internal.policy.DecorView.onMeasure(Unknown Source:308)
    at android.view.View.measure(Unknown Source:232)
    at android.view.ViewRootImpl.performMeasure(Unknown Source:15)
    at android.view.ViewRootImpl.measureHierarchy(Unknown Source:100)
    at android.view.ViewRootImpl.performTraversals(Unknown Source:538)
    at android.view.ViewRootImpl.doTraversal(Unknown Source:36)
    at android.view.ViewRootImpl$TraversalRunnable.run(Unknown Source:2)
    at android.view.Choreographer$CallbackRecord.run(Unknown Source:20)
    at android.view.Choreographer.doCallbacks(Unknown Source:88)
    at android.view.Choreographer.doFrame(Unknown Source:215)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Unknown Source:9)
    at android.os.Handler.handleCallback(Unknown Source:2)
    at android.os.Handler.dispatchMessage(Unknown Source:4)
    at android.os.Looper.loop(Unknown Source:242)
    at android.app.ActivityThread.main(Unknown Source:101)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(Unknown Source:11)
    at com.android.internal.os.ZygoteInit.main(Unknown Source:275)
 

max123

Well-Known Member
Licensed User
Longtime User
Hi @corwin42,

I've tried to convert my really complex app to B4XPages so it can work in background and have some questions.

In my original project I've used your good AHViewPager to slide 10 pages, is this good using B4XPages or B4XPages replace it by just add new pages ?

I can mantain AHViewPager without conflicts so I do not need to rewrite a lot of code and continue to use it because it ?

Please, note that any page load it's layout created with Designer, note even that I used B4A Jetify tool to switch to Android X as Erel said. I've read something you wrote here about Android ViewPager2, I need to update the library ?

Many thanks
 
Last edited:
Top