简体   繁体   English

如何使用 CoordinatorLayout 使视图作为 RecyclerView 的一部分移动

[英]How to make a view move as part of RecyclerView using CoordinatorLayout

I am learning Android CoordinatorLayout/RecyclerView/Behavior/Nested scroll stuff.我正在学习 Android CoordinatorLayout/RecyclerView/Behavior/Nested scroll 的东西。 I found the APIs are not very straight forward.我发现 API 不是很简单。 Thus I did a little experiment but found the behaviors of views inside CoordinatorLayout do not come out as expected.因此我做了一个小实验,但发现 CoordinatorLayout 中的视图行为并没有像预期的那样出现。

Here is what I want to do: I want to have a CoordinatoryLayout as the parent container.这是我想要做的:我想要一个 CoordinatorLayout 作为父容器。 Inside it, there is a RecyclerView as its child.在它里面,有一个 RecyclerView 作为它的孩子。 Also as its child, there is another View that is in red color.同样作为它的孩子,还有另一个红色的 View。 I want the red view to move as the RecyclerView scrolls.我希望红色视图随着 RecyclerView 滚动而移动。 I want the movement of the two views so synchronized that it seems that the red view is part of the RecyclerView.我希望两个视图的移动如此同步,以至于红色视图似乎是 RecyclerView 的一部分。

Note: I am aware that to achieve what I just said, there is much more simpler ways.注意:我知道要实现我刚才所说的,还有更简单的方法。 But I just want to do it with CoordinatorLayout and Behavior class so that I can learn how they work.但我只想用 CoordinatorLayout 和 Behavior 类来做,这样我就可以了解它们是如何工作的。

Here is my layout file:这是我的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="io.github.seemuch.coordinatorlayoutexperiment.MainActivity">

<android.support.v7.widget.RecyclerView
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="40dp"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:dividerHeight="10dp"
    />

<View
    android:id="@+id/red_view"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_marginBottom="20dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:background="#ff0000"
    app:layout_scrollFlags="scroll|enterAlways"
    />

</android.support.design.widget.CoordinatorLayout>

And here is my behavior class:这是我的行为类:

package io.github.seemuch.coordinatorlayoutexperiment;

import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;


public class MyBehavior extends CoordinatorLayout.Behavior<View> {
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View toolbar, View dependency) {
        return dependency instanceof RecyclerView;
    }


    @Override
    public boolean onStartNestedScroll (CoordinatorLayout coordinatorLayout,
                             View child,
                             View directTargetChild,
                             View target,
                             int nestedScrollAxes) {

        int vertical = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL);
        int horizontal = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_HORIZONTAL);

        return (vertical != 0 && horizontal == 0);
    }

    @Override
    public void onNestedPreScroll (CoordinatorLayout coordinatorLayout,
                        View child,
                        View target,
                        int dx,
                        int dy,
                        int[] consumed) {

        float currY = child.getY();
        if (currY <= 0 && dy >= 0) {
        return;
        }
        child.setY(currY - dy);
    }

}

As you can see in the onNestedPreScroll method, I want the child, which is the red_view, move as much as the view it depends on, which is the RecyclerView.正如您在 onNestedPreScroll 方法中看到的那样,我希望子节点(即 red_view)移动到它所依赖的视图(即 RecyclerView)尽可能多的位置。

What actually happened was this: if you scroll the RecyclerView with very big movement, the red view does move with it, as expected;实际发生的事情是这样的:如果你滚动 RecyclerView 的动作非常大,红色的视图会和它一起移动,正如预期的那样; but if you move very little, the red_view moves much faster than the RecyclerView.但是如果你移动得很少,red_view 的移动速度会比 RecyclerView 快得多。

Here is a link to the screen record video: https://youtu.be/zK4g61F2aa0 And here is the Github repo of the project, incase you want to download it and run it yourself: https://github.com/seemuch/CoordinatorLayoutExperiment这是屏幕录制视频的链接: https : //youtu.be/zK4g61F2aa0这里是该项目的 Github 存储库,如果您想自己下载并运行它: https : //github.com/seemuch/协调器布局实验

