TVFocusGuide
TVFocusGuide可帮助您编写直观的电视应用。它支持autofocus,有助于找到/恢复焦点,并记住多次访问时的焦点。它还支持trapping和focus redirection,后者让您可以在应用中自定义焦点行为。
该组件确保即使可设定焦点控件与其他控件未直接对齐,也可以导航到这些控件。RNTester中提供了一个示例,该示例展示了使用该组件的两种不同方式。
| 属性 | 值 | 描述 |
|---|---|---|
| destinations | any[]? | 要注册为FocusGuideView目的地的Component数组 |
| autoFocus | boolean? | 如果为true,TVFocusGuide将自动为您管理焦点。它会在第一次访问时将焦点重定向到第一个可设定焦点的子项上。它还会记住最后一个聚焦的子项,并在随后的访问中将焦点重定向到该子项。在一起使用时,destinations属性会优先于此属性。 |
| trapFocus* (Up、Down、Left、Right) | 防止焦点在给定方向上从容器中逸出。 |
以下动画显示了使用TVFocusGuideView时的导航控件。

有关上述焦点处理改进的更多信息,可以参阅这篇文章(仅提供英文版)。
示例
import React from 'react';
import {
Dimensions,
View,
StyleSheet,
TouchableHighlight,
Text
} from 'react-native';
import {
TVFocusGuideView
} from '@amazon-devices/react-native-kepler';
const screenHeight = Dimensions.get('window').height;
const scale = screenHeight / 1080;
const width = 200 * scale;
const height = 120 * scale;
const theme = {
LinkColor: '#0984ffff',
LabelColor: '#ffffffff',
TertiarySystemFillColor: '#3085C3',
BackgroundColor: '#0c0700ff'
};
const Button = React.forwardRef((props: $FlowFixMeProps, ref) => {
const [focused, setFocused] = React.useState(false);
return (
<TouchableHighlight
onPress={() => {
if (props.onPress) {
props.onPress();
}
console.log(`${props.label} in press`);
}}
onFocus={() => {
if (props.onFocus) {
props.onFocus();
}
console.log(`${props.label} in focus`);
setFocused(true);
}}
onBlur={() => {
if (props.onBlur) {
props.onBlur();
}
console.log(`${props.label} in blur`);
setFocused(false);
}}
style={focused ? styles.buttonStyleFocused : styles.buttonStyle}
ref={ref}>
<Text style={[{ color: theme.LinkColor }, styles.buttonText]}>
{props.label}
</Text>
</TouchableHighlight>
);
});
const ThemedView = (props: $FlowFixMeProps) => {
return (
<View style={[styles.buttonStyle, props.style]}>
<Text style={[{ color: theme.LabelColor }, styles.buttonText]}>
{props.label}
</Text>
</View>
);
};
const TVFocusGuideExample = () => {
const [destination, setDestination] = React.useState(null);
const [destinationText, setDestinationText] = React.useState('');
const destinations = destination?.current ? [destination?.current] : [];
const buttonTopRight = React.useRef(null);
const buttonBottomLeft = React.useRef(null);
const rightButtonInFocusViewContainer = React.useRef(null);
const containerDestinations = rightButtonInFocusViewContainer?.current
? [rightButtonInFocusViewContainer?.current]
: [];
const _setDestination = (o: Object, text: string) => {
setDestination(o);
setDestinationText(text);
};
return (
<View
style={[styles.container, { backgroundColor: theme.BackgroundColor }]}>
<View style={styles.rowContainer}>
<Button onPress={() => {}} label="左上角" />
<Button
onPress={() => {}}
onFocus={() => _setDestination(buttonBottomLeft, 'bottom left')}
ref={buttonTopRight}
label="右上角"
/>
<ThemedView label={`焦点指南指向${destinationText}`} />
{/* @ts-expect-error */}
<TVFocusGuideView
style={styles.containerFocusGuide}
destinations={containerDestinations}>
<Button onPress={() => {}} label="被包装按钮1" />
<Button onPress={() => {}} label="被包装按钮2" />
<Button
ref={rightButtonInFocusViewContainer}
onPress={() => {}}
label="被包装按钮3"
/>
</TVFocusGuideView>
</View>
<View style={styles.rowContainer}>
<Button
onPress={() => {}}
onFocus={() => _setDestination(buttonTopRight, 'top right')}
ref={buttonBottomLeft}
label="左下角"
/>
<TVFocusGuideView
style={[
{ backgroundColor: theme.TertiarySystemFillColor },
styles.focusGuide
]}
destinations={destinations}>
<Text style={[{ color: theme.LabelColor }, styles.buttonText]}>
焦点指南
</Text>
</TVFocusGuideView>
<ThemedView label="" />
<ThemedView
style={{
width: width * 3
}}
label="如果从外部导航,上方的蓝色 焦点指南容器始终
指向按钮3"
/>
</View>
</View>
);
};
const marginSize = 20 * scale;
const styles = StyleSheet.create({
container: {
marginTop: -marginSize,
height: screenHeight
},
rowContainer: {
flexDirection: 'row',
padding: 100 * scale
},
buttonText: {
fontSize: 30 * scale
},
buttonStyle: {
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
buttonStyleFocused: {
opacity: 0.5,
borderColor: 'white',
borderWidth: 4,
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
focusGuide: {
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
containerFocusGuide: {
backgroundColor: 'transparent',
borderColor: 'blue',
borderWidth: 2,
flexDirection: 'row'
}
});
export default TVFocusGuideExample;
参考
属性
autoFocus
如果为true,TVFocusGuide将自动为您管理焦点。它会在第一次访问时将焦点重定向到第一个可设定焦点的子项上。它还会记住最后一个聚焦的子项,并在随后的访问中将焦点重定向到该子项。在使用时,destinations属性会优先于此属性。
| 类型 | 必填 |
|---|---|
| 布尔值 | 否 |
trapFocus* (Up、Down、Left、Right)
防止焦点在给定方向上从容器中逸出。
| 类型 | 必填 |
|---|---|
| 布尔值 | 否 |
destinations
要注册为FocusGuideView目的地的Component数组。
| 类型 | 必填 |
|---|---|
| 引用项的数组 | 否 |
方法
setDestinations
setDestinations([ref1, ref2, ...]);
要注册为FocusGuideView目的地的Component数组。
| 类型 | 必填 |
|---|---|
| 引用项的数组 | 否 |
已知问题
- 如果未挂载组件,
setDestinations回调将无法更新。要么改用destinations属性,要么在调用setDestinations之前使用setTimeout添加延迟。 - 使用严格的类型检查在.tsx中导入时,TVFocusGuide会失败并显示错误
Property 'children' does not exist on type(属性“children”在类型上不存在)。应用可以在使用组件之前添加{/* @ts-expect-error */}或{/* @ts-ignore */}以避免错误。
const TVApp = () => {
return (
<View>
{/* @ts-expect-error */}
<TVFocusGuideView>
<Text>Hello World</Text>
</TVFocusGuideView>
</View>
);
};
其他资源
有关其他库的信息,请参阅支持的第三方库和服务。
Last updated: 2025年9月30日

