Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在不更改滚动位置的情况下动态更新Recyclerview项的布局_Android_Android Layout_Android Recyclerview_Layout Manager - Fatal编程技术网

Android 在不更改滚动位置的情况下动态更新Recyclerview项的布局

Android 在不更改滚动位置的情况下动态更新Recyclerview项的布局,android,android-layout,android-recyclerview,layout-manager,Android,Android Layout,Android Recyclerview,Layout Manager,情景: 我有一个卡片列表,基本上是一个RecyclerView,Recycler视图中只有两个项目。我还扩展了RecyclerView.LayoutManager()并重写了LayoutManager类的onLayoutChildren()方法。 最初,第二张卡在底部,当我向上滑动时,第二张卡滚动到顶部,就在第一张卡的稍下方 单击第二张卡(列表中的第二项)中的“生成条形码”按钮,我将隐藏该按钮并显示替换buton的条形码图像。更新卡布局时,将自动调用onLayoutChildren()方法。此方

情景: 我有一个卡片列表,基本上是一个RecyclerView,Recycler视图中只有两个项目。我还扩展了RecyclerView.LayoutManager()并重写了LayoutManager类的onLayoutChildren()方法。 最初,第二张卡在底部,当我向上滑动时,第二张卡滚动到顶部,就在第一张卡的稍下方

单击第二张卡(列表中的第二项)中的“生成条形码”按钮,我将隐藏该按钮并显示替换buton的条形码图像。更新卡布局时,将自动调用onLayoutChildren()方法。此方法将被重写,以便在启动“回收器”视图时在特定位置显示卡。这将导致布局管理器重新绘制子视图。因此,第二张卡将滚动回初始位置

预期行为:当我们尝试更新第二张卡布局时,第二张卡不应向下滚动

StackCardLayoutManager.kt

class StackCardLayoutManager(
    private val maxItemCount: Int
) : RecyclerView.LayoutManager() {
private val addedChildren: List<View>
    get() = (0 until childCount).map { getChildAt(it) ?: throw NullPointerException() }
private var firstTime: Boolean = true

init {
    Log.d(TAG_K, "StackCardLayoutManager.init()")
}

override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams =
        RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.MATCH_PARENT)

override fun isAutoMeasureEnabled(): Boolean = true

override fun onLayoutChildren(
        recycler: RecyclerView.Recycler,
        state: RecyclerView.State
) {
    Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren(itemcount : ${state.itemCount}) addedChildren Size : ${addedChildren.size} firstTime : $firstTime")
    firstTime = false
    if (state.itemCount == 0) {
        return
    }

    if (state.itemCount > maxItemCount) {
        throw RuntimeException("Can not set more Item than $maxItemCount")
    }
    detachAndScrapAttachedViews(recycler)

    for (i in 0 until state.itemCount) {
        Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren($i) - layoutDecorated")
        val view = recycler.getViewForPosition(i)
        measureChild(view, 0, 0)
        addView(view)
        val layoutParams = view.layoutParams as RecyclerView.LayoutParams
        val left = layoutParams.marginStart
        Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren() left  : $left")
        val top = (view.measuredHeight * i * 1.15).toInt()
        Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren() top  : $top")
        val right = view.measuredWidth + layoutParams.marginEnd
        Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren() right  : $right")
        val bottom = top + view.measuredHeight
        Log.d(TAG_K, "StackCardLayoutManager.onLayoutChildren() bottom  : $bottom")
        layoutDecorated(view, left, top, right, bottom)
        view.setTag(InitializedPosition.TOP.key, top)
    }
}

override fun canScrollVertically(): Boolean = true

override fun scrollVerticallyBy(
        dy: Int,
        recycler: RecyclerView.Recycler,
        state: RecyclerView.State
): Int = dy.also { deltaY ->
    Log.d("stackcardlayout", "scrollVerticallyBy: $deltaY")
    if (childCount == 0) {
        Log.d("stackcardlayout", "scrollVerticallyBy: child count is 0")
        return@also
    }
    var deltaY1 = 0
    addedChildren.forEachIndexed { index, view ->
        val initializedTop = view.getTag(InitializedPosition.TOP.key) as Int
        val layoutParams = view.layoutParams as RecyclerView.LayoutParams
        val left = layoutParams.marginStart

        if(deltaY < 0){
            deltaY1 = -500
        }else {
            deltaY1 = 500
        }

        val top = min(max((view.top - deltaY1), index * dpToPx(70)), initializedTop)
        val right = view.measuredWidth + layoutParams.marginEnd
        val bottom = top + view.measuredHeight
        layoutDecorated(view, left, top, right, bottom)
    }
}

