Prevent foocus from escaping open navigation drawer

When contents of NewPipe navigation drawer change, NavigationMenuView
(which is actually a RecyclerView) removes and re-adds all its adapter
children, which leads to temporary loss of focus on currently focused drawer
child. This situation was not anticipated by developers of original
support library DrawerLayout: while NavigationMenuView itself is able
to keep focus from escaping via onRequestFocusInDescendants(),
the implementation of that method in DrawerLayout does not pass focus
to previously focused View. In fact it does not pass focus correctly at all
because the AOSP implementation of that method does not call addFocusables()
and simply focuses the first available VISIBLE View, without regard
to state of drawers.
This commit is contained in:
Alexander-- 2020-03-15 09:19:22 +06:59
parent 6aca344bf7
commit 381b491845
1 changed files with 29 additions and 0 deletions

View File

@ -19,6 +19,7 @@ package org.schabi.newpipe.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@ -44,6 +45,34 @@ public final class FocusAwareDrawerLayout extends DrawerLayout {
super(context, attrs, defStyle);
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
// SDK implementation of this method picks whatever visible View takes the focus first without regard to addFocusables
// if the open drawer is temporarily empty, the focus escapes outside of it, which can be confusing
boolean hasOpenPanels = false;
for (int i = 0; i < getChildCount(); ++i) {
View child = getChildAt(i);
DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) child.getLayoutParams();
if (lp.gravity != 0 && isDrawerVisible(child)) {
hasOpenPanels = true;
if (child.requestFocus(direction, previouslyFocusedRect)) {
return true;
}
}
}
if (hasOpenPanels) {
return false;
}
return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
boolean hasOpenPanels = false;