更新: 我决定针对此问题创建一个github存储库,任何人都可以尝试重现并修复它。 https://github.com/LolusKekus/NestsedRecyclerScrollItselfChallenge
更新2 花一些时间在研究上,我终于找到了满足我需求的解决方案。
我需要做的是扩展recyclerview 类和覆盖forcusSearch 方法,如下:
@Override
public View focusSearch(View focused, int direction) {
View view = super.focusSearch(focused, direction);
Log.d(TAG, "focusSearch: ");
if (view instanceof CRecyclerView) {
int position = ((LinearLayoutManager)((CRecyclerView) view).getLayoutManager()).findFirstVisibleItemPosition();
view = ((CRecyclerView) view).getLayoutManager().findViewByPosition(position);
}
return view;
}
CRecyclerView-我的扩展RecyclerView。
在正常情况下,focusSearch返回我的itemview,一切都很好。但是由于某些原因,focusSearch返回了RecyclerView实例,结果我有这种烦人的自动滚动。我没有深入研究这个问题,因为我拥有了我所需要的。但是,如果有人可以,我将不胜感激。
我有一台垂直回收机,里面有一堆嵌套的水平回收机。 当我在垂直回收站上滚动时,嵌套的回收站会无故滚动自己。
看起来像这样。 滚动之前,让我们想象一下31上的选择器:
_____________
|31 32 33 34|
|41 42 43 44|
|51 52 53 54|
_____________
现在在dpad上按一下(我正在使用android电视应用程序):
_____________
|24 25 26 27|
|31 32 33 34|
|41 42 43 44|
_____________
出现隐藏的回收站视图,绑定并滚动最多24个元素。但这一定不是!所选项目必须为21!依此类推,直到垂直回收机的顶部... 14 ... 04 ...
我注意到,嵌套的回收站滚动到最后一个可见的项目。
此行为出现在“ com.android.support:recyclerview-v7:24.2.1”
之后现在我正在使用“ com.android.support:recyclerview-v7:27.1.1” 并遇到此问题。
活动:
public class MainActivity extends AppCompatActivity {
List<String> hDataset;
List<Integer> vDataset;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
hDataset = new ArrayList<>();
for (int i=0; i<hItemsCount; i++) {
hDataset.add(String.format("lolKek Cheburek %d", i));
}
vDataset = new ArrayList<>();
for (int i=0; i<vItemsCount; i++) {
vDataset.add(i);
}
vRecyclerView = findViewById(R.id.vRecyclerView);
vRecyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
vRecyclerView.setLayoutManager(layoutManager);
vRecyclerView.setAdapter(new VAdapter(vDataset, hDataset, context));
}
垂直适配器:
public class VAdapter extends RecyclerView.Adapter<VAdapter.MyVertHolder>() {
private List<String> hDataset;
private Context context;
public VAdapter(List<String> hDataset, List<String> vDataset, Context context) {
this.hDataset = hDataset;
this.vDataset = vDataset;
this.context = context;
}
public static class MyVertHolder extends RecyclerView.ViewHolder {
RecyclerView hRecyclerView;
public MyVertHolder(final View itemView) {
super(itemView);
hRecyclerView = itemView.findViewById(R.id.hRecyclerView);
}
public void setAdapter(HAdapter adapter) {
hRecyclerView.setAdapter(adapter);
}
public void setLayoutManager(LinearLayoutManager layoutManager) {
hRecyclerView.setLayoutManager(layoutManager);
}
}
@NonNull
@Override
public MyVertHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.v_item_view, parent, false);
MyVertHolder holder = new MyVertHolder(itemView);
holder.setAdapter(new HAdapter(hDataset));
holder.setLayoutManager(new LinearLayoutManage(context, LinearLayoutManager.HORIZONTAL, false));
return holder;
}
@Override
public void onBindViewHolder(final @NonNull MyVertHolder holder, int position) {
... some bindings
}
}
水平适配器:
class HAdapter extends RecyclerView.Adapter<HAdapter.MyHolder> {
private List<String> dataset;
public HAdapter(List<String> dataset) {
this.dataset = dataset;
}
public static class MyHolder extends RecyclerView.ViewHolder {
private TextView tvItemText;
public MyHolder(FrameLayout itemView) {
super(itemView);
tvItemText = itemView.findViewById(R.id.tvItemText);
}
}
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
FrameLayout itemView = (FrameLayout) LayoutInflater
.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
return new MyHolder(itemView);
}
@Override
public void onBindViewHolder(final @NonNull MyHolder holder, final int position) {
holder.setItemText(dataset.get(position));
}
主要活动布局:
<FrameLayout
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"
tools:context="MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/vRecyclerView"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
垂直项目视图布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/colorAccent"
android:id="@+id/hRecyclerView"
android:focusableInTouchMode="true"
android:focusable="true"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
水平项目视图布局:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/flContainer"
android:layout_margin="5dp"
android:focusable="true"
android:layout_width="250dp"
android:layout_height="150dp">
<TextView
android:id="@+id/tvItemText"
android:textColor="@color/white"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
我想停止这种烦人的自动滚动行为。 谢谢。
答案 0 :(得分:0)
请删除
android:focusableInTouchMode="true"
android:focusable="true"
让我知道状态。
答案 1 :(得分:0)
将此添加到您的HAdapter类
private View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
RecyclerView rv = (RecyclerView) v.getParent();
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
rv.getLayoutManager().scrollToPosition(0);
}
return false;
}
};
和
itemView.setOnKeyListener(mOnKeyListener);
进入HAdapter类的onCreateViewHolder
方法。
这仅用于Arrow Up键,您可以扩展if子句以同时包含Arrow Down键。
修改:
或者,您可以将其放在if子句中,而不是scrollToPosition方法调用:
private View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
RecyclerView rv = (RecyclerView) v.getParent();
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
int pos = rv.getLayoutManager().getPosition(v);
rv.scrollBy(-((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, pos * width, mContext.getResources().getDisplayMetrics())), 0);
}
return false;
}
};
其中width是RecyclerView项目的宽度,以dp为单位。
建议:
我会将setAdapter和setLayoutManager方法从ViewHolder类移到HAdapter类主体中。 (在VAdapter类中也执行相同的操作)它们与ViewHolder模式无关。 ViewHolder模式用于通过缓存findViewById()返回的视图来优化性能。
编辑2:
将此类添加到您的项目中:
然后,修改您的v_item_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<lolkek.example.com.testrecycler.PersistentFocusWrapper
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hRecyclerView"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</lolkek.example.com.testrecycler.PersistentFocusWrapper>
我对其进行了测试,并且可以正常工作。
答案 2 :(得分:0)
您需要保留每个Horizontal RecyclerView适配器的状态/位置。滚动垂直RecyclerView时,显然是在回收视图,因此,如果未保存水平适配器的状态,则滚动垂直RecyclerView时,滚动到水平RecyclerView所处的位置将不同于您的位置。在视图被回收之前。