Giter Club home page Giter Club logo

recyclerview-fastscroller's Introduction

RecyclerViewFastScroller

Github release Maven Central Code size Android Weekly #317 Kotlin Weekly #101

A simple, easy to use and configurable fast scroller for RecyclerView

Adding the dependency

implementation 'com.quiph.ui:recyclerviewfastscroller:1.0.0'

Java-only project?

As Kotlin compiles to Java, there's no need to externally add the Kotlin runtime or any other Kotlin dependencies when using this. Also the library is 100% compatible with Java and requires no migration of the base project to Kotlin.

Usage:

The base layout type for this fast scroller is a RelativeLayout so creating a simple vertical fast scroller is as simple as adding elements as children to the RecyclerViewFastScroller layout tag

<com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
        android:layout_width="match_parent"
        android:id="@+id/fastscroller"
       android:layout_height="match_parent">
        <android.support.v7.widget.RecyclerView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>
        ....
        other view tags can also come here
        ....
</com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller>

Since the fast scroller extends a RelativeLayout other view tags can also be added to it, with the rule being that the RecyclerView on which the fast scroller functionality needs to be added be the first element in the ViewGroup

Programmatically adding the RecyclerView

If the RecyclerView to be added to the fast scroller is not available during layout creation time, the same can be done programmatically by calling the attachFastScrollerToRecyclerView method on the RecyclerView

Linking with items:

To reflect the item on the index of the top-most visible item, make the adapter implement the OnPopupTextUpdate interface, which overrides the method onChange(int index) which passes the index of the element whose info needs to be displayed in the popup.

The CharSequence to be displayed should be returned in this method.

Ex:

class MyAdapter : RecyclerView.Adapter<SomeViewHolder>, OnPopupTextUpdate{
// ....
override fun onChange(position: Int): CharSequence {
   val header = // compute value for header using position
   return header                  
   }
}

Getting fast scroller callbacks:

To get the callback from the fast scroller for different states, a listener can be added using the setHandleStateListener which accepts an interface of type HandleStateListener which has the following callback methods:

  • onEngaged - Called when the fast scroller is engaged
  • onDragged - Called on every movement of the fast scroller, note: this does not get called when the handle moves programmatically, i.e when then the Scroll is programmatic
  • onReleased - Called when the fast scroller is released.

Customizable XML Attributes:

  • trackDrawable - Adds a custom drawable to the scrolling track, defaults to null
  • handleDrawable - Adds a custom drawable to the scrolling handle of the fast scroller
  • popupDrawable - Adds a custom drawable to the popup used to show the index of the element fast scrolled at
  • popupTextStyle - Sets the style for the popup text shown
  • fastScrollEnabled - Boolean flag to enable/ disable the fast scroller, the fast scroller view and track are hidden when disabled
  • popupPosition - An enum to define where the popup should be shown for the fast scroller, one of
    1. beforeTrack - Positions the popup to be shown before the scroll track
    2. afterTrack - Position it after the scroll track
  • handleWidth - Use to custom set the width of the fast scroll handle - Defaults to 18dp
  • handleHeight - Use to custom set the height of the fast scroll handle - Defaults to 18dp
  • addLastItemPadding - By default the last item of the RecyclerView associated with the fast scroller has an extra padding of the height of the first visible item found, to disable this behaviour set this as false
  • supportSwipeToRefresh - To support smooth scrolling for RecyclerViews nested within a SwipeRefreshLayout
  • trackMarginStart - Adds a start margin to the track of the fastscroller
  • trackMarginEnd - Adds a end margin to the track of the fastscroller
  • handleVisibilityDuration - Adds an option to specify the duration to hide the fastscroller handle, defaults to -1, which doesn't hide it
  • handleHasFixedSize - TODO - currently setting this to false doesn't do anything, as the size of the handle is independent of the item count
  • fastScrollDirection - TODO - currently the fast scroller only works in the vertical direction

Advanced usage:

  • Different color popups can be shown based on the position of the item shown, to do this, implement the OnPopupViewUpdate which overrides the onUpdate(position: Int, popupTextView: TextView) which return void, but has an instance of the TextView used in popup, this can be used to change the background.

