1.迁移到AndroidX

2.修改支持无限循环滑动
This commit is contained in:
leafwai
2022-02-17 15:40:13 +08:00
parent 334e6d26bd
commit 046e67bf78
17 changed files with 159 additions and 153 deletions

3
.idea/misc.xml generated
View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="NullableNotNullManager"> <component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" /> <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
@@ -25,7 +26,7 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

10
.idea/modules.xml generated
View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/StackLayoutManager.iml" filepath="$PROJECT_DIR$/StackLayoutManager.iml" />
<module fileurl="file://$PROJECT_DIR$/StackLayoutManager/StackLayoutManager-StackLayoutManager.iml" filepath="$PROJECT_DIR$/StackLayoutManager/StackLayoutManager-StackLayoutManager.iml" />
<module fileurl="file://$PROJECT_DIR$/sample/sample.iml" filepath="$PROJECT_DIR$/sample/sample.iml" />
</modules>
</component>
</project>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -3,15 +3,15 @@ apply plugin: 'kotlin-android'
apply plugin: 'com.novoda.bintray-release' apply plugin: 'com.novoda.bintray-release'
android { android {
compileSdkVersion 27 compileSdkVersion 31
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 21
targetSdkVersion 27 targetSdkVersion 31
versionCode 6 versionCode 6
versionName "1.0.5" versionName "1.0.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
} }
@@ -30,7 +30,7 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'androidx.recyclerview:recyclerview:1.2.1'
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -2,6 +2,7 @@ package com.littlemango.stacklayoutmanager
import android.view.View import android.view.View
import com.littlemango.stacklayoutmanager.StackLayoutManager.ScrollOrientation import com.littlemango.stacklayoutmanager.StackLayoutManager.ScrollOrientation
import kotlin.math.pow
class DefaultAnimation(scrollOrientation: ScrollOrientation, visibleCount: Int) : StackAnimation(scrollOrientation, visibleCount) { class DefaultAnimation(scrollOrientation: ScrollOrientation, visibleCount: Int) : StackAnimation(scrollOrientation, visibleCount) {
@@ -72,8 +73,8 @@ class DefaultAnimation(scrollOrientation: ScrollOrientation, visibleCount: Int)
scale = 1 - ((1 - mOutScale) * firstMovePercent) scale = 1 - ((1 - mOutScale) * firstMovePercent)
rotation = mOutRotation * firstMovePercent rotation = mOutRotation * firstMovePercent
} else { } else {
val minScale = (Math.pow(mScale.toDouble(), position.toDouble())).toFloat() val minScale = (mScale.toDouble().pow(position.toDouble())).toFloat()
val maxScale = (Math.pow(mScale.toDouble(), (position - 1).toDouble())).toFloat() val maxScale = (mScale.toDouble().pow((position - 1).toDouble())).toFloat()
scale = minScale + (maxScale - minScale) * firstMovePercent scale = minScale + (maxScale - minScale) * firstMovePercent
//只对最后一个 item 做透明度变化 //只对最后一个 item 做透明度变化
if (position == mVisibleCount) { if (position == mVisibleCount) {

View File

@@ -47,12 +47,18 @@ class DefaultLayout(scrollOrientation: StackLayoutManager.ScrollOrientation,
private fun getFirstVisibleItemLeft(): Int { private fun getFirstVisibleItemLeft(): Int {
return when(mScrollOrientation) { return when(mScrollOrientation) {
StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> mStartMargin - mScrollOffset % mWidth StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> {
var offset = mScrollOffset % mWidth
if (offset < 0) offset += mWidth
mStartMargin - offset
}
StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> { StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> {
return if (mScrollOffset % mWidth == 0) { return if (mScrollOffset % mWidth == 0) {
mStartMargin mStartMargin
} else { } else {
mStartMargin + (mWidth - mScrollOffset % mWidth) var offset = mScrollOffset % mWidth
if (offset < 0) offset += mWidth
mStartMargin + (mWidth - offset)
} }
} }
else -> mWidthSpace / 2 else -> mWidthSpace / 2
@@ -61,12 +67,18 @@ class DefaultLayout(scrollOrientation: StackLayoutManager.ScrollOrientation,
private fun getFirstVisibleItemTop(): Int { private fun getFirstVisibleItemTop(): Int {
return when(mScrollOrientation) { return when(mScrollOrientation) {
StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> mStartMargin - mScrollOffset % mHeight StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> {
var offset = mScrollOffset % mHeight
if (offset < 0) offset += mHeight
mStartMargin - offset
}
StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> { StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> {
return if (mScrollOffset % mHeight == 0) { return if (mScrollOffset % mHeight == 0) {
mStartMargin mStartMargin
} else { } else {
mStartMargin + (mHeight - mScrollOffset % mHeight) var offset = mScrollOffset % mHeight
if (offset < 0) offset += mHeight
mStartMargin + (mHeight - offset)
} }
} }
else -> mHeightSpace / 2 else -> mHeightSpace / 2

View File

@@ -1,19 +1,23 @@
package com.littlemango.stacklayoutmanager package com.littlemango.stacklayoutmanager
import android.support.annotation.IntRange import androidx.annotation.IntRange
import android.support.v7.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING
import android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import kotlin.math.ceil
import kotlin.math.floor
class StackLayoutManager(scrollOrientation: ScrollOrientation, class StackLayoutManager(
scrollOrientation: ScrollOrientation,
visibleCount: Int, visibleCount: Int,
animation: Class<out StackAnimation>, animation: Class<out StackAnimation>,
layout: Class<out StackLayout>) : RecyclerView.LayoutManager() { layout: Class<out StackLayout>
private enum class FlingOrientation{NONE, LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP} ) : RecyclerView.LayoutManager() {
private enum class FlingOrientation { NONE, LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP }
enum class ScrollOrientation{LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP} enum class ScrollOrientation { LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP }
private var mVisibleItemCount = visibleCount private var mVisibleItemCount = visibleCount
@@ -26,6 +30,7 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
//做动画的组件,支持自定义 //做动画的组件,支持自定义
private var mAnimation: StackAnimation? = null private var mAnimation: StackAnimation? = null
//做布局的组件,支持自定义 //做布局的组件,支持自定义
private var mLayout: StackLayout? = null private var mLayout: StackLayout? = null
@@ -78,7 +83,7 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
* @param velocity 默认值是2000. * @param velocity 默认值是2000.
*/ */
fun setPagerFlingVelocity(@IntRange(from = 0, to = Int.MAX_VALUE.toLong()) velocity: Int) { fun setPagerFlingVelocity(@IntRange(from = 0, to = Int.MAX_VALUE.toLong()) velocity: Int) {
mPagerFlingVelocity = Math.min(Int.MAX_VALUE, Math.max(0, velocity)) mPagerFlingVelocity = Int.MAX_VALUE.coerceAtMost(0.coerceAtLeast(velocity))
} }
/** /**
@@ -92,8 +97,8 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
* 设置recyclerView 静止时候可见的itemView 个数. * 设置recyclerView 静止时候可见的itemView 个数.
* @param count 可见 itemView默认为3 * @param count 可见 itemView默认为3
*/ */
fun setVisibleItemCount(@IntRange(from = 1, to = Long.MAX_VALUE)count: Int) { fun setVisibleItemCount(@IntRange(from = 1, to = Long.MAX_VALUE) count: Int) {
mVisibleItemCount = Math.min(itemCount - 1, Math.max(1, count)) mVisibleItemCount = (itemCount - 1).coerceAtMost(1.coerceAtLeast(count))
mAnimation?.setVisibleCount(mVisibleItemCount) mAnimation?.setVisibleCount(mVisibleItemCount)
} }
@@ -157,11 +162,11 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
if (width == 0 || height == 0) { if (width == 0 || height == 0) {
return 0 return 0
} }
return when(mScrollOrientation) { return when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT -> Math.floor((mScrollOffset * 1.0 / width)).toInt() ScrollOrientation.RIGHT_TO_LEFT -> floor((mScrollOffset * 1.0 / width)).toInt()
ScrollOrientation.LEFT_TO_RIGHT -> itemCount - 1 - Math.ceil((mScrollOffset * 1.0 / width)).toInt() ScrollOrientation.LEFT_TO_RIGHT -> itemCount - 1 - ceil((mScrollOffset * 1.0 / width)).toInt()
ScrollOrientation.BOTTOM_TO_TOP -> Math.floor((mScrollOffset * 1.0 / height)).toInt() ScrollOrientation.BOTTOM_TO_TOP -> floor((mScrollOffset * 1.0 / height)).toInt()
ScrollOrientation.TOP_TO_BOTTOM -> itemCount - 1 - Math.ceil((mScrollOffset * 1.0 / height)).toInt() ScrollOrientation.TOP_TO_BOTTOM -> itemCount - 1 - ceil((mScrollOffset * 1.0 / height)).toInt()
} }
} }
@@ -179,14 +184,17 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
constructor() : this(ScrollOrientation.RIGHT_TO_LEFT) constructor() : this(ScrollOrientation.RIGHT_TO_LEFT)
init { init {
mScrollOffset = when(mScrollOrientation) { mScrollOffset = when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.BOTTOM_TO_TOP -> 0 ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.BOTTOM_TO_TOP -> 0
else -> Int.MAX_VALUE else -> Int.MAX_VALUE
} }
if (StackAnimation::class.java.isAssignableFrom(animation)) { if (StackAnimation::class.java.isAssignableFrom(animation)) {
try { try {
val cla = animation.getDeclaredConstructor(ScrollOrientation::class.java, Int::class.javaPrimitiveType) val cla = animation.getDeclaredConstructor(
ScrollOrientation::class.java,
Int::class.javaPrimitiveType
)
mAnimation = cla.newInstance(scrollOrientation, visibleCount) as StackAnimation mAnimation = cla.newInstance(scrollOrientation, visibleCount) as StackAnimation
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
@@ -194,7 +202,11 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
if (StackLayout::class.java.isAssignableFrom(layout)) { if (StackLayout::class.java.isAssignableFrom(layout)) {
try { try {
val cla = layout.getDeclaredConstructor(ScrollOrientation::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType) val cla = layout.getDeclaredConstructor(
ScrollOrientation::class.java,
Int::class.javaPrimitiveType,
Int::class.javaPrimitiveType
)
mLayout = cla.newInstance(scrollOrientation, visibleCount, 30) as StackLayout mLayout = cla.newInstance(scrollOrientation, visibleCount, 30) as StackLayout
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
@@ -203,8 +215,10 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams { override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
return RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, return RecyclerView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT) ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
} }
override fun onAttachedToWindow(view: RecyclerView) { override fun onAttachedToWindow(view: RecyclerView) {
@@ -212,7 +226,7 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
mOnFlingListener = object : RecyclerView.OnFlingListener() { mOnFlingListener = object : RecyclerView.OnFlingListener() {
override fun onFling(velocityX: Int, velocityY: Int): Boolean { override fun onFling(velocityX: Int, velocityY: Int): Boolean {
if (mPagerMode) { if (mPagerMode) {
when(mScrollOrientation) { when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT -> { ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT -> {
mFlingOrientation = when { mFlingOrientation = when {
velocityX > mPagerFlingVelocity -> FlingOrientation.RIGHT_TO_LEFT velocityX > mPagerFlingVelocity -> FlingOrientation.RIGHT_TO_LEFT
@@ -299,11 +313,19 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
} }
override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State): Int { override fun scrollHorizontallyBy(
dx: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
): Int {
return handleScrollBy(dx, recycler) return handleScrollBy(dx, recycler)
} }
override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int { override fun scrollVerticallyBy(
dy: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State?
): Int {
return handleScrollBy(dy, recycler) return handleScrollBy(dy, recycler)
} }
@@ -315,7 +337,11 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
requestLayout() requestLayout()
} }
override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State?, position: Int) { override fun smoothScrollToPosition(
recyclerView: RecyclerView,
state: RecyclerView.State?,
position: Int
) {
if (position < 0 || position >= itemCount) { if (position < 0 || position >= itemCount) {
throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]") throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]")
} }
@@ -337,59 +363,51 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
private fun handleScrollBy(offset: Int, recycler: RecyclerView.Recycler): Int { private fun handleScrollBy(offset: Int, recycler: RecyclerView.Recycler): Int {
//期望值,不得超过最大最小值,所以期望值不一定等于实际值 mScrollOffset += offset
val expectOffset = mScrollOffset + offset
//实际值
mScrollOffset = getValidOffset(expectOffset)
//实际偏移超过最大最小值之后的偏移都应该是0该值作为返回值否则在极限位置进行滚动的时候不会出现弹性阴影
val exactMove = mScrollOffset - expectOffset + offset
if (exactMove == 0) {
//itemViews 位置都不会改变,直接 return
return 0
}
detachAndScrapAttachedViews(recycler) detachAndScrapAttachedViews(recycler)
loadItemView(recycler) loadItemView(recycler)
return exactMove
return offset
} }
private fun loadItemView(recycler: RecyclerView.Recycler) { private fun loadItemView(recycler: RecyclerView.Recycler) {
val firstVisiblePosition = getFirstVisibleItemPosition() val firstVisiblePosition = getFirstVisibleItemPosition()
val lastVisiblePosition = getLastVisibleItemPosition() val lastVisiblePosition = getFirstVisibleItemPosition() + mVisibleItemCount - 1
//位移百分比 //位移百分比
val movePercent = getFirstVisibleItemMovePercent() var movePercent = getFirstVisibleItemMovePercent()
if (movePercent < 0) movePercent += 1
for (i in lastVisiblePosition downTo firstVisiblePosition) { for (i in (mVisibleItemCount - 1) downTo 0) {
val view = recycler.getViewForPosition(i) var position = (firstVisiblePosition + i) % itemCount
if (position < 0) {
position += itemCount
}
val view = recycler.getViewForPosition(position)
//添加到recycleView 中 //添加到recycleView 中
addView(view) addView(view)
//测量 //测量
measureChild(view, 0, 0) measureChild(view, 0, 0)
//布局 //布局
mLayout?.doLayout(this, mScrollOffset, movePercent, view, i - firstVisiblePosition) mLayout?.doLayout(this, mScrollOffset, movePercent, view, i)
//做动画 //做动画
mAnimation?.doAnimation(movePercent, view, i - firstVisiblePosition) mAnimation?.doAnimation(movePercent, view, i)
} }
//尝试更新当前item的位置并通知外界 //尝试更新当前item的位置并通知外界
updatePositionRecordAndNotify(firstVisiblePosition) updatePositionRecordAndNotify(firstVisiblePosition)
//重用 //重用
if (firstVisiblePosition - 1 >= 0) { val lastPosition = firstVisiblePosition - 1
val view = recycler.getViewForPosition(firstVisiblePosition - 1) val lastView =
resetViewAnimateProperty(view) recycler.getViewForPosition(if (lastPosition >= 0 || lastPosition % itemCount == 0) lastPosition % itemCount else lastPosition % itemCount + itemCount)
removeAndRecycleView(view, recycler) resetViewAnimateProperty(lastView)
} removeAndRecycleView(lastView, recycler)
if (lastVisiblePosition + 1 < itemCount) {
val view = recycler.getViewForPosition(lastVisiblePosition + 1) val nextPosition = lastVisiblePosition + 1
resetViewAnimateProperty(view) val nextView =
removeAndRecycleView(view, recycler) recycler.getViewForPosition(if (nextPosition >= 0 || nextPosition % itemCount == 0) nextPosition % itemCount else nextPosition % itemCount + itemCount)
} resetViewAnimateProperty(nextView)
removeAndRecycleView(nextView, recycler)
} }
private fun resetViewAnimateProperty(view: View) { private fun resetViewAnimateProperty(view: View) {
@@ -405,9 +423,13 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
scrollToCenter(targetPosition, view, true) scrollToCenter(targetPosition, view, true)
} }
private fun scrollToCenter(targetPosition: Int, recyclerView: RecyclerView, animation: Boolean) { private fun scrollToCenter(
targetPosition: Int,
recyclerView: RecyclerView,
animation: Boolean
) {
val targetOffset = getPositionOffset(targetPosition) val targetOffset = getPositionOffset(targetPosition)
when(mScrollOrientation) { when (mScrollOrientation) {
ScrollOrientation.LEFT_TO_RIGHT, ScrollOrientation.RIGHT_TO_LEFT -> { ScrollOrientation.LEFT_TO_RIGHT, ScrollOrientation.RIGHT_TO_LEFT -> {
if (animation) { if (animation) {
recyclerView.smoothScrollBy(targetOffset - mScrollOffset, 0) recyclerView.smoothScrollBy(targetOffset - mScrollOffset, 0)
@@ -426,14 +448,15 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
private fun getValidOffset(expectOffset: Int): Int { private fun getValidOffset(expectOffset: Int): Int {
return when(mScrollOrientation) { return when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT -> Math.max(Math.min(width * (itemCount - 1), expectOffset), 0) ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT ->
else -> Math.max(Math.min(height * (itemCount - 1), expectOffset), 0) (width * (itemCount - 1)).coerceAtMost(expectOffset).coerceAtLeast(0)
else -> (height * (itemCount - 1)).coerceAtMost(expectOffset).coerceAtLeast(0)
} }
} }
private fun getPositionOffset(position: Int): Int { private fun getPositionOffset(position: Int): Int {
return when(mScrollOrientation) { return when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT -> position * width ScrollOrientation.RIGHT_TO_LEFT -> position * width
ScrollOrientation.LEFT_TO_RIGHT -> (itemCount - 1 - position) * width ScrollOrientation.LEFT_TO_RIGHT -> (itemCount - 1 - position) * width
ScrollOrientation.BOTTOM_TO_TOP -> position * height ScrollOrientation.BOTTOM_TO_TOP -> position * height
@@ -441,15 +464,6 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
} }
} }
private fun getLastVisibleItemPosition(): Int {
val firstVisiblePosition = getFirstVisibleItemPosition()
return if (firstVisiblePosition + mVisibleItemCount > itemCount - 1) {
itemCount - 1
} else {
firstVisiblePosition + mVisibleItemCount
}
}
private fun getFirstVisibleItemMovePercent(): Float { private fun getFirstVisibleItemMovePercent(): Float {
if (width == 0 || height == 0) { if (width == 0 || height == 0) {
return 0f return 0f
@@ -480,7 +494,7 @@ class StackLayoutManager(scrollOrientation: ScrollOrientation,
//当是 Fling 触发的时候 //当是 Fling 触发的时候
val triggerOrientation = mFlingOrientation val triggerOrientation = mFlingOrientation
mFlingOrientation = FlingOrientation.NONE mFlingOrientation = FlingOrientation.NONE
when(mScrollOrientation) { when (mScrollOrientation) {
ScrollOrientation.RIGHT_TO_LEFT -> { ScrollOrientation.RIGHT_TO_LEFT -> {
if (triggerOrientation == FlingOrientation.RIGHT_TO_LEFT) { if (triggerOrientation == FlingOrientation.RIGHT_TO_LEFT) {
return position + 1 return position + 1

View File

@@ -1,13 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.2.60' ext.kotlin_version = '1.6.10'
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.4' classpath 'com.android.tools.build:gradle:4.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.novoda:bintray-release:0.8.1' classpath 'com.novoda:bintray-release:0.8.1'
} }
@@ -29,4 +29,4 @@ allprojects {
task clean(type: Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }
tasks.getByPath(":StackLayoutManager:releaseAndroidJavadocs").enabled = false //tasks.getByPath(":StackLayoutManager:releaseAndroidJavadocs").enabled = false

View File

@@ -6,6 +6,8 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit

View File

@@ -1,6 +1,6 @@
#Thu Jun 28 17:28:50 CST 2018 #Thu Feb 17 14:43:36 CST 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip zipStoreBase=GRADLE_USER_HOME

View File

@@ -5,14 +5,14 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 27 compileSdkVersion 31
defaultConfig { defaultConfig {
applicationId "com.littlemango.stacklayoutmanagermaster" applicationId "com.littlemango.stacklayoutmanagermaster"
minSdkVersion 19 minSdkVersion 21
targetSdkVersion 27 targetSdkVersion 31
versionCode 6 versionCode 6
versionName "1.0.5" versionName "1.0.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
} }
buildTypes { buildTypes {
release { release {
@@ -22,19 +22,19 @@ android {
} }
} }
ext.kotlin_version = '1.2.60' ext.kotlin_version = '1.6.10'
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.android.support:cardview-v7:27.1.1' implementation 'androidx.cardview:cardview:1.0.0'
implementation project(':StackLayoutManager') implementation project(':StackLayoutManager')
implementation 'com.afollestad.material-dialogs:core:0.9.6.0' implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
implementation 'com.android.support:design:27.1.1' implementation 'com.google.android.material:material:1.5.0'
} }

View File

@@ -1,13 +1,11 @@
package com.littlemango.stacklayoutmanagermaster package com.littlemango.stacklayoutmanagermaster
import android.support.test.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4
import android.support.test.runner.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *
@@ -18,7 +16,7 @@ class ExampleInstrumentedTest {
@Test @Test
fun useAppContext() { fun useAppContext() {
// Context of the app under test. // Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext() val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.littlemango.stacklayoutmanagermaster", appContext.packageName) assertEquals("com.littlemango.stacklayoutmanagermaster", appContext.packageName)
} }
} }

View File

@@ -9,7 +9,8 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".MainActivity"> <activity android:name=".MainActivity"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -1,6 +1,5 @@
package com.littlemango.stacklayoutmanagermaster; package com.littlemango.stacklayoutmanagermaster;
import android.support.v7.widget.LinearLayoutManager;
import android.view.View; import android.view.View;
import com.littlemango.stacklayoutmanager.StackAnimation; import com.littlemango.stacklayoutmanager.StackAnimation;

View File

@@ -1,11 +1,11 @@
package com.littlemango.stacklayoutmanagermaster; package com.littlemango.stacklayoutmanagermaster;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -15,7 +15,7 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.littlemango.stacklayoutmanager.StackLayoutManager; import com.littlemango.stacklayoutmanager.StackLayoutManager;
import com.littlemango.stacklayoutmanager.StackLayoutManager.ScrollOrientation;
import java.util.Random; import java.util.Random;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
@@ -66,22 +66,22 @@ public class MainActivity extends AppCompatActivity {
resetRandom(); resetRandom();
break; break;
case 2: case 2:
mStackLayoutManager = new StackLayoutManager(ScrollOrientation.LEFT_TO_RIGHT); mStackLayoutManager = new StackLayoutManager(StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT);
mRecyclerView.setLayoutManager(mStackLayoutManager); mRecyclerView.setLayoutManager(mStackLayoutManager);
getSupportActionBar().setTitle("Picture 0"); getSupportActionBar().setTitle("Picture 0");
break; break;
case 3: case 3:
mStackLayoutManager = new StackLayoutManager(ScrollOrientation.RIGHT_TO_LEFT); mStackLayoutManager = new StackLayoutManager(StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT);
mRecyclerView.setLayoutManager(mStackLayoutManager); mRecyclerView.setLayoutManager(mStackLayoutManager);
getSupportActionBar().setTitle("Picture 0"); getSupportActionBar().setTitle("Picture 0");
break; break;
case 4: case 4:
mStackLayoutManager = new StackLayoutManager(ScrollOrientation.TOP_TO_BOTTOM); mStackLayoutManager = new StackLayoutManager(StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM);
mRecyclerView.setLayoutManager(mStackLayoutManager); mRecyclerView.setLayoutManager(mStackLayoutManager);
getSupportActionBar().setTitle("Picture 0"); getSupportActionBar().setTitle("Picture 0");
break; break;
case 5: case 5:
mStackLayoutManager = new StackLayoutManager(ScrollOrientation.BOTTOM_TO_TOP); mStackLayoutManager = new StackLayoutManager(StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP);
mRecyclerView.setLayoutManager(mStackLayoutManager); mRecyclerView.setLayoutManager(mStackLayoutManager);
getSupportActionBar().setTitle("Picture 0"); getSupportActionBar().setTitle("Picture 0");
break; break;

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycleView" android:id="@+id/recycleView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<android.support.design.widget.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatButton" android:id="@+id/floatButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -22,4 +22,4 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="270dp" android:layout_width="270dp"
android:layout_height="400dp" android:layout_height="400dp"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -17,4 +17,4 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:textSize="50sp"/> android:textSize="50sp"/>
</android.support.v7.widget.CardView> </androidx.cardview.widget.CardView>