如何用React Native和Native Base构建一个安卓新闻应用

417 阅读11分钟

我们生活在一个事物不断变化的世界中。因此,如果你想了解正在发生的事情,你会想要一个好的新闻应用程序。

为了帮助你学习一些很酷的技术并保持现状,在这篇博文中,我们将使用React Native为Android建立一个新闻应用程序。它将从不同的新闻频道获取头条新闻并按类别显示。

这就是我们完成后的应用程序的样子。所以,让我们直接开始吧。

如何安装Expo

那么,Expo是什么?Expo是一个框架,可以帮助你快速、轻松地建立和部署React Native应用。

让我们来安装它。

npm install --global expo-cli

安装Expo

在你的终端运行这个命令来安装Expo CLI。在这里,我们使用--global ,以确保它安装在任何地方。

安装完成后,我们需要创建一个Expo项目。

expo init News-Application

创建一个Expo项目

使用上面的命令来初始化这个项目。它会问你几个问题,比如你的应用程序的名称,你是否想在你的项目中添加TypeScript,或者从一个空白项目开始。只要选择空白,然后按回车。

然后,它将下载文件夹中的所有软件包和依赖项。

现在,完成后,导航到项目文件夹中。要启动该应用程序,输入expo start。它将在浏览器中打开开发者工具。

世博开发者工具

在这里你会看到左边有很多选项,比如在安卓设备/模拟器上运行,或者在iOS模拟器上运行。我们将在网络浏览器上运行应用程序,所以点击在网络浏览器中运行选项。

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

我们的App.js

这是我们的App.js文件,它包含了默认的模板。

我们的输出

现在我们的应用程序正在运行。

如何使用React Navigation创建不同的屏幕

现在,让我们为我们的应用程序创建各种不同的屏幕。为此,我们将使用React Navigation。所以,让我们来安装它。

前往reactnavigation.org/,点击阅读文档。它将打开文档页面。

让我们使用下面的命令来安装React Navigation。

npm install @react-navigation/native

expo install react-native-screens react-native-safe-area-context

安装React Navigation

现在,我们的React Navigation已经安装完毕。

我们将使用bottomTabNavigator 。因此,从左边的菜单中,选择API参考,然后是导航器,然后是底部标签。

选择底部标签

让我们使用下面的命令来安装底部标签。

npm install @react-navigation/bottom-tabs

安装底部标签

现在,在我们的App.js文件中,我们需要导入Bottom Tabs,以便使用它。

所以,像这样导入它。

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

导入Bottom Tabs

现在,让我们导入标签屏幕。

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}

导入标签导航屏幕

这就是我们创建底部标签的方法。

在我们的案例中,我们需要做这样的事情。

<Tab.Navigator>
  <Tab.Screen name="All" component={All} />
  <Tab.Screen name="Business" component={Business} />
  <Tab.Screen name="Health" component={HealthScreen} />
  <Tab.Screen name="Sports" component={SportsScreen} />
  <Tab.Screen name="Tech" component={TechScreen} />
</Tab.Navigator>

我们需要为以下标签创建这些屏幕。所有新闻,商业新闻,体育新闻,健康新闻,以及科技新闻。同时,在项目中为每个屏幕创建一个组件。

我们需要把这个TabNavigtor ,像这样包装成一个NavigationContainer

<NavigationContainer>
  <Tab.Navigator>
    <Tab.Screen name="All" component={All} />
    <Tab.Screen name="Business" component={Business} />
    <Tab.Screen name="Health" component={HealthScreen} />
    <Tab.Screen name="Sports" component={SportsScreen} />
    <Tab.Screen name="Tech" component={TechScreen} />
  </Tab.Navigator>
</NavigationContainer>

我们还需要导入这些所有的组件,所以在顶部导入它们。

import All from './screens/All';
import Business from './screens/Business';
import HealthScreen from './screens/Health';
import SportsScreen from './screens/Sports';
import TechScreen from './screens/Tech';

现在,如果我们把我们写的所有代码放在一起,我们将得到以下代码。

import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import All from './screens/All';
import Business from './screens/Business';
import HealthScreen from './screens/Health';
import SportsScreen from './screens/Sports';
import TechScreen from './screens/Tech';
const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="All" component={All} />
        <Tab.Screen name="Business" component={Business} />
        <Tab.Screen name="Health" component={HealthScreen} />
        <Tab.Screen name="Sports" component={SportsScreen} />
        <Tab.Screen name="Tech" component={TechScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
} 

屏幕的代码

这将是我们的输出。

我们的五个屏幕,即所有、商业、健康、体育和技术。

我们在这里有五个屏幕,分别是所有、商业、健康、体育和技术。

现在,让我们在这里做一些调整。我们需要改变底部标签的图标。

要做到这一点,我们将需要为我们的图标获得一个图标库。为此,我们将使用react-native-elements。

要安装它,请输入以下命令。

npm install react-native-elements

安装React Native Elements

这个图标包有很多图标选项可以选择。

React Native Elements中的可用图标

现在让我们在底部标签导航器中添加我们的图标。

<Tab.Screen name="All" component={All}
          options={{
            tabBarIcon: (props) => (
              <Icon type='feather' name='home' color={props.color} />
            ),
          }} />

添加主页的图标

这里我们为主页添加了名为 "home "的图标,并为类型添加了羽毛图标类。

带有主页图标的底部标签导航器

这将产生上述输出。同样地,让我们对所有的标签重复同样的过程。

<Tab.Navigator>
        <Tab.Screen name="All" component={All}
          options={{
            tabBarIcon: (props) => (
              <Icon type='feather' name='home' color={props.color} />
            ),
          }} />

        <Tab.Screen name="Business" component={Business}
          options={{
            tabBarIcon: (props) => (
              <Icon type='feather' name='dollar-sign' color={props.color} />
            ),
          }} />

        <Tab.Screen name="Health" component={HealthScreen}
          options={{
            tabBarIcon: (props) => (
              <Icon type='feather' name='heart' color={props.color} />
            ),
          }} />

        <Tab.Screen name="Sports" component={SportsScreen}
          options={{
            tabBarIcon: (props) => (
              <Icon type='ionicon' name="tennisball-outline" color={props.color} />
            ),
          }} />

        <Tab.Screen name="Tech" component={TechScreen}
          options={{
            tabBarIcon: (props) => (
              <Icon type='ionicon' name="hardware-chip-outline" color={props.color} />
            ),
          }} />
      </Tab.Navigator>

带有图标的所有底部标签

现在我们每个不同的标签或屏幕都完成了,它们都有自己独特的图标。

如何调用新闻API

现在,让我们从newsapi.org/中调用新闻API。

进入这个网站并注册。它将给你一个API密钥。

我们需要一个配置文件来存储所有的News常量,所以我们来创建它。

export const API_KEY = ``;
export const endpoint = `https://newsapi.org/v2/top-headlines`;
export const country = 'in'

我们的config.js

我们需要API_KEY、端点和国家代码。

现在,我们需要为我们的GET API请求创建一个服务**。**

创建一个名为services.js的文件*。*

在这里,在顶部导入API_KEY、端点和国家。

import { API_KEY, endpoint, country } from '../config/config';

Services.js

然后,我们将编写我们的服务主体。

export async function services(category = 'general') {
    let articles = await fetch(`${endpoint}?country=${country}&category=${category}`, {
        headers: {
            'X-API-KEY': API_KEY
        }
    });

    let result = await articles.json();
    articles = null;

    return result.articles;
}

我们的GET API服务

所以,我们通过使用我们的端点来获取新闻数据,并添加国家和类别。在函数中,我们将类别传递为一般,因为那是默认的类别。我们还在头文件中传递了API_key。

然后,我们将响应或传入的数据转换成JSON格式,并将其存储在一个结果变量中。

最后,我们使用return 关键字将其返回。

下面是整个文件供你参考。

import { API_KEY, endpoint, country } from '../config/config';

