package Ġcom . al . mond . fast sc roller Ċ Ċ import Ġandroid . view . Motion Event Ċ import Ġandroid . view . View Ċ import Ġandroid . view . animation . Alpha Animation Ċ import Ġandroid . view . animation . Animation Ċ import Ġandroidx . recyclerview . widget . Linear LayoutManager Ċ import Ġandroidx . recyclerview . widget . RecyclerView Ċ import Ġkotlin . random . Random ĊĊ Ċ /** Ċ Ġ* ĠFast Ġsc roller Ġsimple Ġversion . Ċ Ġ* Ċ Ġ* Ġ@ author Ġmon d . al Ċ Ġ* Ġ@ property Ġhandle View Ċ Ġ* Ġ@ param Ġfade Out Duration Ġhide Ġanimation Ġduration Ġtime Ġ( ms ) Ċ Ġ* Ġ@ param Ġhide Delay Millis Ġhide Ġanimation Ġdelay Ġtime Ġ( ms ) Ċ Ġ*/ Ċ Ċ class ĠFast Scroller ( ĊĠĠĠ Ġprivate Ġval Ġhandle View : ĠView , ĊĠĠĠ Ġprivate Ġval Ġbubble Listener : ĠB ubble Listener ? Ġ= Ġnull , ĊĠĠĠ Ġprivate Ġval Ġfade Out Duration : ĠLong Ġ= Ġ 3 0 0 . to Long (), ĊĠĠĠ Ġprivate Ġval Ġhide Delay Millis : ĠLong Ġ= Ġ 1 0 0 0 . to Long (), Ċ ) Ġ{ ĊĠĠĠ Ġprivate Ġlateinit Ġvar ĠlistView : ĠRecyclerView ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġlayout Manager : ĠLinearLayoutManager ĊĊĠĠĠ Ġprivate Ġvar Ġis Moved By Handle Drag Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġvar Ġrunnable Ġ= ĠRunnable Ġ{ Ġ} ĊĊĠĠĠ Ġprivate Ġvar ĠlistView Adapter : ĠB ubble Adapter ? Ġ= Ġnull ĊĊĠĠĠ Ġfun Ġbind ( re cyclerView : ĠRecyclerView ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( re cyclerView . layout Manager Ġ! is ĠLinearLayoutManager ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalArgumentException (" re cyclerView 's Ġlayout Manager Ġis Ġnot ĠLinearLayoutManager ") ĊĠĠĠĠĠĠĠ ĠlistView Ġ= Ġre cyclerView ĊĠĠĠĠĠĠĠ Ġlayout Manager Ġ= Ġre cyclerView . layout Manager Ġas ĠLinearLayoutManager ĊĠĠĠĠĠĠĠ Ġif Ġ( bubble Listener Ġ!= Ġnull Ġ&& Ġre cyclerView . adapter Ġis ĠB ubble Adapter ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbubble Listener . setVisible ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠlistView Adapter Ġ= Ġre cyclerView . adapter Ġas ĠB ubble Adapter ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġinit Handler Position Changed Listener () ĊĠĠĠĠĠĠĠ Ġinit Update Handle Position Listener () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinit Handler Position Changed Listener () Ġ{ ĊĠĠĠĠĠĠĠ Ġhandle View . setOn Touch Listener ( object Ġ: ĠView . On Touch Listener Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġm Down X : ĠFloat Ġ= Ġ 0 . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġm Down Y : ĠFloat Ġ= Ġ 0 . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġm Down X In Handle View : ĠFloat Ġ= Ġ 0 . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġm Down Y In Handle View : ĠFloat Ġ= Ġ 0 . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Touch ( handle View : ĠView , Ġevent : ĠMotion Event ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( handle View . alpha Ġ== Ġ 0 f ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( event . action ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Moved By Handle Drag Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down Y Ġ= Ġevent . raw Y ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down Y In Handle View Ġ= Ġevent . y ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ MOVE Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Moved By Handle Drag . not ()) Ġreturn Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġitem Count Ġ= ĠlistView . adapter ?. item Count Ġ?: Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpercent Ġ= Ġcalculate Handle Percent By ( handle View , Ġevent ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġadapter Position Ġ= Ġget Adapter Position ( percent , Ġitem Count ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Handle Position ( percent ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate RecyclerView Position ( adapter Position ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Bubble ( adapter Position ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ UP , ĠMotion Event . ACTION _ CANCEL Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Moved By Handle Drag Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down X Ġ= Ġ 0 f ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down Y Ġ= Ġ 0 f ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down X In Handle View Ġ= Ġ 0 f ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Down Y In Handle View Ġ= Ġ 0 f ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . perform Click () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbubble Listener ?. setVisible ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġreturn Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġfun Ġupdate Bubble ( adapter Position : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( bubble Listener Ġ!= Ġnull Ġ&& ĠlistView Adapter Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbubble Listener . setVisible ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbubble Listener . set Bubble ( list View Adapter !!. get Bubble Item ( adapter Position )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġfun Ġupdate RecyclerView Position ( adapter Position : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTr ick ! Ġby Ġa Ġthumb . Ġyou Ġhave Ġa Ġbig Ġfinger ! Ġ: ~ ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( list View . adapter ?. item Count !! Ġ> Ġ 3 0 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlayout Manager . scrollTo Position With Offset ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġadapter Position , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠRandom . nextInt ( handle View . height ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlayout Manager . scrollTo Position ( adapter Position ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġfun Ġget Adapter Position ( relative Pos : ĠFloat , Ġitem Count : ĠInt ) Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ( relative Pos Ġ* Ġitem Count ). getIn Min Ma X ( 0 , Ġitem Count Ġ- Ġ 1 ). toInt () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġfun Ġcalculate Handle Percent By ( handle : ĠView , Ġevent : ĠMotion Event ): ĠFloat Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġraw Y : ĠFloat Ġ= Ġevent . raw Y Ġ- Ġ( handle . getView Raw Y () Ġ+ Ġm Down Y In Handle View ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġraw Y Ġ/ Ġ( list View . height Ġ- Ġhandle . height ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinit Update Handle Position Listener () Ġ{ ĊĠĠĠĠĠĠĠ ĠlistView . add On Scroll Listener ( object Ġ: ĠRecyclerView . On Scroll Listener () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Sc rolled ( rv : ĠRecyclerView , Ġdx : ĠInt , Ġdy : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Moved By Handle Drag ) Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Handle Position ( get Percent ( rv )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġfun Ġget Percent ( rv : ĠRecyclerView ): ĠFloat Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġoffset : ĠInt Ġ= Ġrv . compute Vertical Scroll Offset () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġextent : ĠInt Ġ= Ġrv . compute Vertical Scroll Extent () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrange : ĠInt Ġ= Ġrv . compute Vertical Scroll Range () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġ( offset Ġ/ Ġ( range Ġ- Ġextent ). toFloat ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġupdate Handle Position ( percent : ĠFloat ) Ġ{ ĊĠĠĠĠĠĠĠ Ġset Handle View ( true ) ĊĠĠĠĠĠĠĠ Ġval Ġhandler Y Ġ= Ġget Handler Y ( percent ) ĊĠĠĠĠĠĠĠ Ġhandle View . y Ġ= Ġhandler Y ĊĠĠĠĠĠĠĠ Ġbubble Listener ?. setView Y ( handler Y ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġset Handle View ( visible : ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( visible Ġ|| Ġis Moved By Handle Drag ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . clear Animation () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( handle View . alpha Ġ!= Ġ 1 f ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . alpha Ġ= Ġ 1 f ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . remove Callbacks ( run nable ) ĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġclear Ġrunning Ġcallback ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrunnable Ġ= ĠRunnable Ġ{ Ġset Handle View ( false ) Ġ} ĠĠĠĠĠĠĠ Ġ// Ġset Ġnew Ġcallback ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . post Delayed ( run nable , Ġhide Delay Millis ) ĠĠ Ġ// Ġpost Ġdelayed Ġcall ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġanim Ġ= ĠAlpha Animation ( 1 f , Ġ 0 f ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġduration Ġ= Ġfade Out Duration ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfill After Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġset Animation Listener ( object Ġ: ĠAnimation . Animation Listener Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Animation End ( animation : ĠAnimation ?) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Moved By Handle Drag ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . alpha Ġ= Ġ 1 f Ġ// Ġcancel ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . alpha Ġ= Ġ 0 f Ġ// Ġend ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Animation Start ( animation : ĠAnimation ?) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Animation Repeat ( animation : ĠAnimation ?) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhandle View . start Animation ( anim ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġget Handler Y ( percent : ĠFloat ): ĠFloat Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġscrollbar Height Ġ= Ġ( handle View . parent Ġas ĠView ). height Ġ- Ġhandle View . height ĊĠĠĠĠĠĠĠ Ġreturn Ġ( percent Ġ* Ġscrollbar Height ). getIn Min Ma X ( 0 f , Ġscrollbar Height ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun ĠView . getView Raw Y (): ĠFloat Ġ{ ĊĠĠĠ Ġval Ġlocation Ġ= ĠInt Array ( 2 ) ĊĠĠĠ Ġlocation [ 0 ] Ġ= Ġ 0 ĊĠĠĠ Ġlocation [ 1 ] Ġ= Ġy . toInt () ĊĠĠĠ Ġ( parent Ġas ĠView ). getLocation In Window ( location ) ĊĠĠĠ Ġreturn Ġlocation [ 1 ]. toFloat () Ċ } Ċ Ċ private Ġfun ĠNumber . getIn Min Ma X ( min : ĠNumber , Ġmax : ĠNumber ): ĠFloat Ġ{ ĊĠĠĠ Ġval Ġminimum Ġ= Ġmin . toFloat (). coerce At Least ( this . toFloat ()) ĊĠĠĠ Ġreturn Ġminimum . coerce At Most ( max . toFloat ()) Ċ } ĊĊ Ċ interface ĠB ubble Adapter Ġ{ ĊĠĠĠ Ġfun Ġget Bubble Item ( adapter Position : ĠInt ): ĠString Ċ } Ċ Ċ interface ĠB ubble Listener Ġ{ ĊĠĠĠ Ġfun Ġset Bubble ( str : ĠString ) ĊĠĠĠ Ġfun Ġset View Y ( y : ĠFloat ) ĊĠĠĠ Ġfun Ġset Visible ( isVisible : ĠBoolean ) Ċ } Ċ