Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TouchableHighlight Does Not Focus AndroidTV Inside Modal #24448

Closed
jdmueller opened this issue Apr 14, 2019 · 38 comments
Closed

TouchableHighlight Does Not Focus AndroidTV Inside Modal #24448

jdmueller opened this issue Apr 14, 2019 · 38 comments

Comments

@jdmueller
Copy link

jdmueller commented Apr 14, 2019

🐛 Bug Report

I am using a modal to display a page of information using TouchableHighlights. I have noticed that it says hasTVPreferredFocus={true} is only for tvOS but it does seem to work on AndroidTV anyways, but not inside the modal. It is working on my main home screen the d-pad works correctly and moves between the TouchableHighlights on the page. However, as soon as I open the modal that contains 4 TouchableHighlight buttons they refuse to focus and you cannot navigate to any of the items. The entire app runs correctly on tvOS but on Android TV emulator and physical device it will not work. On emulator you can click the screen and it will work correctly. I have tried hasTVPreferredFocus={true} and it will not work inside the modal. You can use the example modal code from React Native adding a TouchableHighlight and it does not work for AndroidTV.

To Reproduce

Setup basic project using react-native init using the example modal code that launches from a main home screen. Place a TouchableHighlight inside the modal and the focus will not change even with hasTVPreferredFocus={true} on ATV. My modals are imported from separate class components.

Expected Behavior

Using hasTVPreferredFocus={true} the d-pad should work between the touchable highlights just like it does on tvOS. tvOS correctly focuses on the first TouchableHighlight even without hasTVPreferredFocus: True.

Code Example using React Native modal code from docs:

<View style={{marginTop: 22}}>
        <Modal
          animationType="slide"
          transparent={false}
          visible={this.state.modalVisible}
          onRequestClose={() => {
            Alert.alert('Modal has been closed.');
          }}>
          <View style={{marginTop: 22}}>
            <View>
              <Text>Hello World!</Text>

              <TouchableHighlight
                onPress={() => {
                  this.setModalVisible(!this.state.modalVisible);
                }}>
                <Text>Hide Modal</Text>
              </TouchableHighlight>
            </View>
          </View>
        </Modal>

        <TouchableHighlight
          onPress={() => {
            this.setModalVisible(true);
          }}>
          <Text>Show Modal</Text>
        </TouchableHighlight>
      </View>

Here is my touchable code. I have tried using a ref as well.

<TouchableHighlight ref={(ref) => { this.touchRef = ref; }} hasTVPreferredFocus={true} style={styles.touchableTop} underlayColor={'gray'} onPress={this.handleImage.bind(this)}>
    <View style={styles.touchableView}>
        <Image source={require('../assets/icon-images.png')} style={styles.touchableIcon} />
        <Text style={styles.touchableText}>{i18n.t('Property Slideshow')}</Text>
    </View>
</TouchableHighlight>

Environment

React Native Environment Info:
System:
OS: macOS 10.14.4
CPU: (8) x64 Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz
Memory: 385.13 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 11.8.0 - /usr/local/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.7.0 - /usr/local/bin/npm
SDKs:
iOS SDK:
Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
Android SDK:
API Levels: 24, 26, 27, 28
Build Tools: 24.0.0, 26.0.0, 28.0.3
System Images: android-27 | Android TV Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom
IDEs:
Android Studio: 3.3 AI-182.5107.16.33.5314842
Xcode: 10.2/10E125 - /usr/bin/xcodebuild
npmPackages:
react: 16.8.3 => 16.8.3
react-native: 0.59.4 => 0.59.4
npmGlobalPackages:
react-native-cli: 2.0.1
react-native: 0.59.4

I will attach images to further explain my issue. The main screen is not within a modal and you can see the d-pad works and remote works tvOS and ATV. However, on ATV neither of the modals with TouchableHighlights inside will receive focus making the page unresponsive.

Screenshot_1555270698
Screenshot_1555270577
Screenshot_1555270712

@asgvard
Copy link

asgvard commented Jun 13, 2019