export async function services(category = 'general') {
    let articles = await fetch(`${endpoint}?country=${country}&category=${category}`, {
        headers: {
            'X-API-KEY': API_KEY
        }
    });

    let result = await articles.json();
    articles = null;

    return result.articles;
}

现在,我们需要将这个服务导入我们的All.js文件。

import { services } from '../services/services';

将服务导入All.js中

我们将需要使用useStateuseEffect 钩子。useEffect钩子将在All.js文件中调用这个服务,useState将创建一个状态,存储来自API的响应。

import React, { useEffect, useState } from 'react'
import { View } from 'react-native';
import { services } from '../services/services';
export default function All() {
    const [newsData, setNewsData] = useState([])
    useEffect(() => {
        services('general')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])
    return (
        <View>

        </View>
    )
}

使用useState和useEffect钩子

在这个文件中,我们在useEffect钩子中调用服务。然后我们将响应存储在newsData状态中,它是一个数组。我们还为类别传递了一个参数,它是一般的。

这个屏幕将获取所有的新闻,所以我们使用一般类别。它将在其他每个屏幕上改变。对于健康屏幕,它将是健康 ,对于体育,它将是体育 ,等等。

现在,我们需要在我们的界面上显示这些数据。为此,我们需要另一个叫做Native Base的包。所以,让我们来安装它。

输入下面的命令来安装Native Base。

yarn add native-base styled-components styled-system
expo install react-native-svg react-native-safe-area-context

安装Native Base

在All.js中,让我们从Native Base导入一些东西。

import React, { useEffect, useState } from 'react'
import { View, Text } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';

从Native Base导入东西

然后在返回中,我们将添加NativeBaseProvider

return (
        <NativeBaseProvider>
            
        </NativeBaseProvider>
    )

在返回中添加NativeBaseProvider

然后,让我们添加Scroll View。如果新闻数据超出了我们的屏幕高度,这将让用户滚动。

<NativeBaseProvider>
            <ScrollView height={850}>

            </ScrollView>
        </NativeBaseProvider>

添加ScrollView

现在,让我们添加FlatList 来显示我们的新闻数据。

<NativeBaseProvider>
            <ScrollView height={850}>
                <FlatList
                    data={newsData}
                    renderItem={({ item }) => (
                       <View>

                       </View> 
                    )}
                    keyExtractor={(item) => item.id}
                />
            </ScrollView>
        </NativeBaseProvider>

使用FlatList

FlatList接收一个数据道具,也就是我们之前创建的newsData 状态,它从renderItems,返回一个item

这类似于JavaScript中的map ,它遍历一个数组并返回一个项目。它也有一个keyExtractor ,我们用它来使每个项目都是独一无二的。

现在,让我们在视图中显示我们的数据。

像这样在父视图中再创建一个视图。

<NativeBaseProvider>
            <ScrollView height={850}>
                <FlatList
                    data={newsData}
                    renderItem={({ item }) => (
                       <View>
                           <View>
                               
                           </View>
                       </View> 
                    )}
                    keyExtractor={(item) => item.id}
                />
            </ScrollView>
        </NativeBaseProvider>

现在,让我们在子视图内添加一些文本。

<NativeBaseProvider>
            <ScrollView height={850}>
                <FlatList
                    data={newsData}
                    renderItem={({ item }) => (
                        <View>
                            <View>
                                <Text>
                                    {item.title}
                                </Text>
                                <Text>
                                    {item.publishedAt}
                                </Text>
                                <Text>
                                    {item.description}
                                </Text>
                            </View>
                        </View>
                    )}
                    keyExtractor={(item) => item.id}
                />
            </ScrollView>
        </NativeBaseProvider>

这包含了我们的新闻标题,描述,和发布日期。

如何为我们的React Native新闻应用设计风格

这就是我们的应用程序现在的样子,包括新闻标题、描述和日期。为了使它看起来更漂亮,我们需要给它一些样式。

在顶部从React Native导入StyleSheet ,以便使用其样式。

