Created
May 3, 2023 09:26
-
-
Save nikclayton/6eddadbb864e1e541a91f6018fd8d803 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2023 Tusky Contributors | |
* | |
* This file is a part of Tusky. | |
* | |
* This program is free software; you can redistribute it and/or modify it under the terms of the | |
* GNU General Public License as published by the Free Software Foundation; either version 3 of the | |
* License, or (at your option) any later version. | |
* | |
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | |
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | |
* Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License along with Tusky; if not, | |
* see <http://www.gnu.org/licenses>. | |
*/ | |
package com.keylesspalace.tusky.view | |
import android.content.Context | |
import androidx.recyclerview.widget.LinearLayoutManager | |
import androidx.recyclerview.widget.RecyclerView | |
import kotlin.math.abs | |
/** | |
* [LinearLayoutManager] with a fixed size scroll bar thumb. | |
* | |
* The normal [LinearLayoutManager] handles scrolling through items of different heights by | |
* varying the size of the scrollbar thumb. | |
* | |
* This code maintains a fixed thumb size (relative to the number of items in the list), and | |
* adjusts the thumb position to compensate. | |
* | |
* Based on https://medium.com/dowjones/scrolling-in-android-custom-scroll-behavior-for-a-list-of-varying-height-7426f0f9046 | |
*/ | |
class FixedScrollThumbLinearLayoutManager(context: Context?) : LinearLayoutManager(context) { | |
init { | |
isSmoothScrollbarEnabled = false | |
} | |
override fun computeVerticalScrollExtent(state: RecyclerView.State): Int { | |
return if (childCount > 0) SMOOTH_VALUE * 3 else 0 | |
} | |
override fun computeVerticalScrollRange(state: RecyclerView.State): Int { | |
return ((itemCount - 1) * SMOOTH_VALUE).coerceAtLeast(0) | |
} | |
override fun computeVerticalScrollOffset(state: RecyclerView.State): Int { | |
val count = childCount | |
if (count <= 0) return 0 | |
if (findLastCompletelyVisibleItemPosition() == itemCount - 1) { | |
return ((itemCount - 1) * SMOOTH_VALUE).coerceAtLeast(0) | |
} | |
val firstPosition = findFirstVisibleItemPosition() | |
if (firstPosition == RecyclerView.NO_POSITION) return 0 | |
val view = findViewByPosition(firstPosition) ?: return 0 | |
val top = getDecoratedTop(view) | |
val height = getDecoratedMeasuredHeight(view) | |
val heightOfScreen = if (height <= 0) 0 else abs(SMOOTH_VALUE * top / height) | |
if (heightOfScreen == 0 && firstPosition > 0) return SMOOTH_VALUE * firstPosition - 1 | |
return (SMOOTH_VALUE * firstPosition) + heightOfScreen | |
} | |
companion object { | |
private const val SMOOTH_VALUE = 100 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment