Android 自定义布局管理器滚动/动画

Android 自定义布局管理器滚动/动画,android,android-layout,kotlin,carousel,Android,Android Layout,Kotlin,Carousel,我想做什么。 使用RecyclerView创建一个简单的旋转木马 问题 最初,视图未对齐到中心,并且视图未获得我想要的样式。(即,完全可见的项目应该比其他项目大,当用手指滚动时,它工作正常) 以编程方式滚动时,视图不会像用手指滚动时那样获得捕捉效果 例如,请参见下面附带的gif 问题 开始时如何使样式符合预期(即完全可见的项目更大) 单击“滚动到”按钮时如何获取样式。(它会滚动到正确的位置唯一的问题是没有获得预期的样式,并且没有对齐中心) 完整的代码在这里 以下是自定义布局管理器的代码 ope

我想做什么。

使用RecyclerView创建一个简单的旋转木马

问题

  • 最初,视图未对齐到中心,并且视图未获得我想要的样式。(即,完全可见的项目应该比其他项目大,当用手指滚动时,它工作正常)
  • 以编程方式滚动时,视图不会像用手指滚动时那样获得捕捉效果
  • 例如,请参见下面附带的gif

    问题

  • 开始时如何使样式符合预期(即完全可见的项目更大)
  • 单击“滚动到”按钮时如何获取样式。(它会滚动到正确的位置唯一的问题是没有获得预期的样式,并且没有对齐中心)
  • 完整的代码在这里

    以下是自定义布局管理器的代码

    open class CarouselLayoutManager(
        context: Context,
        orientation: Int,
        reverseLayout: Boolean
    ) : LinearLayoutManager(context, orientation, reverseLayout) {
    
    private val mShrinkAmount = 0.15f
    private val mShrinkDistance = 0.9f
    
    override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
        scrollVerticallyBy(0, recycler, state)
        super.onLayoutChildren(recycler, state)
    }
    
    override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
        val orientation = orientation
        if (orientation == LinearLayoutManager.HORIZONTAL) {
            val scrolled = super.scrollHorizontallyBy(dx, recycler, state)
    
            val midpoint = width / 2f
            val d0 = 0f
            val d1 = mShrinkDistance * midpoint
            val s0 = 1f
            val s1 = 1f - mShrinkAmount
            for (i in 0 until childCount) {
                val child = getChildAt(i)
                val childMidpoint = (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f
                val d = Math.min(d1, Math.abs(midpoint - childMidpoint))
                val scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0)
                child.scaleX = scale
                child.scaleY = scale
            }
            return scrolled
        } else {
            return 0
        }
    }
    
    override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
        val orientation = orientation
        if (orientation == LinearLayoutManager.VERTICAL) {
            val scrolled = super.scrollVerticallyBy(dy, recycler, state)
            val midpoint = height / 2f
            val d0 = 0f
            val d1 = mShrinkDistance * midpoint
            val s0 = 1f
            val s1 = 1f - mShrinkAmount
            for (i in 0 until childCount) {
                val child = getChildAt(i)
                val childMidpoint = (getDecoratedBottom(child) + getDecoratedTop(child)) / 2f
                val d = Math.min(d1, Math.abs(midpoint - childMidpoint))
                val scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0)
                child.scaleX = scale
                child.scaleY = scale
            }
            return scrolled
        } else {
            return 0
        }
    }
    

    }

    最后,我使用这个库/示例解决了这个问题

  • 这是最终结果。

    有关完整代码,请参阅


    最后,我使用这个库/示例解决了这个问题

  • 这是最终结果。

    有关完整代码,请参阅


    调用
    scrollVerticallyBy(0,回收器,状态)
    中的
    onLayoutCompleted()
    方法调用
    scrollVerticallyBy(0,回收器,状态)
    中的
    onLayoutCompleted()
    method

    当您的第一件物品从“回收者”视图的开始位置开始时,会发生这种情况-这种行为在最终物品上也会是相反的-它永远不会捕捉到中心。为“页眉”和“页脚”位置(项目计数=数据大小+2)创建第二个宽度为:宽度=(屏幕宽度/2)-(普通视图支架最大宽度/2)的视图支架。我也做过类似的事情,但我在之前创建了一个自定义的
    RecyclerView.ItemDecoration
    ——我的代码可以工作,但是逻辑采用了不同的方法,所以发布没有帮助,但关键是页眉(开始)和页脚(完成)视图。这说明第一个和最后一个项目不会捕捉到中心,但是,如果我忽略第一个和最后一个项目,是否有办法从中间或第二个位置启动回收器视图?您可能会在第一个/最后一个项目上实施一些特殊的左/右填充(根据屏幕大小和深度动态设置),但是这可能会变得非常难看,因为视图持有者会被重用(即,即使它们是相同的视图持有者,也会有特殊的行为),这可能必须在视图绑定到数据(onBind)时进行当你知道位置时。我只是在想我的头顶-可能有不同的方法来做这件事,我选择了一个,然后就去了..祝你好运!这发生在你的第一件物品从你的回收器视图的开始位置开始时-这种行为在最后一件物品也会是相反的-它永远不会弹到中心。创建第二个V“页眉”和“页脚”位置(项目计数=数据大小+2)的文件夹宽度为:宽度=(屏幕宽度/2)-(普通视图支架最大宽度/2).我也做过类似的事情,但我在之前创建了一个自定义的
    RecyclerView.ItemDecoration
    -我的代码可以工作,但是逻辑采用了不同的方法,所以发布没有帮助,但关键是页眉(开始)和页脚(完成)视图。第一个和最后一个项目不会对齐到中心是有道理的,但是如果我忽略第一个和最后一个项目,是否有办法从中间或第二个位置启动回收器视图?您可能可以在第一个/最后一个项目上实施一些特殊的左/右填充(根据屏幕大小和深度动态设置)但是,这可能会变得非常难看,因为视图持有者会被重用(即,即使它们是相同的视图持有者,它们也会有特殊的行为),这可能必须在视图绑定到数据(onBind)时完成当你知道这个职位的时候。我只是在想我的头顶-可能有不同的方法来做这件事,我选择了一个,然后就去了。祝你好运!