import { View, Text, StyleSheet } from 'react-native';

从react-native导入StyleSheet

<View>
                            <View style={styles.newsContainer}>
                                <Text style={styles.title}>
                                    {item.title}
                                </Text>
                                <Text style={styles.date}>
                                    {item.publishedAt}
                                </Text>
                                <Text style={styles.newsDescription}>
                                    {item.description}
                                </Text>
                            </View>
                        </View>

然后,像这样添加样式。而在底部,我们需要创建这些样式。

const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
});

我们在All.js中的StyleSheet

这就是得到一些样式后的应用程序现在的样子。你也可以向下滚动页面。

现在,我们需要将日期格式改为可读格式,因为我不明白**'2021-08-21T11:00:40Z'。**

我们将为此使用有用的moment.js包,所以让我们使用下面的命令来安装它。

npm install moment --save

安装Moment.js来格式化时间

然后,在我们的All.js界面中导入它。

<Text style={styles.date}>
  {moment(item.publishedAt).format('LLL')}
</Text>

使用 moment.js 格式化日期和时间

像这样格式化日期。

Moment.js的时间和日期格式

moment文档给了我们这么多格式可供选择。我选择了*'LLL'*格式。

而现在我们的日期更容易让人读懂。

我们还需要一个分隔符,把新闻文章彼此分开,这样它们就不会都跑到一起。

<View>
                            <View style={styles.newsContainer}>
                                <Text style={styles.title}>
                                    {item.title}
                                </Text>
                                <Text style={styles.date}>
                                    {moment(item.publishedAt).format('LLL')}
                                </Text>
                                <Text style={styles.newsDescription}>
                                    {item.description}
                                </Text>
                            </View>
                            <Divider my={2} bg="#e0e0e0" />
                        </View>

添加一个分隔符

因此,在子视图之后添加了一个分隔器,我们的应用程序看起来像这样。

现在我们的新闻标题被分割开来,看起来很不错。

这个新闻API也有一个图片。所以,让我们来添加它。

<View>
                            <View style={styles.newsContainer}>
                                <Image
                                    width={550}
                                    height={250}
                                    resizeMode={"cover"}
                                    source={{
                                        uri: item.urlToImage,
                                    }}
                                    alt="Alternate Text"
                                />
                                <Text style={styles.title}>
                                    {item.title}
                                </Text>
                                <Text style={styles.date}>
                                    {moment(item.publishedAt).format('LLL')}
                                </Text>
                                <Text style={styles.newsDescription}>
                                    {item.description}
                                </Text>
                            </View>
                            <Divider my={2} bg="#e0e0e0" />
                        </View>

所以,我们已经添加了图片,我们使用了名为urlToImage 的键来做这个*。*

现在我们有新闻图片显示了。

如何添加一个旋转器来显示正在加载的新闻

让我们添加一个旋转器,在新闻加载时显示。

首先,我们将创建一个检查。如果newsData 状态的长度超过1,我们将显示我们的FlatList ,它包含我们的新闻数据。否则,我们将显示加载旋钮。

换句话说,如果newsData 状态的长度小于1,这意味着它是空的,API仍在被调用。一旦API调用结束,它将把数据存储到newsData 状态中,并且该状态的长度将变为大于1。

{newsData.length > 1 ? (
                    <FlatList
                        data={newsData}
                        renderItem={({ item }) => (
                            <View>
                                <View style={styles.newsContainer}>
                                    <Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    />
                                    <Text style={styles.title}>
                                        {item.title}
                                    </Text>
                                    <Text style={styles.date}>
                                        {moment(item.publishedAt).format('LLL')}
                                    </Text>
                                    <Text style={styles.newsDescription}>
                                        {item.description}
                                    </Text>
                                </View>
                                <Divider my={2} bg="#e0e0e0" />
                            </View>
                        )}
                        keyExtractor={(item) => item.id}
                    />
                ) : (
                    <View style={styles.spinner}>
                        <Spinner color="danger.400" />
                    </View>
                )}

添加一个旋转器

在我们的样式中,为旋转器添加以下样式代码。

spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
}

旋转器的样式

这是下面的代码,供你参考。

import React, { useEffect, useState } from 'react'
import { View, Text, StyleSheet } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';
import moment from 'moment'
export default function All() {
    const [newsData, setNewsData] = useState([])
    useEffect(() => {
        services('general')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])
    return (
        <NativeBaseProvider>
            <ScrollView height={850}>
                {newsData.length > 1 ? (
                    <FlatList
                        data={newsData}
                        renderItem={({ item }) => (
                            <View>
                                <View style={styles.newsContainer}>
                                    <Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    />
                                    <Text style={styles.title}>
                                        {item.title}
                                    </Text>
                                    <Text style={styles.date}>
                                        {moment(item.publishedAt).format('LLL')}
                                    </Text>
                                    <Text style={styles.newsDescription}>
                                        {item.description}
                                    </Text>
                                </View>
                                <Divider my={2} bg="#e0e0e0" />
                            </View>
                        )}
                        keyExtractor={(item) => item.id}
                    />
                ) : (
                    <View style={styles.spinner}>
                        <Spinner color="danger.400" />
                    </View>
                )}
            </ScrollView>
        </NativeBaseProvider>
    )
}

const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
    spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
    }
});

我们的All.js屏幕现在已经完成了。

现在,我们也可以在所有其他屏幕上使用同样的代码。我们只需要在useEffect Hook中改变我们在服务中传递的参数 。

因此,对于商业屏幕,我们将使用商业。对于健康,我们将使用健康,以此类推。

import React, { useEffect, useState } from 'react'
import { View, Text, StyleSheet } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';
import moment from 'moment'
export default function Business() {
    const [newsData, setNewsData] = useState([])
    useEffect(() => {
        services('business')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])
    return (
        <NativeBaseProvider>
            <ScrollView height={850}>
                {newsData.length > 1 ? (
                    <FlatList
                        data={newsData}
                        renderItem={({ item }) => (
                            <View>
                                <View style={styles.newsContainer}>
                                    <Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    />
                                    <Text style={styles.title}>
                                        {item.title}
                                    </Text>
                                    <Text style={styles.date}>
                                        {moment(item.publishedAt).format('LLL')}
                                    </Text>
                                    <Text style={styles.newsDescription}>
                                        {item.description}
                                    </Text>
                                </View>
                                <Divider my={2} bg="#e0e0e0" />
                            </View>
                        )}
                        keyExtractor={(item) => item.id}
                    />
                ) : (
                    <View style={styles.spinner}>
                        <Spinner color="danger.400" />
                    </View>
                )}
            </ScrollView>
        </NativeBaseProvider>
    )
}

const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
    spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
    }
});

业务屏幕

向下滚动商业屏幕,你会看到与商业有关的新闻。

你也可以对所有其他屏幕做同样的事情。

useEffect(() => {
        services('business')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
}, [])

对于商业

useEffect(() => {
        services('health')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])

健康

useEffect(() => {
        services('sports')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])

体育

useEffect(() => {
        services('technology')
            .then(data => {
                setNewsData(data)
            })
            .catch(error => {
                alert(error)
            })
    }, [])

科技

结语

恭喜你!现在我们的新闻应用已经完成。现在我们的新闻应用程序已经完成。

所以,继续吧,建立和实验一下。你有很多事情可以做。

你可以查看我的播放列表:使用React Native和Native Base构建一个新闻应用程序,这是在我的YouTube频道上。

欢迎在这里下载代码:https://github.com/nishant-666/React-Native-News

快乐学习。


Nishant Kumar

Nishant Kumar

我建立项目是为了学习代码的工作原理。当我不在编码的时候,我喜欢写诗和故事,弹钢琴,做美味的食物。


如果你读到这里,请发推特给作者,向他们表示你的关心。鸣谢

免费学习代码。freeCodeCamp的开源课程已经帮助超过40,000人获得了开发者的工作。开始吧