6

I'm using the Button component from React Native and I need to change the color of the button when the button is focused with a TV remote (Amazon Fire Stick). I don't see any focus listeners available for the button. Is there anyway to achieve this functionality? Here is my code:

<Button disabled={props.loading} styles={styles.button} title="1" onPress={() => {props.addNumber(1)}}/>

I looked at the TouchableHighlight component but it won't work because I need the color to change when the user has focused on the button before the button is clicked. By default, the opacity change is so small that it's hard to tell the button is currently focused.

Cannon Moyer
  • 3,014
  • 3
  • 31
  • 75
  • [TouchableWithoutFeedback](https://reactnative.dev/docs/touchablewithoutfeedback) has a onFocus listener – diedu Oct 17 '21 at 22:33
  • @diedu I was really hoping this would work but I was unable to even select the element that was wrapped in `TouchableWithoutFeedback` via the TV remote. In the emulator, I can use the mouse to click the button however. – Cannon Moyer Oct 17 '21 at 23:34
  • try passing `focusable={true}` – diedu Oct 18 '21 at 01:33
  • @diedu That didn't work :( – Cannon Moyer Oct 18 '21 at 01:50
  • you mention you tried `TouchableHighlight` but I didn't understand very well what you mean with opacity change is too small, does it mean that `TouchableHighlight` does show the change you want but is not enough? because I see it has an [activeopacity](https://reactnative.dev/docs/touchablehighlight#activeopacity) prop that you could set to 1 and set the color with [underlaycolor](https://reactnative.dev/docs/touchablehighlight#underlaycolor) – diedu Oct 18 '21 at 02:26
  • So, I have a set of buttons that look like a calculator keypad. On my app, you can use the remote (up, down, right, left buttons) to move the focus to the number (button) you want to select and then select the button. The problem is that when you move from button to button with the remote, it's very difficult to tell which button currently has the focus of the remote because the default opacity that appears to be set via the Android framework is very faint. @diedu – Cannon Moyer Oct 18 '21 at 02:57

4 Answers4

3

you can have onFocus prop in TouchableOpacity or TouchableHighlight, but in order to work it on TV you need to import it from the specific package as mentioned here. as mentioned there you need to move from react-native to react-native-tvos. All TV-related stuff has been moved to that package. It tracks react-native but with additional TV support. It won't be coming back to react-native core package.

read this

Sanira Nimantha
  • 1,160
  • 1
  • 12
  • 29
1

Replace it for:

      state = {
        buttonStyle: styles.button,
        [...]
      }
      [...]

      <TouchableWithoutFeedback disabled={props.loading} styles={this.state.buttonStyle} 
      onPress={() => {props.addNumber(1)}} 
      onFocus={() => {this.setState({buttonStyle: styles.focusedButton})}} >
          <Text>1</Text>
      </TouchableWithoutFeedback >

If you have all buttons in the same component, you will need to use the state value as array or object and define the key or index to access to the specific one.

https://reactnative.dev/docs/touchablewithoutfeedback#onfocus

zelda11
  • 425
  • 2
  • 7
1

from react-native docs :

When running on Android TV the Android framework will automatically apply a directional navigation scheme based on the relative position of focusable elements in your views. The Touchable mixin has code added to detect focus changes and use existing methods to style the components properly and initiate the proper actions when the view is selected using the TV remote, so TouchableWithoutFeedback, TouchableHighlight, TouchableOpacity, and TouchableNativeFeedback will work as expected. In particular:

onFocus will be executed when the touchable view goes into focus
onBlur will be executed when the touchable view goes out of focus
onPress will be executed when the touchable view is actually selected by pressing the "select" button on the TV remote.

so adding onfocus on TouchableOpacity should work for you the reason it is not you need some changes in AndroidManifest.xml to activate android tv mode

  <!-- Add custom banner image to display as Android TV launcher icon -->
 <application
  ...
  android:banner="@drawable/tv_banner"
  >
    ...
    <intent-filter>
      ...
      <!-- Needed to properly create a launch intent when running on Android TV -->
      <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
    </intent-filter>
    ...
  </application>

also, you can use tvParallaxProperties and hasTVPreferredFocus to show the initial focus but it has limited effects

    <TouchableHighlight
      hasTVPreferredFocus
      tvParallaxProperties={{ magnification: 1.2 }}
    >
      <Text>Button</Text>
    </TouchableHighlight>

https://reactnative.dev/docs/touchableopacity#tvparallaxproperties-android

pfndesign
  • 174
  • 3
  • 12
1

You can use the Pressable component, here's how you can do it:

<Pressable
  onPress={onPressFunction}
  style={({ focused }) => ({ backgroundColor: focused ? 'red' : 'blue' })}
>
  <Text>I'm pressable!</Text>
</Pressable>

You can read more about it in the docs

Ahmed Mahmoud
  • 148
  • 1
  • 6