Android 回收视图项目失去焦点

Android 回收视图项目失去焦点,android,android-recyclerview,linearlayoutmanager,Android,Android Recyclerview,Linearlayoutmanager,在我的fire tv应用程序中,我正在使用带有水平布局的recyclerview 使用dpad滚动可以工作,而且项目也获得了关注 但是,当我按住按钮时,它会快速滚动,因为许多按键事件都会被触发,项目会失去焦点,并且无法再滚动,因为我的recyclerview上方的另一个Textview正在获得焦点 它看起来像一只虫子。有什么解决方法吗?我也面临同样的问题,我在项目中所做的事情就像我的活动(包含RecyclerView)中所做的那样: private long mLastKeyDownTime=0

在我的fire tv应用程序中,我正在使用带有水平布局的
recyclerview

使用dpad滚动可以工作,而且项目也获得了关注

但是,当我按住按钮时,它会快速滚动,因为许多按键事件都会被触发,项目会失去焦点,并且无法再滚动,因为我的recyclerview上方的另一个
Textview
正在获得焦点


它看起来像一只虫子。有什么解决方法吗?

我也面临同样的问题,我在项目中所做的事情就像我的活动(包含RecyclerView)中所做的那样:

private long mLastKeyDownTime=0;
@凌驾
公共布尔onKeyDown(int-keyCode,KeyEvent事件){
长电流=System.currentTimeMillis();
布尔res=false;
如果(当前-MLASTKEYDOWNTH<300){
res=真;
}否则{
res=super.onKeyDown(键码,事件);
MLASTKEYDOWNTH=当前;
}
返回res;
}

这避免了当您按住dpad上的按钮时快速滚动,并且在我的RecyclerView中焦点工作正常。

看起来这是一个bug

看到和


我可以通过对我的项目视图进行中性化
clearFocus()
来解决此错误,因此分离视图失去焦点不会将焦点移到RecyclerView之外:

    private long mLastKeyDownTime = 0;
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        long current = System. currentTimeMillis();
        boolean res = false;
        if (current - mLastKeyDownTime < 300 ) {
            res = true;
        } else {
            res = super.onKeyDown(keyCode, event);
            mLastKeyDownTime = current;
        }
        return res;
    }
override fun clearFocus() {
    if (parent != null)
        super.clearFocus()
}

我在为Android TVleanback library工作时也遇到过同样的问题

好消息是,流行应用(YouTube和其他)没有这个问题。 我发现信息丰富。经过调查,我提出了一个对我来说方便的解决方案。 关键是用而不是用 有一个最简单的例子

//Presenter class
public class ItemViewPresenter extends Presenter {

    @Override
    public final ViewHolder onCreateViewHolder(ViewGroup parent) {

        //I use data binding
        ItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item, parent, false);
        return new MyViewHolder(binding);
    }

    @Override
    public final void onBindViewHolder(ViewHolder viewHolder, Object item) {
        String text = (String) item;
        ((MyViewHolder) viewHolder).bind(text);
    }

    @Override
    public final void onUnbindViewHolder(ViewHolder viewHolder) {
    }

    private class MyViewHolder extends Presenter.ViewHolder {

        private final ItemBinding binding;

        private DiscoveryViewHolder(ItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        private void bind(String text) {

            binding.textView.setText(text);
        }
    }
}