Check the sample file AdvancedFragment and AdvancedAdapter for example usage

Ex:

class MyAdapter : RecyclerView.Adapter<SomeViewHolder>, OnPopupViewUpdate{

    override fun onChange(position: Int, popupTextView: TextView) {
       // Do something with the TextView here
       popupTextView.background = Color.RED // change some values etc
       }
}

The popupDrawable attribute and the popupTextStyle attributes can be used to create different kinds of elements, shapes and text appearance combinations, for example like the popup similar to the Google Dialer app:

Check the sample to view the implementation. Many such shapes and text styles can be created.

Proguard:

There is no need for any additional proguard rules when using this.

Contributing

Thank you for your interest :)

To start contributing, you can check out the issues section with the tag "Good first issue" to start working on the low-hanging fruits. Once you feel comfortable to contribute, fork the project and raise a PR, we'd be happy to review it <3

Creating a Pull Request

Our team follows the GitHub pull request workflow: fork, branch, commit, pull request, review, merge. If you're new to GitHub, check out the official guides for more information.

An example commit message summary looks like, For #5: Upgrade gradle to v1.3.0.

Please follow these guidelines for your pull requests:

  • All Pull Requests should address an issue. If your pull request doesn't have an issue, file it!
    • GitHub search defaults to issues, not PRs, so ensuring there is an issue for your PR means it'll be easier to find
  • The commit message summary should briefly describe what code changed in the commit, not the issue you're fixing.
    • We encourage you to use the commit message body to elaborate what changed and why
  • Include the issue number in your commit messages. This links your PR to the issue it's intended to fix.
    • If your PR closes an issue, include Closes #... in one of your commit messages. This will automatically close the linked issue more info.
    • If your PR has to go through a longer process, for example QA verification, use the For #... syntax to allow the linked issue to be closed at a later, more appropriate time.
  • Prefer "micro commits".
    • A micro commit is a small commit that generally changes one thing. A single Pull Request may comprise of multiple incremental micro commits.
    • A series of micro commits should tell a story. For example, if your goal is to add a new icon to the toolbar, you can make a commit to add the icon asset and then make a commit to use the icon in the code.
    • Commits should generally not undo the work of previous commits in the same PR.
    • If you're not comfortable making micro commits, it's okay to begin contributing without them.
  • Add a reviewer to ensure someone sees, and reviews, your pull request so it can be merged
  • If the tests fail, please try to fix them! Keeping the tests passing ensures our code isn't broken and the code is unlikely to get merged without passing tests. If you run into trouble, ask for help!
  • If there are UI changes, include a screenshot so UX can also do a visual review
  • When in doubt, look at the closed PRs in the repository to follow as an example or ask us online!

If your code is not approved, address the suggested comments, push your changes, and re-request review from your reviewer again.

Merging

After your code has been approved and the tests pass, your code will be merged into master by the core team. When merging, we use GitHub's "Rebase and merge":

  • We keep a linear git history for readability
  • We prefer incremental commits to remain in the history
    • It's easier to read, helps with bisection, and matches repo state during review.### Building the source:

Building the source

To build the aar using using gradle, simply run the build command, ./gradlew build this will build and place the aars in the outputs/aar folder inside the library module. The final path may look something like:

"${rootProject.projectDir}/recyclerviewfastscroller/build/outputs/aar"

This path has a number of aars in it, (debug and release variants namely). To use these aars in the sample, simple uncomment the following line in build.gradle for sample

// implementation files("${rootProject.projectDir}/recyclerviewfastscroller/build/outputs/aar/recyclerviewfastscroller-release.aar")

Don't forget to comment the project/ module dependency above it. Re-sync the project and run the sample to test how the compiled version would behave.

Uploading to maven central:

We will be using the Nexus Software Repository for pushing our aars to maven-central, there are different methods to do this, another simple way is to upload to bintray and then push to maven-central from there, which one to use can completely depend upon the developer.

Detailed explanation here.

Once the environment is setup as mentioned in the gist, run the following command:

./gradlew clean build uploadArchives

