@@ -119,12 +119,26 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
119
119
*/
120
120
var isSmoothScrollingEnabled = true
121
121
122
+ /* *
123
+ * When true, the scroll view stops on multiples of the scroll view's size
124
+ * when scrolling. This can be used for horizontal pagination. The default
125
+ * value is false.
126
+ */
127
+ var isPagingEnabled = false
128
+
129
+ var horizontalPagingThreshold = 0.5
130
+ var verticalPagingThreshold = 0.5
131
+
132
+
122
133
/* *
123
134
* When true, the ScrollView will try to lock to only vertical or horizontal
124
135
* scrolling while dragging.
125
136
*/
126
137
var isDirectionalLockEnabled = false
127
138
139
+ private var mActivelyScrolling = false
140
+
141
+ private var mPostTouchRunnable: Runnable ? = null
128
142
private val configuration = ViewConfiguration .get(context)
129
143
private var mTouchSlop = configuration.scaledTouchSlop
130
144
private var mMinimumVelocity = configuration.scaledMinimumFlingVelocity
@@ -204,6 +218,9 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
204
218
return scrollRange
205
219
}
206
220
221
+ val isHorizontal: Boolean
222
+ get() = childCount > 0 && getChildAt(0 ).width > (width - paddingLeft - paddingRight)
223
+
207
224
/* *
208
225
* Interface definition for a callback to be invoked when the scroll
209
226
* X or Y positions of a view change.
@@ -231,9 +248,10 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
231
248
initScrollView()
232
249
233
250
val a = context.obtainStyledAttributes(
234
- attrs, SCROLLVIEW_STYLEABLE , defStyleAttr, 0 )
251
+ attrs, R .styleable. SuperScrollView , defStyleAttr, 0 )
235
252
236
- isFillViewport = a.getBoolean(0 , false )
253
+ isFillViewport = a.getBoolean(R .styleable.SuperScrollView_isFillViewport , false )
254
+ isPagingEnabled = a.getBoolean(R .styleable.SuperScrollView_isPagingEnabled , false )
237
255
238
256
a.recycle()
239
257
@@ -466,6 +484,8 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
466
484
if (mOnScrollChangeListener != null ) {
467
485
mOnScrollChangeListener!! .onScrollChange(this , l, t, oldl, oldt)
468
486
}
487
+
488
+ mActivelyScrolling = true
469
489
}
470
490
471
491
override fun onMeasure (widthMeasureSpec : Int , heightMeasureSpec : Int ) {
@@ -563,10 +583,10 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
563
583
val canScrollVertical = computeVerticalScrollRange() > computeVerticalScrollExtent()
564
584
565
585
if (canScrollVertical) {
566
- val direction = if (event.isShiftPressed) View .FOCUS_UP else View .FOCUS_DOWN
586
+ val direction = if (event.isShiftPressed) View .FOCUS_UP else View .FOCUS_DOWN
567
587
pageScrollVertical(direction)
568
588
} else {
569
- val direction = if (event.isShiftPressed) View .FOCUS_LEFT else View .FOCUS_RIGHT
589
+ val direction = if (event.isShiftPressed) View .FOCUS_LEFT else View .FOCUS_RIGHT
570
590
pageScrollHorizontal(direction)
571
591
}
572
592
@@ -904,6 +924,7 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
904
924
}
905
925
mActivePointerId = INVALID_POINTER
906
926
endDrag()
927
+ handlePostTouchScrolling()
907
928
}
908
929
MotionEvent .ACTION_CANCEL -> {
909
930
if (mIsBeingDragged && childCount > 0 ) {
@@ -1204,6 +1225,7 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
1204
1225
1205
1226
return scrollAndFocusHorizontal(direction, mTempRect.left, mTempRect.right)
1206
1227
}
1228
+
1207
1229
/* *
1208
1230
*
1209
1231
* Handles scrolling in response to a "home/end" shortcut press. This
@@ -1459,6 +1481,42 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
1459
1481
return true
1460
1482
}
1461
1483
1484
+
1485
+ private fun handlePostTouchScrolling () {
1486
+ if (isPagingEnabled) {
1487
+ mActivelyScrolling = false
1488
+ mPostTouchRunnable = PostTouchRunnable ()
1489
+ ViewCompat .postOnAnimationDelayed(this , mPostTouchRunnable, MOMENTUM_DELAY )
1490
+ }
1491
+ }
1492
+
1493
+ /* *
1494
+ * This will smooth scroll us to the nearest page boundary
1495
+ * It currently just looks at where the content is relative to the page and slides to the nearest
1496
+ * page. It is intended to be run after we are done scrolling, and handling any momentum
1497
+ * scrolling.
1498
+ */
1499
+ private fun smoothScrollToPage (velocityX : Int = 0, velocityY : Int = 0) {
1500
+ val width = width
1501
+ val currentX = scrollX
1502
+ val predictedX = currentX + velocityX
1503
+ var hpage = currentX / width
1504
+ if (predictedX > hpage * width + width * horizontalPagingThreshold) {
1505
+ hpage + = 1
1506
+ }
1507
+
1508
+ val height = height
1509
+ val currentY = scrollY
1510
+ val preY = currentY + velocityY
1511
+ var vpage = currentY / height
1512
+ if (preY > vpage * height + height * verticalPagingThreshold) {
1513
+ vpage + = 1
1514
+ }
1515
+
1516
+ smoothScrollTo(hpage * width, vpage * height)
1517
+
1518
+ }
1519
+
1462
1520
/* *
1463
1521
* @return whether the descendant of this scroll view is scrolled off
1464
1522
* screen.
@@ -1951,19 +2009,24 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
1951
2009
* which means we want to scroll towards the top.
1952
2010
*/
1953
2011
fun fling (velocityX : Int , velocityY : Int ) {
1954
- if (childCount > 0 ) {
1955
- val view = getChildAt(0 )
1956
- val width = width - paddingRight - paddingLeft
1957
- val right = view.width
2012
+ if (isPagingEnabled) {
2013
+ smoothScrollToPage(velocityX, velocityY)
2014
+ } else {
2015
+ if (childCount > 0 ) {
2016
+ val view = getChildAt(0 )
2017
+ val width = width - paddingRight - paddingLeft
2018
+ val right = view.width
1958
2019
1959
- val height = height - paddingBottom - paddingTop
1960
- val bottom = view.height
2020
+ val height = height - paddingBottom - paddingTop
2021
+ val bottom = view.height
1961
2022
1962
- mScroller.fling(scrollX, scrollY, velocityX, velocityY, 0 , max(0 , right - width), 0 ,
1963
- max(0 , bottom - height), width / 2 , height / 2 )
2023
+ mScroller.fling(scrollX, scrollY, velocityX, velocityY, 0 , max(0 , right - width), 0 ,
2024
+ max(0 , bottom - height), width / 2 , height / 2 )
1964
2025
1965
- ViewCompat .postInvalidateOnAnimation(this )
2026
+ ViewCompat .postInvalidateOnAnimation(this )
2027
+ }
1966
2028
}
2029
+ handlePostTouchScrolling()
1967
2030
}
1968
2031
1969
2032
private fun flingWithNestedDispatch (velocityX : Int , velocityY : Int ) {
@@ -2158,6 +2221,30 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
2158
2221
}
2159
2222
}
2160
2223
2224
+ inner class PostTouchRunnable : Runnable {
2225
+ private var mSnappingToPage = false
2226
+
2227
+ override fun run () {
2228
+ if (mActivelyScrolling) {
2229
+ mActivelyScrolling = false
2230
+ ViewCompat .postOnAnimationDelayed(this @SuperScrollView, this , MOMENTUM_DELAY )
2231
+
2232
+ } else {
2233
+ var doneWithAllScrolling = true
2234
+ if (isPagingEnabled && ! mSnappingToPage) {
2235
+ mSnappingToPage = true
2236
+ smoothScrollToPage()
2237
+ doneWithAllScrolling = false
2238
+ }
2239
+ if (doneWithAllScrolling) {
2240
+ mPostTouchRunnable = null
2241
+ } else {
2242
+ ViewCompat .postOnAnimationDelayed(this @SuperScrollView, this , MOMENTUM_DELAY )
2243
+ }
2244
+ }
2245
+ }
2246
+ }
2247
+
2161
2248
internal class AccessibilityDelegate : AccessibilityDelegateCompat () {
2162
2249
override fun performAccessibilityAction (host : View , action : Int , arguments : Bundle ): Boolean {
2163
2250
if (super .performAccessibilityAction(host, action, arguments)) {
@@ -2243,6 +2330,8 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
2243
2330
2244
2331
private const val TAG = " SuperScrollView"
2245
2332
2333
+ const val MOMENTUM_DELAY = 20L
2334
+
2246
2335
/* *
2247
2336
* Sentinel value for no current active pointer.
2248
2337
* Used by [.mActivePointerId].
@@ -2251,8 +2340,6 @@ class SuperScrollView @JvmOverloads constructor(context: Context, attrs: Attribu
2251
2340
2252
2341
private val ACCESSIBILITY_DELEGATE = AccessibilityDelegate ()
2253
2342
2254
- private val SCROLLVIEW_STYLEABLE = intArrayOf(android.R .attr.fillViewport)
2255
-
2256
2343
/* *
2257
2344
* Return true if child is a descendant of parent, (or equal to the parent).
2258
2345
*/
0 commit comments