//... 
private void setupRecyclerView() {

    RecyclerView recyclerView = _baseLayout.findViewById(R.id.recyclerView);

    ArrayObjectAdapter arrayObjectAdapter = new ArrayObjectAdapter(new ItemViewPresenter());

    ItemBridgeAdapter bridgeAdapter = new ItemBridgeAdapter(arrayObjectAdapter);

    recyclerView.setAdapter(bridgeAdapter);

    LinearLayoutManager layoutManager = new LinearLayoutManager(_baseLayout.getContext(), LinearLayoutManager.HORIZONTAL, false);
    recyclerView.setLayoutManager(layoutManager);

    List<Strings> textList = new ArrayList(1);
    textList.add("1");

    //add objects
    arrayObjectAdapter.addAll(0, textList);

    //clear objects
    //arrayObjectAdapter.clear();
}
//演示者类
公共类ItemViewPresenter扩展了Presenter{
@凌驾
公共最终视图持有者onCreateViewHolder(视图组父视图){
//我使用数据绑定
ItemBinding=DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.item,parent,false);
返回新的MyViewHolder(具有约束力);
}
@凌驾
BindViewHolder上的公共最终无效(ViewHolder ViewHolder,对象项){
字符串文本=(字符串)项;
((MyViewHolder)viewHolder.bind(文本);
}
@凌驾
公开最终无效onUnbindViewHolder(ViewHolder ViewHolder){
}
私有类MyViewHolder扩展了Presenter.ViewHolder{
私人最终条款具有约束力;
私有发现文件夹(ItemBinding绑定){
super(binding.getRoot());
这个。绑定=绑定;
}
私有void绑定(字符串文本){
binding.textView.setText(text);
}
}
}
//... 
私有void setupRecyclerView(){
RecycleView RecycleView=\u baseLayout.findViewById(R.id.RecycleView);
ArrayObjectAdapter ArrayObjectAdapter=new ArrayObjectAdapter(new ItemViewPresenter());
ItemBridgeAdapter bridgeAdapter=新的ItemBridgeAdapter(arrayObjectAdapter);
recyclerView.setAdapter(桥接适配器);
LinearLayoutManager布局管理器=新的LinearLayoutManager(_baseLayout.getContext(),LinearLayoutManager.HORIZONTAL,false);
recyclerView.setLayoutManager(layoutManager);
List textList=newarraylist(1);
文本列表。添加(“1”);
//添加对象
arrayObjectAdapter.addAll(0,文本列表);
//清除物体
//arrayObjectAdapter.clear();
}

我认为@tmm1给出的答案是目前为止最好的。我已经成功地实现了这个解决方案,解决了如果用户使用DPAD太快而无法滚动时,在RecyclerView中加载的元素会失去焦点的问题

在我的RecyclerView适配器中,我使用LayoutFlater来像这样膨胀我的元素视图

@Override
public ListItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_keyboard_key, viewGroup, false);
    return new ListItemViewHolder(itemView);
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_keyboard_key_layout"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_keyboard_key_text"
        android:text="A"/>

</FrameLayout>
public class FocusFixFrameLayout extends FrameLayout {

    public FocusFixFrameLayout(@NonNull Context context) {
        super(context);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
}

    @Override
    public void clearFocus() {
        if(this.getParent() != null)
            super.clearFocus();
    }
}
我的item_keyboard_key.xml最初是这样定义的

@Override
public ListItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_keyboard_key, viewGroup, false);
    return new ListItemViewHolder(itemView);
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_keyboard_key_layout"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/item_keyboard_key_text"
        android:text="A"/>

</FrameLayout>
public class FocusFixFrameLayout extends FrameLayout {

    public FocusFixFrameLayout(@NonNull Context context) {
        super(context);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FocusFixFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
}

    @Override
    public void clearFocus() {
        if(this.getParent() != null)
            super.clearFocus();
    }
}

对于那些将面临同样问题的人。我找到了解决办法。我不再使用RecyclerView了。我已经切换到这个HorizontalListView库:,它足以满足我的需要。
parent
从哪里来?
parent
是在
FrameLayout
/
ViewGroup
/
视图
中定义的,我认为它在任何地方都没有定义,我的意思是有一个
getParent()
方法,但没有公共/受保护的
parent
变量。我正在使用Kotlin,因此
parent
正在调用
getParent()
。我在项目中对此进行了测试,但它并没有真正起作用。它将减少问题,但仍然是如此抱歉,但它没有帮助((如何在某些片段或视图中在关键侦听器中使用它而不在活动中使用?嗨,哈瓦德。它真的解决了我的问题。非常感谢你。你是一个救生员))这在某些设备上解决了问题,但在其他设备上它仍然存在(例如,API 21上的Fire OS 5设备)我得到了“java.lang.NullPointerException:尝试调用虚拟方法'boolean android.view.ViewGroup.getTouchscreenBlocksFocus()'on a null object reference”。这个答案发布后有什么变化吗?问题是关于重新循环视图,而不是关于leanback库