Skip to content

[Android] Whole pager gets a grey tint after a TextInput blurs while a hardware keyboard is used (v8) #1151

Description

@youchi1

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

  1. A key event from a hardware keyboard takes the window out of touch mode (adb shell dumpsys window | grep mInTouchMode prints mInTouchMode=false).
  2. 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.
  3. 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.
  4. 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>
  );
}
  1. Run the app on an Android 8+ emulator (its host keyboard is a hardware keyboard) or on a device with a hardware keyboard.
  2. 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.
  3. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions