当前位置: 首页 > 知识库问答 >
问题:

为什么回收站视图的平滑滚动不能很好地与一些插值类配合使用?

云俊美
2023-03-14

在努力使一个好的

出于某种原因,我尝试的所有插值器类(此处提供了插图)似乎都不允许项目进入RecyclerView或在其上反弹。

更具体地说,我尝试过过冲插值器 ,反弹插值器和其他一些类似的。我甚至尝试了PrespeciousOvershootInterpolator。在大多数情况下,它执行简单的滚动,没有特殊效果。在ProspectOvershootInterpolator上,它甚至不会滚动...

以下是我制作的POC的代码,以显示问题:

主活动. kt

class MainActivity : AppCompatActivity() {
    val handler = Handler()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val itemSize = resources.getDimensionPixelSize(R.dimen.list_item_size)
        val itemsCount = 6
        recyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
            override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
                val imageView = ImageView(this@MainActivity)
                imageView.setImageResource(android.R.drawable.sym_def_app_icon)
                imageView.layoutParams = RecyclerView.LayoutParams(itemSize, itemSize)
                return object : RecyclerView.ViewHolder(imageView) {}
            }

            override fun getItemCount(): Int = itemsCount

            override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            }
        }
        val itemToGoTo = Math.min(3, itemsCount - 1)
        val scrollValue = itemSize * itemToGoTo
        recyclerView.post {
            recyclerView.scrollBy(scrollValue, 0)
            handler.postDelayed({
                recyclerView.smoothScrollBy(-scrollValue, 0, BounceInterpolator())
            }, 500L)
        }
    }
}

activity_main.xml

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView" 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="@dimen/list_item_size" android:orientation="horizontal"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>

梯度文件

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
    implementation 'androidx.core:core-ktx:1.0.0-rc02'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
    implementation 'androidx.recyclerview:recyclerview:1.0.0-rc02'
}

这是它如何寻找BounceInterpolator的动画,正如您所看到的,它根本不会反弹:

此处提供 POC 项目html" target="_blank">示例

为什么它不能按预期工作,我如何修复它?

RecyclerView能否与用于滚动的插值器配合使用?

编辑:似乎这是一个错误,因为我不能使用任何“有趣”的插值器进行RecyclerView滚动,所以我在这里报告了这个问题。

共有3个答案

於鸿羲
2023-03-14

您需要以某种方式启用覆盖反弹。

一个可能的解决方案是使用https://github.com/chthai64/overscroll-bouncy-android

将其包含在您的项目中

implementation 'com.chauthai.overscroll:overscroll-bouncy:0.1.1'

然后在您的POV中,在activity_main中更改RecyclerView。xmlcom.chauthai.overscroll.RecycleWebouncy

<?xml version="1.0" encoding="utf-8"?>
<com.chauthai.overscroll.RecyclerViewBouncy
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="@dimen/list_item_size"
    android:orientation="horizontal"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>

进行此更改后,您将在应用中看到退回邮件。

施默
2023-03-14

就像我说的,我不会真诚地期望发布候选(回收器视图:1.0.0-rc02在您的情况下)能够正常工作而不会引起任何问题,因为它已经在开发中。

    < li >使用第三方库可能可行,但我不这么认为,因为他们刚刚引入了< code>androidx依赖项,而且他们已经在开发中,还不够稳定,无法供其他开发人员使用。

更新谷歌开发者的答案:

我们已经将此问题传递给开发团队,并将在有更多信息时更新此问题。

所以,最好等待新的更新。

公冶峰
2023-03-14

我会看看谷歌的支持动画包。具体 https://developer.android.com/reference/android/support/animation/DynamicAnimation#SCROLL_X

它看起来像这样:

SpringAnimation(recyclerView, DynamicAnimation.SCROLL_X, 0f)
        .setStartVelocity(1000)
        .start()

更新:

看起来这也不起作用。我查看了RecyclerView的一些源代码,反弹插值器不起作用的原因是RecyclizerView没有正确使用插值器。有一个调用来计算ScrollDuration对插值器的调用,然后以秒为单位获取原始动画时间,而不是作为总动画时间百分比的值。这个值也不是完全可预测的,我测试了几个值,看到了100ms - 250ms的任何地方。无论如何,从我所看到的,你有两个选择(我已经测试了两个)

