as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

呈现视频列表

呈现视频列表

现在我们想为islandVideos和underwaterVideos数组中的每个项目渲染显卡。我们可以通过多种方式做到这一点:

  1. 使用诸如.map函数之类的JavaScript逻辑遍历JSX中的数组并为每个项目创建一个组件。
  2. 使用接收数组对象的React Native FlatList组件。

在这种情况下,我们将选择选项2,即FlatList,因为它性能比.map更高,并且无疑更简单一点。

创建FlatList

  • 首先,从LandingScreen.tsx中的'react-native'导入FlatList、View和StyleSheet。
import { FlatList, View, StyleSheet } from 'react-native';
  • 将VideoCard组件替换为FlatList组件。
  • 添加horizontal属性以水平显示项目。
  • data属性添加到FlatList并将其设置为islandVideos。这是FlatList将呈现的源数据。
<FlatList
  horizontal
  data={islandVideos}
/>
  • 添加renderItem属性。它将来自data属性的item(在本例中为单个视频元素)传递给箭头函数,在其中您可以指定要呈现该项目的JSX。
  • 将VideoCard组件添加到renderItem并将其打包在View中。
  • key属性添加到VideoCard,FlatList使用它来跟踪项目(密钥必须是唯一的)。您也可以向FlatList添加keyExtractor属性,而不是在VideoCard中指定key。您可以在React Native FlatList文档中了解与此相关的更多信息。
  • titledescriptionimgURL属性添加到VideoCard组件,然后传入item中的相应字段。
  • underwaterVideos创建第二个FlatList。
  • 向每行添加一个Text组件以标记类别。
<Text>Costa Rica Islands</Text>
<FlatList
  horizontal
  data={islandVideos}
  renderItem={({item}) => (
    <View>
      <VideoCard
        key={item.id}
        title={item.title}
        description={item.description}
        imgURL={item.imgURL}
      />
    </View>
  )}
/>
<Text>Costa Rica Underwater</Text>
<FlatList
  horizontal
  data={underwaterVideos}
  renderItem={({item}) => (
    <View>
      <VideoCard
        key={item.id}
        title={item.title}
        description={item.description}
        imgURL={item.imgURL}
      />
    </View>
  )}
/>
  • 刷新应用程序并验证VideoCard是否呈现。

添加样式

我们来添加一些样式,让VideoCard在屏幕上看起来更美观。

  • 使用LandingScreen箭头函数后,使用名为flatListitemContainercategoryTitle的样式创建StyleSheet。这些样式将为我们的卡片留出一定的间距,并使我们的类别标题看起来更美观一些。
const styles = StyleSheet.create({
  flatList: {
    padding: 10,
  },
  itemContainer: {
    margin: 10,
  },
  categoryTitle: {
    fontSize: 24,
    fontWeight: 'bold',
    color: 'white',
    marginLeft: 30,
  },
});
  • 现在将flatList样式添加到FlatList中,将itemContainer样式添加到View,将categoryTitle添加到Text。
<Text style={styles.categoryTitle}>Costa Rica Islands</Text>
<FlatList
  style={styles.flatList}
  horizontal
  data={islandVideos}
  renderItem={({item}) => (
    <View style={styles.itemContainer}>
      <VideoCard
        key={item.id}
        title={item.title}
        description={item.description}
        imgURL={item.imgURL}
      />
    </View>
  )}
/>

将行包装在TVFocusGuideView中

现在,为了确保在两行之间处理焦点,我们可以使用TVFocusGuideView组件。该组件使您的应用能够查找、恢复和记住多次访问的焦点。

  • Import TVFocusGuideView from @amazon-devices/react-native-kepler.
import {TVFocusGuideView} from '@amazon-devices/react-native-kepler';
  • 在TVFocusGuideView中包装FlatList并将autoFocus设置为true,这使得TVFocusGuide能够自动为您管理焦点。

更新后的LandingScreen.tsx应该如以下所示:

已复制到剪贴板。

import React, {useState, useEffect} from 'react';
import {FlatList, StyleSheet, View, Text} from 'react-native';
import Header from '../components/Header';
import VideoCard from '../components/VideoCard';
import {TVFocusGuideView} from '@amazon-devices/react-native-kepler';

interface IVideo {
  id: string;
  title: string;
  description: string;
  duration: number;
  thumbURL: string;
  imgURL: string;
  videoURL: string;
  categories: Array<string>;
  channel_id: number;
}

const LandingScreen = () => {
  const [islandVideos, setIslandVideos] = useState<IVideo[]>([]);
  const [underwaterVideos, setUnderwaterVideos] = useState<IVideo[]>([]);

  const url = 'https://d2ob7xfxpe6plv.cloudfront.net/TestData.json';

  const getAllVideos = () => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        // 筛选每个类别的视频
        const islands = data.testData.filter(
          (video: IVideo) =>
            video.categories && video.categories.includes('Costa Rica Islands'),
        );

        const underwater = data.testData.filter(
          (video: IVideo) =>
            video.categories &&
            video.categories.includes('Costa Rica Underwater'),
        );

        setIslandVideos(islands);
        setUnderwaterVideos(underwater);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  useEffect(() => {
    getAllVideos();
  }, []);

  return (
    <>
      <Header />
      <TVFocusGuideView autoFocus={true}>
        <Text style={styles.categoryTitle}>Costa Rica Islands</Text>
        <FlatList
          style={styles.flatList}
          horizontal
          data={islandVideos}
          renderItem={({item}) => (
            <View style={styles.itemContainer}>
              <VideoCard
                title={item.title}
                description={item.description}
                imgURL={item.imgURL}
                pressFunction={() => {}}
              />
            </View>
          )}
        />
      </TVFocusGuideView>
      <TVFocusGuideView autoFocus={true}>
        <Text style={styles.categoryTitle}>Costa Rica Underwater</Text>
        <FlatList
          style={styles.flatList}
          horizontal
          data={underwaterVideos}
          renderItem={({item}) => (
            <View style={styles.itemContainer}>
              <VideoCard
                title={item.title}
                description={item.description}
                imgURL={item.imgURL}
                pressFunction={() => {}}
              />
            </View>
          )}
        />
      </TVFocusGuideView>
    </>
  );
};

const styles = StyleSheet.create({
  flatList: {
    padding: 10,
  },
  itemContainer: {
    margin: 10,
  },
  categoryTitle: {
    fontSize: 24,
    fontWeight: 'bold',
    color: 'white',
    marginLeft: 30,
  },
});

export default LandingScreen;
  • 刷新应用,然后从一行导航到另一行。焦点会保留在您导航的项目上,而不是移至新行中的相应项目,注意到了吗? 这种行为由TVFocusGuideView组件控制!

恭喜! 我们已经成功完成了本实验的第1部分,我们在该部分中为视频应用奠定了基础。我们创建了可重复使用的组件,实现了数据提取,并为VideoCard增加了交互性。在第2部分中,我们将扩展应用的功能。