[英]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.