由于第一次使用react-native开发电视应用,也是个新手,所以在这方面比较菜,看了很久官网,官网简简单单一串代码,对于初次接触的我表明很头大,可能是使用RN开发电视应用的,网上找了很久没有合适的例子,也没有相关教程视频。最后在GitHub上面找了一个demo研究了一番(附上地址:https://github.com/dev-seb/react-native-tv-demo),可以直接下载这个例子打包安装到TV上。另外一个小例子:https://github.com/avkan1087/react-native-android-tv/blob/master/App.js
之后自己根据demo做的时候,输入账号密码登录到首页,发现焦点是很乱的,由于Android TV每个页面有每个页面的焦点事件,所以我在首页点击的时候,发现弹出了输入框,我的首页里面并没有任何输入框,说明焦点跑到了之前的登录页,可是我在componentWillUnmount() 钩子函数里面已经卸载了,为什么焦点还是跑到了这里,这个问题困扰了我很久。
后来才发现,我在登录页跳转到首页的时候是使用navigation.push跳到首页,而使用push的话这个页面的componentWillUnmount() 是不会执行的,这就是造成了跳到了首页但是登录页面焦点并没有卸载,所以在首页的时候我的焦点会跳到登录页。
于是我最后采用了replace替换了push,replace会替换当前路由,push是添加路由,所以replace就可以卸载了登录页面的焦点事件,在跳到首页的时候就可以找到焦点了。

按照这个思路,在使用焦点事件的时候,要注意自己的焦点是否符合当前页面的焦点,是否还存在其他页面的焦点,如果存在则想办法卸载其他页面的焦点,也可以通过DeviceEventEmitter来判断卸载焦点
附上登录页代码:
/*
*登录
* */
import React, {Component} from react ;
import Console from "../common/Console";
import {
View,
Text,
StyleSheet,
TextInput,
Image,
TouchableOpacity,
NativeModules,
TVEventHandler
} from react-native
import Util from ../common/util
import request from ../constant/request
import * as URLconstant from ../constant/URLconstant
import Toast from ../common/ToastUtil
import MyStroage from ../common/myStroage ;
import Loading from react-native-easy-loading-view ;
export default class login extends Component {
static EVENT_LINES = 3;
constructor(props) {
super(props);
this.tvEventHandler = null;
this.inputTextRef1 = React.createRef();
this.inputTextRef2 = React.createRef();
this.state = {
handlerStatus: disabled ,
tvEventStack: [],
componentEventStack: [],
username: ,
password: ,
textInputFocused1: false,
textInputFocused2: false,
textInputFocused3: false,
};
}
componentDidMount() {
this.setState({
handlerStatus: enabled
});
this.tvEventHandler = new TVEventHandler();
this.tvEventHandler.enable(
this, this.tvEventListener.bind(this)
);
}
tvEventListener(component, event) {
console.log("tvEventListener:", event.eventType);
// Get event stack
let tvEventStack = this.state.tvEventStack;
if(tvEventStack.length >= login.EVENT_LINES) {
tvEventStack.shift();
}
tvEventStack.push(JSON.stringify(event));
this.setState({
tvEventStack: tvEventStack
});
}
//启用第一个Input的遥控
componentEventListener(event) {
console.warn("componentEventListener:", event);
// Get event stack
if(event=== input1 ){
this.inputTextRef1.focus()
}else if(event=== input2 ){
this.inputTextRef2.focus()
}
let componentEventStack = this.state.componentEventStack;
if(componentEventStack.length >= login.EVENT_LINES) {
componentEventStack.shift();
}
componentEventStack.push(JSON.stringify(event));
this.setState({
componentEventStack: componentEventStack
});
}
//禁用这个页面的遥控
// _disableTVEventHandler() {
// if (this.tvEventHandler) {
// this.tvEventHandler.disable();
// delete this.tvEventHandler;
// }
// this.setState({
// handlerStatus: disabled ,
// tvEventStack: [],
// componentEventStack: [],
// });
// }
onChangeUserNameText(txt){
// Console.log( usertxt=== ,txt)
this.setState({
username:txt
})
}
onChangePwdText(txt){
// Console.log( pwd=== ,txt)
this.setState({
password:txt
})
}
login(event){
let componentEventStack = this.state.componentEventStack;
if(componentEventStack.length >= login.EVENT_LINES) {
componentEventStack.shift();
}
componentEventStack.push(event);
this.setState({
componentEventStack: componentEventStack
});
Loading.showHud( 正在登录... ,)
// this.props.navigation.push( Home ,{navigation:this.props.navigation})
// Console.log(this.state.username)
// Console.log(this.state.password)
let username = this.state.username
let password =this.state.password
if(!username){
Toast.show( 请输入用户名 )
return false
}
if(!password){
Toast.show( 请输入密码 )
return false
}
let datakey={
user_name:username,
pwd:password,
newSas:1
}
// let datakey = [];
// datakey[ user_name ] = username;
// datakey[ pwd ] = password;
// datakey[ newSas ] = 1;
let url = URLconstant.USER_LOGIN_URL
// Console.log( 登录请求路径与参数=== ,url, params=== ,datakey)
// Console.log( params===== ,datakey)
request.post(url,datakey,this.loginSuc.bind(this),this.errorCallback.bind(this))
}
loginSuc(datas){
// Console.log( 登录返回数据==== ,JSON.stringify(datas))
// LOG( datas== +JSON.stringify(datas))
if(datas.status==0){
MyStroage.saveStorage( userinfo , JSON.stringify(datas));
this.props.navigation.replace( Home ,{navigation:this.props.navigation})
this.props.loginSuc()
}else{
Toast.show(datas.msg)
}
}
errorCallback(err){
}
render() {
return(
<View style={styles.container}>
<View style={styles.logo}>
<Loading
ref={(view)=>{Loading.loadingDidCreate(view)}} // 必须调用
// top={-400}
// offsetY={-150}
hudStyle={{position: absolute ,top: 4% ,left: 4% }}
hudTextStyle={{ fontSize : 16, color: red }}
hudBackgroundColor={ transparent } // hud全局背景色
/>
<Image source={require( ../images/home/avatar.jpg )} style={{width: 100% ,height:"100%"}}></Image>
</View>
<Text style={styles.logoTitle}>门店账号登录</Text>
<View style={styles.cell}>
<Text style={styles.cellTitle}>商户id</Text>
<TouchableOpacity
onFocus={this.componentEventListener.bind(this, input1 )}
>
<View style={[
styles.cell_input_view,
this.state.textInputFocused1 && styles.textInputContainerFocused]}>
<TextInput
ref={ref => this.inputTextRef1 = ref}
onFocus={()=>this.setState({textInputFocused1: true})}
onBlur={()=>this.setState({textInputFocused1: false})}
onChangeText={(txt)=>{this.onChangeUserNameText(txt)}}
autoFocus={true}
clearButtonMode={ always }
placeholder= 请输入账号
placeholderTextColor={ #696969 }
style={styles.input_view}
/>
</View>
</TouchableOpacity>
</View>
<View style={styles.cell}>
<Text style={styles.cellTitle}>登录密码</Text>
<TouchableOpacity
onFocus={this.componentEventListener.bind(this, input2 )}
>
<View style={[
styles.cell_input_view,
this.state.textInputFocused2 && styles.textInputContainerFocused]}>
<TextInput
ref={ref => this.inputTextRef2 = ref}
onFocus={()=>this.setState({textInputFocused2: true})}
onBlur={()=>this.setState({textInputFocused2: false})}
onChangeText={(txt)=>{this.onChangePwdText(txt)}}
// autoFocus={true}
clearButtonMode={ always }
placeholder= 请输入账号
placeholderTextColor={ #696969 }
style={styles.input_view}
/>
</View>
</TouchableOpacity>
</View>
<TouchableOpacity
onPress={this.login.bind(this)}
onFocus={()=>this.setState({textInputFocused3: true})}
onBlur={()=>this.setState({textInputFocused3: false})}
>
<View style={[
styles.btn,
this.state.textInputFocused3 && styles.textInputContainerFocused]}>
<Text style={{fontSize: 18, color: "#000"}}>前往登录>></Text>
</View>
</TouchableOpacity>
</View>
)
}
componentWillUnmount() {
// this._disableTVEventHandler();
if (this.tvEventHandler) {
this.tvEventHandler.disable();
delete this.tvEventHandler;
}
this.setState({
handlerStatus: disabled ,
tvEventStack: [],
componentEventStack: [],
});
if(this.inputTextRef1) {
this.inputTextRef1.clear();
}
if(this.inputTextRef2) {
this.inputTextRef2.clear();
}
}
}
var styles = StyleSheet.create({
container:{
alignItems: center ,
justifyContent: center ,
height: 100% ,
},
logo:{
height:150,
width:150,
// width: Util.size.width - 30,
borderRadius:75,
borderWidth: 1,
borderColor: #000 ,
overflow: hidden ,
position: relative
},
logoTitle:{
marginTop:20,
fontSize: 24
},
cell:{
// backgroundColor: red ,
flexDirection: row ,
width: Util.size.width-150,
alignItems: center ,
justifyContent: flex-end ,
marginTop:20
},
cellTitle:{
fontSize:18,
marginRight:15
},
cell_input_view: {
borderWidth: 1,
borderColor: "#ccc",
width: Util.size.width - 250,
height: 40,
},
input_view: {
flex: 1,
padding: 0,
textAlign: left ,
marginLeft:10,
fontSize: 16,
color: "#333",
},
btn:{
width: Util.size.width - 200,
height:40,
backgroundColor: #ccc ,
justifyContent: center ,
alignItems: center ,
marginTop:20
},
//焦点聚焦时输入框的颜色
textInputContainerFocused: {
borderColor: #61dafb
},
})
