Description
On Android 8+ (API 26+), if the user types into a TextInput inside a PagerView with a hardware keyboard and the input then blurs (for example on submit), every page of the pager gets a light grey tint. Tapping the screen does not remove it. It goes away only when another view takes focus.
Colors from screenshots: a white view becomes #ECECEC, and a #FBF6F0 background becomes #E8E4DE. Views drawn above the pager (a header, a tab bar) keep their colors.
Cause
- A key event from a hardware keyboard takes the window out of touch mode (
adb shell dumpsys window | grep mInTouchMode prints mInTouchMode=false).
- When a view clears its focus outside touch mode, Android gives focus to the first focusable view. Inside a
PagerView, that is ViewPager2's internal RecyclerView. It is focusable (also in touch mode), and ViewPager2 sets FOCUS_BEFORE_DESCENDANTS, so it takes focus before any page child.
- That
RecyclerView has no drawable with state_focused, so Android 8+ draws its default focus highlight over the whole view: the ripple color #1F000000 at 60 % opacity, about 7.5 % black. The measured colors match this exactly.
- RecyclerView is focusable in touch mode, so it keeps the focus, and the highlight, after the user taps again.
adb shell dumpsys activity <package>/.MainActivity shows the focused view:
androidx.viewpager2.widget.ViewPager2$RecyclerViewImpl{9c0563c VFED..... .F...... 0,0-1280,2856 #4}
Reproduce
import { TextInput, View } from 'react-native';
import PagerView from 'react-native-pager-view';
export default function App() {
return (
<PagerView style={{ flex: 1 }} initialPage={0}>
<View key="1" style={{ flex: 1, backgroundColor: 'white', padding: 24 }}>
<TextInput
placeholder="Type, then press Enter"
style={{ borderWidth: 1, padding: 12 }}
/>
</View>
<View key="2" style={{ flex: 1, backgroundColor: 'white' }} />
</PagerView>
);
}
- Run the app on an Android 8+ emulator (its host keyboard is a hardware keyboard) or on a device with a hardware keyboard.
- Tap the input. Type with the hardware keyboard, then press Enter. With adb:
adb shell input text hello, then adb shell input keyevent KEYCODE_ENTER.
- The whole pager turns grey.
Expected: no tint. The pager is a layout container, so a focus highlight over all pages does not help the user.
Typing only with the on-screen keyboard does not cause it, because the IME does not take the window out of touch mode.
Environment
- react-native-pager-view 8.0.4. The same code is on
pager-8 (8.0.5).
- React Native 0.81.5, New Architecture, Expo SDK 54
- Android 17 (API 37) emulator
- Not checked on v9: its Android pager uses Jetpack Compose, not ViewPager2.
Suggested fix
In PagerViewViewManager.createViewInstance, turn off the default focus highlight of the inner RecyclerView:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vp.getChildAt(0).defaultFocusHighlightEnabled = false
}
The RecyclerView stays focusable, so keyboard navigation does not change, and page children keep their own focus highlight. We use this change as a patch in our app. PR: #1152
Description
On Android 8+ (API 26+), if the user types into a
TextInputinside aPagerViewwith a hardware keyboard and the input then blurs (for example on submit), every page of the pager gets a light grey tint. Tapping the screen does not remove it. It goes away only when another view takes focus.Colors from screenshots: a white view becomes
#ECECEC, and a#FBF6F0background becomes#E8E4DE. Views drawn above the pager (a header, a tab bar) keep their colors.Cause
adb shell dumpsys window | grep mInTouchModeprintsmInTouchMode=false).PagerView, that is ViewPager2's internalRecyclerView. It is focusable (also in touch mode), and ViewPager2 setsFOCUS_BEFORE_DESCENDANTS, so it takes focus before any page child.RecyclerViewhas no drawable withstate_focused, so Android 8+ draws its default focus highlight over the whole view: the ripple color#1F000000at 60 % opacity, about 7.5 % black. The measured colors match this exactly.adb shell dumpsys activity <package>/.MainActivityshows the focused view:Reproduce
adb shell input text hello, thenadb shell input keyevent KEYCODE_ENTER.Expected: no tint. The pager is a layout container, so a focus highlight over all pages does not help the user.
Typing only with the on-screen keyboard does not cause it, because the IME does not take the window out of touch mode.
Environment
pager-8(8.0.5).Suggested fix
In
PagerViewViewManager.createViewInstance, turn off the default focus highlight of the innerRecyclerView:The
RecyclerViewstays focusable, so keyboard navigation does not change, and page children keep their own focus highlight. We use this change as a patch in our app. PR: #1152