Following this issue. I am struggling a bit with how to imperatively set focus on some element in AndroidTV. For example when the page is just loaded or like in your case, when Modal is opened.

@mohmdalfaha
Copy link

mohmdalfaha commented Jul 9, 2019

I was just facing a similar issue only on android where I have a modal and a closing TouchableOpacity. The TouchableOpacity doesn't respond to the clicks where on iOS it is working fine. To solve that I got rid of the extra wrappers above the TouchableOpacity. In your code I can see there are some unnecessary view like the below ones.

<View style={{marginTop: 22}}> <View> <Text>Hello World!</Text> <TouchableHighlight onPress={() => { this.setModalVisible(!this.state.modalVisible); }}> <Text>Hide Modal</Text> </TouchableHighlight> </View> </View>

Hope this solve your issue and It seems like a bug that needs to be solved by react-native team.

@jdmueller
Copy link
Author

I was just facing a similar issue only on android where I have a modal and a closing TouchableOpacity. The TouchableOpacity doesn't respond to the clicks where on iOS it is working fine. To solve that I got rid of the extra wrappers above the TouchableOpacity. In your code I can see there are some unnecessary view like the below ones.

<View style={{marginTop: 22}}> <View> <Text>Hello World!</Text> <TouchableHighlight onPress={() => { this.setModalVisible(!this.state.modalVisible); }}> <Text>Hide Modal</Text> </TouchableHighlight> </View> </View>

Hope this solve your issue and It seems like a bug that needs to be solved by react-native team.

I think I tried this already before posting the bug report. But next time I spin up the dev environment I will try removing the view containers that you suggested. Thanks!

@catmans1
Copy link

i have the same issue, Any solution for this?

@jdmueller
Copy link
Author

i have the same issue, Any solution for this?

I am getting ready to do an update on my TV apps so I am going to give it another try in the next few days.

@stale
Copy link

stale bot commented Dec 1, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 1, 2019
@dblachut-adb
Copy link

@jdmueller any update on your check?

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 2, 2019
@jdmueller
Copy link
Author

I had some issues updating to the very latest version when I worked with it last. I was able to get mostly current however, I still had the issues the same as before with the TouchableHighlight. They still work perfectly for me on Apple TV devices.

@brooklyn097
Copy link

I'm currently facing the same problem. Any workaround this?

@numericgraphics
Copy link

Same problem here ! Did you find a workaround, or a fix, thx !

@adri1336
Copy link

same problem, any fix?

@NickAVolpe
Copy link

NickAVolpe commented Apr 22, 2020

I have a similar problem. My workaround is to hide all views that are underneath the modal.

@BertaFly
Copy link

I have a similar issue with TouchableOpacity on Android TV, inside modal: items don't change their opacity and onFocus method doesn't trigger. Looking forward to some solution.

@artemsh5432
Copy link

Have you got a solution?
Does anyone know how to disable the focus on TouchableHighlight?

@s349856186
Copy link

@artemsh5432
disable? can you enable onFocus method on Android TV?
How to do?

@artemsh5432
Copy link

artemsh5432 commented May 25, 2020