>

  • 使用其他库,如 https://github.com/EverythingMe/overscroll-décor

    实现您自己的属性并使用Spring动画:

    
    class ScrollXProperty : FloatPropertyCompat("scrollX") {
    
        override fun setValue(obj: RecyclerView, value: Float) {
            obj.scrollBy(value.roundToInt() - getValue(obj).roundToInt(), 0)
        }
    
        override fun getValue(obj: RecyclerView): Float =
                obj.computeHorizontalScrollOffset().toFloat()
    }
    

    然后,在您的退回中,将对< code>smoothScrollBy的调用替换为:

    SpringAnimation(recyclerView, ScrollXProperty())
        .setSpring(SpringForce()
                .setFinalPosition(0f)
                .setStiffness(SpringForce.STIFFNESS_LOW)
                .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY))
        .start()
    

    更新:

    第二个解决方案是开箱即用的,对你的回收器视图没有任何改变,是我完全编写和测试的。

    有关插值器的更多信息,smoothScrollBy与插值器不兼容(可能是一个bug)。使用插值器时,基本上将0-1值映射到另一个值,该值是动画的乘数。示例:t=0,interp(0)=0意味着在动画开始时,该值应与动画开始时的值相同,t=。5,interp(。25表示元素将以1/4的方式设置动画,等等。反弹插值器基本上返回值

    解决方案2正在做的是使用spring animator,但是需要更新scroll。SCROLL_X不工作的原因是RecyclerView实际上并不滚动(这是我的错误)。它根据不同的计算来计算视图应该在哪里,这就是为什么您需要调用< code > computeHorizontalScrollOffset 。< code>ScrollXProperty允许您更改RecyclerView的水平滚动,就像您在ScrollView中指定< code>scrollX属性一样,它基本上是一个适配器。RecyclerViews不支持滚动到特定的像素偏移量,只支持平滑滚动,但是SpringAnimation已经为你平滑地做到了,所以我们不需要它。相反,我们希望滚动到一个离散的位置。见https://Android . Google source . com/platform/frameworks/support//247185 b 98675 b 09 C5 e 98 c 87448 DD 24 AEF 4d fc9 d/V7/recycle view/src/Android/support/V7/widget/recycle view . Java # 387

    更新:

    以下是我用来测试 https://github.com/yperess/StackOverflow/tree/52148251

    更新:

    使用插值器有相同的概念:

    class ScrollXProperty : Property<RecyclerView, Int>(Int::class.java, "horozontalOffset") {
        override fun get(`object`: RecyclerView): Int =
                `object`.computeHorizontalScrollOffset()
    
        override fun set(`object`: RecyclerView, value: Int) {
            `object`.scrollBy(value - get(`object`), 0)
        }
    }
    
    ObjectAnimator.ofInt(recycler_view, ScrollXProperty(), 0).apply {
        interpolator = BounceInterpolator()
        duration = 500L
    }.start()
    

    GitHub上的演示项目已更新

    我更新了ScrollXProperty以包含优化,它似乎在我的Pixel上运行良好,但我还没有在旧设备上进行测试。

    class ScrollXProperty(
            private val enableOptimizations: Boolean
    ) : Property<RecyclerView, Int>(Int::class.java, "horizontalOffset") {
    
        private var lastKnownValue: Int? = null
    
        override fun get(`object`: RecyclerView): Int =
                `object`.computeHorizontalScrollOffset().also {
                    if (enableOptimizations) {
                        lastKnownValue = it
                    }
                }
    
        override fun set(`object`: RecyclerView, value: Int) {
            val currentValue = lastKnownValue?.takeIf { enableOptimizations } ?: get(`object`)
            if (enableOptimizations) {
                lastKnownValue = value
            }
            `object`.scrollBy(value - currentValue, 0)
        }
    }
    

    GitHub项目现在包括带有以下插值器的演示:

    <string-array name="interpolators">
        <item>AccelerateDecelerate</item>
        <item>Accelerate</item>
        <item>Anticipate</item>
        <item>AnticipateOvershoot</item>
        <item>Bounce</item>
        <item>Cycle</item>
        <item>Decelerate</item>
        <item>Linear</item>
        <item>Overshoot</item>
    </string-array>
    

  •  类似资料:
    • 我做了一个水平循环视图,效果很好(多亏了这个),但滚动和数据的方向是从左向右扩展的;那么,我该如何更改RecyclerView滚动方向,如下图所示? 我的代码:

    • 我的活动中有一个片段,其结构如下: 它只有一个回收视图。它有一个适配器,其代码如下: 我还以这种方式设置我的片段: 每次我从服务器接收到新数据时,我都会通过以下方式将它们添加到s中的RecyclerView: 每件事都很好!我可以下载数据,将它们添加到回收者视图等等,但问题是回收者视图不流畅滚动。我真的很困惑。有什么想法吗?任何帮助将不胜感激。

    • 我正在将Recyclerview与CardView一起使用我知道如何在列表视图上控制速度。但对于RecyclerView不是。 更新: 我用这个总结了吉尔的回答

    • 我有一个关于Android的RecyclerView的问题。状态 我正在使用RecyclerView,如何使用它并将其与RecyclerView绑定。状态 我的目的是保存RecyclerView的滚动位置。

    • 我有一个水平回收视图。每个子级包含一个TextView和一个垂直RecyclerView。垂直RecyclerView的子级仅包含TextView。 垂直滚动非常平滑,但水平滚动滞后很多。我已经尝试在onBindViewHolder中使用swapAdapter,而不是setAdapter,但这并没有解决问题。我也尝试过更改数据集并调用notifyDataSetChanged(),但这也没有帮助。