TODO:

  • Add support for horizontal fast scrolling
  • Make handle size flexible to item count in adapter
  • Fix 0 item bug, which makes the fast scroller visible

recyclerview-fastscroller's People

Contributors

naveenchandan avatar shahsurajk avatar suhasts avatar tom5079 avatar tomriddle25 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

recyclerview-fastscroller's Issues

java.lang.NoSuchMethodException

android.view.InflateException: Binary XML file line #5: Binary XML file line #5: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
Caused by: android.view.InflateException: Binary XML file line #5: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
Caused by: java.lang.NoSuchMethodException: [class android.content.Context, interface android.util.AttributeSet]

Problem when using with ViewPager2 widget

There seems to be a problem when using the ViewPager2 widget to display a number of RecyclerViews each with a fast scroller. When swiping back and forwards between views the fast scroller stops working or crashes the app.

The problem seems to be the fast scroller's onDetachedFromWindow() function gets called (which de-attaches the fast scroller) when swiping away from a view meaning that it no longer works when the view is restored.

issue when using with SwipeRefreshLayout

it doesn't work properly with SwipeRefreshLayout.
here is code I have modified in your sample app

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
        android:id="@+id/fast_scroller"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:handleHeight="32dp"
        app:handleWidth="@dimen/default_handle_size">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/basic_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="@dimen/recycler_view_margin"
            android:layout_marginRight="@dimen/recycler_view_margin" />
    </com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

here is the issue what I am facing
19-12-06-13-40-05

Scroll handle is not positionned properly when scrolling the recycling view

Hello and thank you for this project.

I have noticed an issue when the list contains a small number of elements.
It can be reproduced by only keeping the first 20 or so items in the countries.json file of the sample app.

When scrolling using the scroll handle everything is going fine :

but when dragging down the list itself to the end, the scroll handle doesn't go until the bottom, even though I have reached the last element in the list :

Is it related to the TODO item mentioned in the README ( Make handle size flexible to item count in adapter) or is it a bug?

Population is not shown properly

So in "Advanced" where the countries are listed by population as you can see from my screen recording from the moment that it reaches the "Marshall Islands" the coloured box instead of being inside the rectangular of each country, so we can have country-population, it goes between the countries so we don't know which number is for which country.

I don't know if that was your purpose but I found that behaviour somehow strange so I wanted to point it out in case it is a bug so you can fix it :)

(URL: https://www.dropbox.com/s/bsty0kfhu9l8qrr/20210111_133818~2.mp4?dl=0)

This issue refers to the first 9 seconds of the video. (0:00 - 0:09)

Crash Fatal error android.widget.ImageView cannot be cast to androidx.appcompat.widget.AppCompatImageView

App crash when fragment is shown

I'm using vector drawable support library
Maybe that's causing this issue


defaultConfig {
        minSdkVersion 19
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        **vectorDrawables.useSupportLibrary = true**


        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
    }
android.view.InflateException: Binary XML file line #9 in com.pkg:layout/fragment_gallery_album_picker: Binary XML file line #9 in com.pkg:layout/fragment_gallery_album_picker: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
    Caused by: android.view.InflateException: Binary XML file line #9 in com.pkg:layout/fragment_gallery_album_picker: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
    Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at android.view.LayoutInflater.createView(LayoutInflater.java:854)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
        at com.pkg.VideoPickerFragment.onCreateView(VideoPickerFragment.java:62)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2663)
        at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2613)
        at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2624)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:904)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.ClassCastException: android.widget.ImageView cannot be cast to androidx.appcompat.widget.AppCompatImageView
        at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.addThumbAndTrack(Unknown Source:20)
2020-08-28 02:33:37.179 E:     at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.<init>(Unknown Source:58)
        at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.<init>(Unknown Source:10)
        at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.<init>(Unknown Source:6)

[Bug] Handle is moved when touched after sibling view stub is inflated

Setup

I have a vertical linear layout with a RecyclerView and a banner ViewStub above it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ViewStub
        android:id="@+id/stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/list_item"/>

    <com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
        android:id="@+id/fastScroller"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:handleHeight="40dp"
        app:handleWidth="40dp"
        app:handleHasFixedSize="true">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            />
    </com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller>
    
