RecyclerView items lose focus

巧了我就是萌 提交于 2019-12-05 00:14:59

问题


In my fire tv app I'm using a recyclerview with horizontal layout.

Scrolling with dpad works and also items are gaining focus.

But when I hold the button it scrolls very fast because many keydown events are triggered, and items are losing their focus and it's not possible to scroll anymore because another Textview above my recyclerview is gaining the focus.

It looks like a bug. Is there any workaround for this?


回答1:


I face the same problem, what i do in my project likes below in my Activity (containing 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;
    }

which avoids the fast scrolling when you hold the button on the dpad, and the focus works fine in my RecyclerView.




回答2:


I think the answer by @tmm1 is the best one so far. I have successfully implemented this workaround for the issue of elements loaded in a RecyclerView loosing focus if user uses the DPAD too quickly to scroll.

In my RecyclerView's adapter I use a LayoutInflater to inflate my element views like this

@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);
}

My item_keyboard_key.xml were originally defined like this

<?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>

Then I created a new custom FrameLayout class (FocusFixFrameLayout) extending FrameLayout and using this as my root layout. My item_keyboard_key.xml then became

<?xml version="1.0" encoding="utf-8"?>
<no.bluebit.views.FocusFixFrameLayout 
    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"/>

</no.bluebit.views.FocusFixFrameLayout>

and my FocusFixFrameLayout class looks like this

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();
    }
}



回答3:


Looks like this is a bug.

See https://stackoverflow.com/a/33190656/332798 and https://issuetracker.google.com/issues/37067220


I was able to work around this bug by neutering clearFocus() on my item views, so detached views losing focus did not move focus outside the RecyclerView:

override fun clearFocus() {
    if (parent != null)
        super.clearFocus()
}



回答4:


I have faced the same problem when was working on project for Android TV and leanback library.

The good news is that popular apps(YouTube and others) do not have this issue. I found informative resource. After investigation I made a solution that is convenient to me. The key is to use Presenter instead of Adapter There is the simplest example

//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();
}


来源:https://stackoverflow.com/questions/34277425/recyclerview-items-lose-focus