@s349856186 I can not turn it on, but put the listener.
```
enableTVEventHandler() {
this.evtHandler = new TVEventHandler();
this.evtHandler.enable(this, this.handleTVRemoteEvent);
}

disableTVEventHandler() {
    if (this.evtHandler) {
        this.evtHandler.disable();
        delete this.evtHandler;
    }
}

handleTVRemoteEvent = (cmp, event) => {
    const { eventType, tag } = event;

    if (tag !== this.nodeHandle) {
        return;
    }

    if (eventType === "left") {
        if (this.props.onLeft !== undefined) {
            this.props.onLeft();
        }
    }

    if (eventType === "right" && event.eventKeyAction === 1) {
        if (this.props.onRight !== undefined) {
            this.props.onRight();
        }
    }

    if (eventType === "focus") {
        this.setState({ isFocus: true });

        if (this.props.focus !== undefined) {
            this.props.focus();
        }
    }
    if (eventType === "select") {
        if (this.props.onTouch !== undefined) {
            this.props.onTouch();
        }
    }

    if (eventType === "blur") {
        this.setState({ isFocus: false });
    }
}

componentDidMount() {
    this.nodeHandle = findNodeHandle(this.myRef.current)
    this.enableTVEventHandler();
}

componentWillUnmount() {
    this.disableTVEventHandler();
}
render() {
       const { children, hide, ...props } = this.props;
       var { isFocus } = this.state;
       console.debug('focusing, isFocus', isFocus);
       return (
           <TouchableHighlight 
           touchableHandleActivePressIn 
           hasTVPreferredFocus={true} 
           ref={this.myRef} onPress={() => this.onPress()} style={{ backgroundColor: isFocus ? 'blue' : 'red' }}
               onPressIn={() => this.onFocus(true)}
               onPressOut={() => this.onFocus(false)}>
               <View>
                   {children}
               </View>
           </TouchableHighlight>
       )
   }

@fabOnReact
Copy link
Contributor

fabOnReact commented May 25, 2020

after briefly recreating this scenario (with a basic modal example) ...

I noticed that none of your code references the usage of nextFocusDown and all the other related focus methods for android tv

I suggest you to research about it https://reactnative.dev/docs/view#nextfocusright and read https://reactnative.dev/docs/building-for-tv.html

I believe this is not a bug, but just your implementation is missing the logic to handle remote control focus and navigation

Pass the Remote: User Input on TV Devices
https://netflixtechblog.com/pass-the-remote-user-input-on-tv-devices-923f6920c9a8

Similar Issue
https://stackoverflow.com/questions/52303706/react-native-derectional-pad-support-android-tv-app

@fabOnReact
Copy link
Contributor

This is artemsh5432 solution.. It is not complete. I am trying to figure how to build this and hopefully find a way to contribute to tv in the future..

import React, { Component, useState } from "react";
import {
  Alert,
  Modal,
  StyleSheet,
  Text,
  TouchableHighlight,
  TouchableOpacity,
  View,
  TVEventHandler,
  findNodeHandle,
  Button
} from "react-native";


class App extends Component { 
  constructor(props) {
    super(props);
    this.state = { isFocus: false };
  }

  disableTVEventHandler() {
      if (this.evtHandler) {
          this.evtHandler.disable();
          delete this.evtHandler;
      }
  }
  enableTVEventHandler = () => {
    this.evtHandler = new TVEventHandler();
    this.evtHandler.enable(this, this.handleTVRemoteEvent);
  }

  handleTVRemoteEvent = (cmp, event) => {
    const { eventType, tag } = event;
    if (tag !== this.nodeHandle) {
      return;
    }
    if (eventType === "left") {
      if (this.props.onLeft !== undefined) {
          this.props.onLeft();
      }
    }

    if (eventType === "right" && event.eventKeyAction === 1) {
        if (this.props.onRight !== undefined) {
            this.props.onRight();
        }
    }

    if (eventType === "focus") {
        this.setState({ isFocus: true });

        if (this.props.focus !== undefined) {
            this.props.focus();
        }
    }
    if (eventType === "select") {
        if (this.props.onTouch !== undefined) {
            this.props.onTouch();
        }
    }

    if (eventType === "blur") {
        this.setState({ isFocus: false });
    }
  }

  componentDidMount = () => {
      this.nodeHandle = findNodeHandle(this.myRef)
      this.enableTVEventHandler();
  }

  componentWillUnmount() {
      this.disableTVEventHandler();
  }
  render() {
       const { children, hide, ...props } = this.props;
       var { isFocus } = this.state;
       console.debug('focusing, isFocus', isFocus);
       return (
         <TouchableHighlight 
         touchableHandleActivePressIn 
         hasTVPreferredFocus={true} 
         ref={this.myRef} 
         style={{ backgroundColor: isFocus ? 'blue' : 'red' }}
         onPressIn={() => this.setState({isFocus: true})}
         onPressOut={() => this.setState({isFocus: true})}>
             <View>
               <Text>TEsting</Text>
             </View>
         </TouchableHighlight>
       )
   }
};

const styles = StyleSheet.create({
});

export default App;

@fabOnReact
Copy link
Contributor

fabOnReact commented May 25, 2020

@artemsh5432
Copy link

@fabriziobertoglio1987 I do not understand how this code works

  1. Here the listener on clicking is 'if (eventType === "select")', then why onPressIn and onPressOut? (And these methods do not work :((( )
  2. touchableHandleActivePressIn - a certain parameter needs a listener, because it will be involved in focusing and defocusing
  3. And like everything else is my code

@prashantchothani
Copy link

I am facing the same issue when we have any Touchable Components in the Modal

@fabOnReact
Copy link
Contributor

fabOnReact commented May 27, 2020

@artemsh5432 I'm kind of giving up on this issue, I believe here the issue is on the missing/incomplete documentation... we need additional guide at https://github.com/facebook/react-native-website (the docs you see at reactnative.dev/) ... so maybe you should open an issue there and reference it

I don't know the solution to your problem, but here are my points:

  1. this.props.right(), this.props.left() and this.props.focus() should call respective functions that move the focus on the screen

To better understand this concept you may read more about building apps on android tv and for example Netflix. I just want to tell you that I experimented the same bug in Spotify tv app... when I move between songs they do not highlight my cursor because that part of the screen does not support dpad navigation
https://netflixtechblog.com/pass-the-remote-user-input-on-tv-devices-923f6920c9a8

  1. The functions describe on point 1) are nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight. You should read the docs from android sdk

image

@artemsh5432
Copy link

@fabriziobertoglio1987 I have a list of items, I think it will be very bad for him

@wanglaohushiwo
Copy link

Following this issue. I am struggling a bit with how to imperatively set focus on some element in AndroidTV. For example when the page is just loaded or like in your case, when Modal is opened.

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@wanglaohushiwo
Copy link

i have the same issue, Any solution for this?

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@wanglaohushiwo
Copy link

i have the same issue, Any solution for this?

I am getting ready to do an update on my TV apps so I am going to give it another try in the next few days.

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@wanglaohushiwo
Copy link

I'm currently facing the same problem. Any workaround this?

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@wanglaohushiwo
Copy link

Same problem here ! Did you find a workaround, or a fix, thx !

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@wanglaohushiwo
Copy link

I have a similar problem. My workaround is to hide all views that are underneath the modal.

I am doing Android TV development now, and I have encountered the problem that I cannot focus TouchableHighlight when switching the remote control in modal. Is your problem solved now? If it is solved, can you share your solution? thank you very much.

@artemsh5432
Copy link

artemsh5432 commented May 29, 2020

@wanglaohushiwo, Hello, Sorry, but this problem, as well as the defocusing problem, remains unanswered from the developers.
There is only a solution that you see above, but I have not tried it yet

@wanglaohushiwo
Copy link

wanglaohushiwo commented May 29, 2020 via email

@artemsh5432
Copy link

artemsh5432 commented May 29, 2020

@wanglaohushiwo, Currently, I know that I have only 2 focus options:

  1. https://stackoverflow.com/questions/60811901/disable-default-focus-behaviour-on-android-tv?noredirect=1#comment109702958_60811901
  2. https://stackoverflow.com/questions/61868301/how-to-set-focus-in-touchableopacity?noredirect=1#comment109428493_61868301

I think that for Android tv it is better to change the framework. But I don’t know how things are on other platforms, but everything is not very good here

@wanglaohushiwo
Copy link

I have a similar problem. My workaround is to hide all views that are underneath the modal.

I tried it here, it doesn't seem to work

@JoaoCEAlmeida
Copy link

Same problem here, and no solution found.

@augustolopez
Copy link

Has anyone found any solution?

@safaiyeh
Copy link
Contributor

Hey all please check out https://github.com/react-native-community/react-native-tvos for future development for react-native-tvos

@parshantnagpalSmartData
Copy link

please use this version of react-native-TV 0.64.2-3. Android Modal Focus issue is resolved in that.
It works for me

@memanoj
Copy link

memanoj commented Mar 7, 2023

Use view with absolute position with zindex and it will work like a modal

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

No branches or pull requests