</LinearLayout>

Banner view stub is inflated later, after some conditions are met. To simplify this:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<RecyclerView>(R.id.recycler).run {
            adapter = MyListAdapter().also { it.submitList((0..100).toList()) }
        }

        Handler().postDelayed({
            findViewById<ViewStub>(R.id.stub).inflate()
        }, 500)
    }
}

Behavior

Actual
After view stub is inflated, handle is moved down when touched (approximately by an inflated view height). List is also scrolled down. Touch position does not correspond to a handle position.

device-2020-09-29-210938

Expected
Handle is not moved when touched. Handle is moved under a finger.

Here is the project that reproduces this issue: testfastscroll.zip

Can you suggest any workarounds?

FastScroll Padding?

Is there a way to set an upper and lower margin without affecting the recyclerview?

Since at the end of the scroll it is not possible to reach the last item and it must slide out of view :/

Render problem in layout xml file

Having this error in the layout file. FastScroller works alright though.
How can I fix this? My repo
https://github.com/AlexSheva-mason/Rickypedia

java.lang.NullPointerException
	at android.graphics.Canvas_Delegate.nGetClipBounds(Canvas_Delegate.java:418)
	at android.graphics.Canvas.nGetClipBounds(Canvas.java)
	at android.graphics.Canvas.getClipBounds(Canvas.java:1261)
	at android.text.Layout.getLineRangeForDraw(Layout.java:672)
	at android.text.Layout.draw(Layout.java:317)
	at android.text.BoringLayout.draw(BoringLayout.java:460)
	at android.widget.TextView.onDraw(TextView.java:7976)
	at android.view.View.draw_Original(View.java:21443)
	at android.view.View_Delegate.draw(View_Delegate.java:56)
	at android.view.View.draw(View.java:21417)
	at android.view.View.draw_Original(View.java:21317)
	at android.view.View_Delegate.draw(View_Delegate.java:68)
	at android.view.View.draw(View.java:21089)
	at android.view.ViewGroup.drawChild_Original(ViewGroup.java:4388)
	at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:65)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw_Original(View.java:21315)
	at android.view.View_Delegate.draw(View_Delegate.java:68)
	at android.view.View.draw(View.java:21089)
	at android.view.ViewGroup.drawChild_Original(ViewGroup.java:4388)
	at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:65)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw_Original(View.java:21315)
	at android.view.View_Delegate.draw(View_Delegate.java:68)
	at android.view.View.draw(View.java:21089)
	at android.view.ViewGroup.drawChild_Original(ViewGroup.java:4388)
	at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:65)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw_Original(View.java:21315)
	at android.view.View_Delegate.draw(View_Delegate.java:68)
	at android.view.View.draw(View.java:21089)
	at android.view.ViewGroup.drawChild_Original(ViewGroup.java:4388)
	at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:65)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw_Original(View.java:21315)
	at android.view.View_Delegate.draw(View_Delegate.java:68)
	at android.view.View.draw(View.java:21089)
	at android.view.ViewGroup.drawChild_Original(ViewGroup.java:4388)
	at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:65)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw_Original(View.java:21446)
	at android.view.View_Delegate.draw(View_Delegate.java:56)
	at android.view.View.draw(View.java:21417)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:404)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:565)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:425)
	at com.android.layoutlib.bridge.BridgeRenderSession.render(BridgeRenderSession.java:120)
	at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:151)
	at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:133)
	at com.android.tools.idea.rendering.RenderTask.lambda$null$9(RenderTask.java:819)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Support programmatic enabling/disabling of fastscroller

At the moment, this can only be done through the XML (fastScrollEnabled), but often we want to enable/disable according to, for example, how many items there are in the list. So it would be good to add a property on the recyclerview for this.

Similarly, for other XML-only attributes.

[Bug] FastScroll handle disappears

Bug Description

When you scroll to the last element and re-draw the fragment, the handle disappears (it's actually below the visible screen length).

Recording for reference :
output

SnapHelper().attachToRecyclerView() causes IllegalStateException

PageSnapHelper().attachToRecyclerView(reader_recyclerview)

causes

java.lang.IllegalStateException: An instance of OnFlingListener already set.
    at androidx.recyclerview.widget.SnapHelper.setupCallbacks(SnapHelper.java:113)
    at androidx.recyclerview.widget.SnapHelper.attachToRecyclerView(SnapHelper.java:101)
    ...

Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScrolle

 android.view.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
    Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
    Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
        at java.lang.Class.getConstructor0(Class.java:2327)
        at java.lang.Class.getConstructor(Class.java:1725)
        at android.view.LayoutInflater.createView(LayoutInflater.java:615)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)

Crash adapterDataObserver was not registered

java.lang.IllegalStateException: Observer com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller$adapterDataObserver$1$1@4a87042 was not registered.
at android.database.Observable.unregisterObserver(Observable.java:69)
at androidx.recyclerview.widget.RecyclerView$Adapter.unregisterAdapterDataObserver(RecyclerView.java:7537)
at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.detachFastScrollerFromRecyclerView(Unknown Source:31)
at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.onDetachedFromWindow(Unknown Source:0)
at android.view.View.dispatchDetachedFromWindow(View.java:20534)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3942)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3934)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5560)
at android.view.ViewGroup.removeViewAt(ViewGroup.java:5507)
at androidx.recyclerview.widget.RecyclerView$5.removeViewAt(RecyclerView.java:915)
at androidx.recyclerview.widget.ChildHelper.removeViewAt(ChildHelper.java:168)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeViewAt(RecyclerView.java:8946)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleViewAt(RecyclerView.java:9217)
at androidx.recyclerview.widget.LinearLayoutManager.recycleChildren(LinearLayoutManager.java:1437)
at androidx.recyclerview.widget.LinearLayoutManager.recycleViewsFromEnd(LinearLayoutManager.java:1531)
at androidx.recyclerview.widget.LinearLayoutManager.recycleByLayoutState(LinearLayoutManager.java:1556)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1582)
at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1395)
at androidx.recyclerview.widget.LinearLayoutManager.scrollHorizontallyBy(LinearLayoutManager.java:1124)
at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1969)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5476)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

Issue with handle not scrolling list in certain circumstances

Hello! Thanks for making this project, I've found it really easy to integrate and style, I really appreciate that it exists :)

I have an issue where the fast scroller gets stuck sometimes. What seems to prompt it is that I scroll using the fast scroller handle, then just scroll a little by touching the RecyclerView directly. After this, if I grab the fast scroller handle, I can move the handle up and down all the way from the top to the bottom of the screen, but the position in the list and the popup text do not change.

I can see that my onChange is not getting called either. If I implement a HandleStateListener I can see that onDragged is being fired, but in this situation, it always has a position of -1.

Then if I scroll the RecyclerView directly again, it becomes "reattached" and the fast scroller handle jumps back to the correct position and is able to be used properly again, with the correct position reported in onDragged, the correct text in onChange, and so on.

I can't work out a way to reliably replicate this โ€” it seems to happen only sometimes, perhaps based on the position of the items on screen?

Hope this has given you enough info to be able to replicate and fix. Thanks!

Crash - lateinit property recyclerView has not been initialized

kotlin.UninitializedPropertyAccessException: lateinit property recyclerView has not been initialized
    at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.access$getRecyclerView$p(Unknown Source:6)
    at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller$alignTrackAndHandle$5.run(Unknown Source:111)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

androidx.recyclerview.widget.StaggeredGridLayoutManager not supported

While I think this is a great library, it sadly seems only to support androidx.recyclerview.widget.LinearLayoutManager. Because our customer insists on a Layout which can only be produced by androidx.recyclerview.widget.StaggeredGridLayoutManager we sadly can't use this

    java.lang.ClassCastException: androidx.recyclerview.widget.StaggeredGridLayoutManager cannot be cast to androidx.recyclerview.widget.LinearLayoutManager
        at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller$onScrollListener$1.onScrolled(Unknown Source:31)
        at androidx.recyclerview.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:5347)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4405)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4031)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4578)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1103)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1213)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:899)
        at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:919)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1855)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1855)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at com.android.internal.policy.DecorView.onLayout(DecorView.java:1099)
        at android.view.View.layout(View.java:23750)
        at android.view.ViewGroup.layout(ViewGroup.java:7277)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3712)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3164)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2225)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9126)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:999)
        at android.view.Choreographer.doCallbacks(Choreographer.java:797)
E/AndroidRuntime:     at android.view.Choreographer.doFrame(Choreographer.java:732)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:984)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8167)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
I/Process: Sending signal. PID: 22966 SIG: 9

[Sample] Sample fragment to test horizontal scroll

Should create a sample fragment to test horizontal scroll and use it inside the view pager. Was thinking of programming languages Alphabetically sorted.

Horizontal scroll is yet to be merged. It's currently present as a PR and can be tracked at #29

Issues with "Changes sample app to use view pager 2"

I've experienced various issues in the sample app, after the above commit, which is on the development branch as of 26 Nov 2020.

I put them all here in the same issue, because they might share the same root cause.

  1. When switching tabs he app will sometimes crash with the below stacktrace. Unfortunately I haven't found a way to reliably trigger this, but it does occur frequently.
  2. Display a tab, switch to another tab and then go back to the original tab, will stop the fast scroller handle from moving when the list is scrolled. The fast scroller handle still works. When using the Basic tab, this means that the fast scroller will not become visible when the list is scrolled.

2021-02-05 22:50:22.986 26158-26158/com.qtalk.sample D/RVFastScroller: Touch Action: 1
2021-02-05 22:50:24.590 26158-26158/com.qtalk.sample D/AndroidRuntime: Shutting down VM
2021-02-05 22:50:24.599 26158-26158/com.qtalk.sample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.qtalk.sample, PID: 26158
java.lang.IllegalStateException: Observer com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller$adapterDataObserver$1$1@e29f01d was not registered.
at android.database.Observable.unregisterObserver(Observable.java:69)
at androidx.recyclerview.widget.RecyclerView$Adapter.unregisterAdapterDataObserver(RecyclerView.java:7537)
at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.detachFastScrollerFromRecyclerView(RecyclerViewFastScroller.kt:964)
at com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller.onDetachedFromWindow(RecyclerViewFastScroller.kt:381)
at android.view.View.dispatchDetachedFromWindow(View.java:17456)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3681)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3673)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3673)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5227)
at android.view.ViewGroup.removeViewAt(ViewGroup.java:5174)
at androidx.recyclerview.widget.RecyclerView$5.removeViewAt(RecyclerView.java:915)
at androidx.recyclerview.widget.ChildHelper.removeViewAt(ChildHelper.java:168)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeViewAt(RecyclerView.java:8946)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleViewAt(RecyclerView.java:9217)
at androidx.recyclerview.widget.LinearLayoutManager.recycleChildren(LinearLayoutManager.java:1437)
at androidx.recyclerview.widget.LinearLayoutManager.recycleViewsFromEnd(LinearLayoutManager.java:1531)
at androidx.recyclerview.widget.LinearLayoutManager.recycleByLayoutState(LinearLayoutManager.java:1556)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1582)
at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1395)
at androidx.recyclerview.widget.LinearLayoutManager.scrollHorizontallyBy(LinearLayoutManager.java:1124)
at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1969)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5476)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1029)
at android.view.Choreographer.doCallbacks(Choreographer.java:841)
at android.view.Choreographer.doFrame(Choreographer.java:769)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1015)
at android.os.Handler.handleCallback(Handler.java:793)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:173)
at android.app.ActivityThread.main(ActivityThread.java:6698)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)

China's population has multiple numbers

When I scroll to China and while I am inside China's box, it shows a lot of different numbers of population when there should only be one number referring to China's population.

Screen Recording:
(URL : https://www.dropbox.com/s/bsty0kfhu9l8qrr/20210111_133818~2.mp4?dl=0)
This issue in depicted in the video from 0:09 to the end.

Sorry for the multiple issue creations. At first I wrote this issue in the same together with #47 but as they are not refered to the same problem I thought it was better to separate them.

I have experimented a lot with your app and I'm also trying to contribute with the grid layout for one of previous comments and I came up with this issue as well as #47 . Hope these help to make some improvement !

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.