private enum class InitializedPosition(val key: Int) {
    TOP(R.integer.top)
}
}
类StackCardLayoutManager(
私有val maxItemCount:Int
):RecyclerView.LayoutManager(){
private val addedChildren:列表
get()=(0直到childCount).map{getChildAt(it)?:抛出NullPointerException()}
private var firstTime:Boolean=true
初始化{
Log.d(标记“StackCardLayoutManager.init()”)
}
重写fun generateDefaultLayoutParams():RecyclerView.LayoutParams=
RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_内容,RecyclerView.LayoutParams.MATCH_父项)
override fun isAutoMeasureEnabled():Boolean=true
儿童在线娱乐(
回收商:回收商视图,回收商,
状态:RecyclerView.state
) {
Log.d(TAG_K,“StackCardLayoutManager.onLayoutChildren(itemcount:${state.itemcount})addedChildren大小:${addedChildren.Size}firstTime:$firstTime”)
第一次=错误
如果(state.itemCount==0){
返回
}
如果(state.itemCount>maxItemCount){
抛出RuntimeException(“不能设置超过$maxItemCount的项”)
}
拆卸和报废附件(回收器)
for(0中的i,直到state.itemCount){
Log.d(标签K,“StackCardLayoutManager.onLayoutChildren($i)-layoutDecorated”)
val view=recycler.getViewForPosition(i)
measureChild(视图,0,0)
添加视图(视图)
val layoutParams=view.layoutParams作为RecyclerView.layoutParams
val left=layoutParams.margintart
Log.d(标记K,“StackCardLayoutManager.onLayoutChildren()左:$left”)
val top=(view.measuredHeight*i*1.15).toInt()
Log.d(标记K,“StackCardLayoutManager.onLayoutChildren()top:$top”)
val right=view.measuredWidth+layoutParams.margined
Log.d(标记K,“StackCardLayoutManager.onLayoutChildren()右:$right”)
val底部=顶部+视图。测量高度
Log.d(标记K,“StackCardLayoutManager.onLayoutChildren()底部:$bottom”)
布局装饰(视图、左侧、顶部、右侧、底部)
view.setTag(InitializedPosition.TOP.key,TOP)
}
}
override fun canscrollvertical():Boolean=true
无情地覆盖乐趣(
狄:Int,
回收商:回收商视图,回收商,
状态:RecyclerView.state
):Int=dy.也{deltaY->
Log.d(“stackcardlayout”,“ScrollVerticalyBy:$deltaY”)
if(childCount==0){
Log.d(“stackcardlayout”,“ScrollVerticalyBy:子计数为0”)
return@also
}
变量deltaY1=0
addedChildren.ForAchineDexed{索引,视图->
val initializedTop=view.getTag(InitializedPosition.TOP.key)为Int
val layoutParams=view.layoutParams作为RecyclerView.layoutParams
val left=layoutParams.margintart
如果(三角洲<0){
deltaY1=-500
}否则{
deltaY1=500
}
val top=最小值(最大值((view.top-deltaY1),索引*dpToPx(70)),初始化为top)
val right=view.measuredWidth+layoutParams.margined
val底部=顶部+视图。测量高度
布局装饰(视图、左侧、顶部、右侧、底部)
}
}
私有枚举类InitializedPosition(val键:Int){
TOP(R.integer.TOP)
}
}

我试着用谷歌搜索这个解决方案,并在上发现了类似的问题,但该解决方案对androidx Recyclerview无效,但仅对android v7 Recycyler视图支持库有效。

我看到了答案。建议您根据
eatRequestLayout()
方法来实现自定义视图
requestLayout
方法

// RecyclerView requestlayout
@Override
    public void requestLayout() {
        if (!mEatRequestLayout) {
            super.requestLayout();
        } else {
            mLayoutRequestEaten = true;
        }
    }
//RecyclerView.eatRequestLayout
void eatRequestLayout() {
        if (!mEatRequestLayout) {
            mEatRequestLayout = true;
            mLayoutRequestEaten = false;
        }
    }

由于文档所述的
requestLayout
,视图将根据它重新绘制

当某些更改使此视图的布局无效时调用此函数。这将计划视图树的布局过程。 在自定义视图
requestLayout
中,您可以根据自己的情况设置不同的标志以防止重新绘制