So, anybody knows what happened?那么,有人知道发生了什么吗? Thanks!谢谢!

Found a solution: Do not override onNestedPreScroll, instead, override onNestedScroll().找到了一个解决方案:不要覆盖 onNestedPreScroll,而是覆盖 onNestedScroll()。 Simple as that.就这么简单。 It does not handle fling, though.但是,它不处理投掷。 Flings need to be handled separately. Flings 需要单独处理。

I've solved this issue doing something pretty simple.我已经解决了这个问题,做了一些非常简单的事情。 First I defined the RecyclerView not scrollable (we still have the touch for each row) and then I put a ScrollView in the layout.首先,我定义了RecyclerView不可滚动(我们仍然可以触摸每一行),然后在布局中放置一个ScrollView

Here some code:这里有一些代码:

layout.xml布局文件

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="409dp"
            android:layout_height="729dp"
            android:layout_marginTop="200dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.505" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.089" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

MainActivity.kt主活动.kt

class MainActivity : AppCompatActivity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)

            val adapter = PersonAdapter { /*handle touch*/ }
            val manager = CustomGridLayoutManager(this)
            manager.setScrollEnabled(false)
            recycler.layoutManager = manager
            recycler.adapter = adapter
        }
    }

CustomGridLayoutManager.kt自定义网格布局管理器.kt

class CustomGridLayoutManager(context: Context?) :
    LinearLayoutManager(context) {
    private var isScrollEnabled = true
    fun setScrollEnabled(flag: Boolean) {
        isScrollEnabled = flag
    }

    override fun canScrollVertically(): Boolean { 
        return isScrollEnabled && super.canScrollVertically()
    }
}

PersonAdapter.kt PersonAdapter.kt

class PersonAdapter(val onItemClick : (Int) -> (Unit))
: RecyclerView.Adapter<PersonAdapter.ViewHolder>() {

private val personList = arrayOf("marco", "anna", "gianna", "giulia", "alice", "sini", "marco", "anna", "gianna",
    "giulia", "alice", "sini", "marco", "anna", "gianna", "giulia", "alice", "sini", "marco", "anna", "gianna", "giulia", "alice", "sini")

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false))
}

override fun getItemCount(): Int {
    return personList.size
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {

    val element = personList[position]

    holder.text.text = element

    holder.text.setOnClickListener {
        onItemClick(position)
    }

    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val text = itemView.findViewById<TextView>(R.id.textRow)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 CoordinatorLayout 中使视图位于另一个视图之上? - How to make view on top of another view in CoordinatorLayout? 如何使视图的一部分(相对布局)滚动而另一部分不动? - How to make one part of view (relativelayout) scroll, but another part not move? 如何使recyclerview始终显示视图的顶部? - How to make the recyclerview always show the top part of the view? 使用ViewPager的RecyclerView的CoordinatorLayout - CoordinatorLayout using the ViewPager's RecyclerView 如何防止Recyclerview在CoordinatorLayout中展开 - How to prevent Recyclerview expand in CoordinatorLayout android上CoordinatorLayout中RecyclerView下方的底部视图 - bottom view below RecyclerView in CoordinatorLayout on android 使用CoordinatorLayout时如何隐藏工具栏的一部分内容 - How to hide part of content of the toolbar when using CoordinatorLayout CoordinatorLayout与RecyclerView - CoordinatorLayout with RecyclerView 使用CoordinatorLayout与SwipeRefreshLayout以及RecyclerView和FloatingActionButton一起使用 - Using CoordinatorLayout with SwipeRefreshLayout and RecyclerView and FloatingActionButton together 如何使用两个数据模型在 RecyclerView 中创建多个视图类型? - How to make multiple view type in RecyclerView using two data models?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM