想要用RN写个小说APP第一天【页面结构💨】

3,387 阅读4分钟

我正在参加「掘金·启航计划」

唠唠叨叨

作为一个每天不是摆烂看小说就是睡🐖觉的带三学生,小说app是我我手机应用里打开时间最久的应用(这是可以说的吗(・∀・(・∀・(・∀・*)?故事还要从那天说起我想要清理内存说起。。。。我勾选着那些不再常用的应用->全选删除,duang!内存瞬间好起来了!嘿嘿!下一刻,当我想要顺手继续看小说时??我熟练的点开那个位置,欸?怎么看不到了?它怎么不见了??我意识到一件事,我误删了~这一刻,我瞬间回想着我是否还能记得我看过的小说。一阵折腾过后,他回来了,但也只有着空荡荡的列表 ~
这一刻,我脑袋里闪过一个flag💭💭 ~>
我能不能自己弄一个自动备份的小说app,也就有了现在这篇文章💣

说干就干,该用什么?

这是我的项目地址,star看我后续更新🌠🌠🌠
作为安卓用户,我有这些选择:

  1. Android原生(我不会)
  2. ReactNative(不选这个选什么??)
  3. Flutter(还是不会)

准备工作

  1. 敲代码利器VsCode
  2. RN官方文档一份
  3. 善于制造bug的双手
  4. 一颗善于搜索的心

页面结构

主要分为三部分,左边是排行榜,中间是小说内容

image.png

image.png


如何实现

作为一个大一就开始切图的小菜比,想要实现这个效果,我需要的是一个类似于路由管理的插件。在RN中也就是navigator,我在文档中找到了它React Native Navigation。我打开了他并通过浏览的翻译插件帮助,磕磕绊绊的看了一遍后。开始了我的实现之旅。

使用自带标签导航器Tab.Navigator

要求使用NavigationContainer作为顶层组件:

const App = () => {
  return (
    <NavigationContainer theme={MyTheme}>
    // 这是控制导航栏的组件
      <StatusBar
        translucent={true}
        backgroundColor="transparent"
        barStyle={'dark-content'}
      />
      <NovelTabs />
    </NavigationContainer>
  );
};

NovelTabs组件中,在下面有几个导航选项,就有几个Tab.Screen子元素,通过tabBarIcon配置项进行自定义Icon图标,通过传入参数的解构出的focused,判断当前选中的Tab栏并设置选中样式,如下:


function NovelTabs() {
  return (
    <Tab.Navigator
      initialRouteName="阅读"
      screenOptions={({route}) => ({
        tabBarIcon: ({focused, color}) => {
          let iconName: IconNames;
          switch (route.name) {
            case '阅读':
              iconName = 'all';
              break;
            case '设置':
              iconName = 'set';
              break;
            case '浏览':
              iconName = 'form';
              break;
            default:
              iconName = 'all';
          }
          return (
            <View style={Style.bar}>
              <IconFont
                name={focused ? `${iconName}-fill` : iconName}
                color={color}
                size={27}
              />
              {focused && (
                <Text style={{...Style.barText, color}}>{route.name}</Text>
              )}
            </View>
          );
        },
        tabBarActiveTintColor: '#1892a6',
        tabBarInactiveTintColor: 'gray',
        tabBarLabelPosition: 'beside-icon',
        tabBarActiveBackgroundColor: '#e2f1f4',
        tabBarItemStyle: {
          borderRadius: 15,
          marginHorizontal: 15,
          marginVertical: 10,
        },
        tabBarShowLabel: false,
        headerShown: false,
        tabBarStyle: {
          ...getTabBarStyle(route),
          height: 60,
        },
      })}>
      <Tab.Screen name="浏览" component={Scan} />
      <Tab.Screen
        name="阅读"
        component={ReaderScreen}
        options={{
          headerShown: false,
        }}
      />
      <Tab.Screen name="设置" component={Setting} />
    </Tab.Navigator>
  );
}

这段代码通过阅读文档,可以很容易的写出来。而在之后,我很快就遇到了问题。
在上面的传入给Tab.Screencomponent=>ReaderScreen组件中,具体代码:

const ReaderScreen: React.FC = ({navigation}: any) => {
  const {bgColor} = useContentSetStore();
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="NovelList"
        component={novelList}
        options={{
          headerShadowVisible: false,
          header: HeaderCustom,
        }}
      />
      <Stack.Screen
        name="NovelContent"
        component={NovelContent}
        options={{
          contentStyle: {
            backgroundColor: bgColor,
          },
          headerShown: false,
          animation: 'fade',
        }}
      />
    </Stack.Navigator>
  );
};

这是一个包含能够导航控制多个页面的的组件,而当你写好demo代码进行测试时,你会发现,每一个页面都是默认显示下方的Tab栏,这与我的要求是不相符的,我需要比如用户通过点击小说列表页<novelList/>的小说进入小说内容<NovelContent/>,这时导航栏的隐藏的。我第一时间就去文档中查看配置项,发现官网并没有给出较简易的配置来实现我的要求。
经过一段时间的搜寻后:我得到了这样的一个解决方案:通过在进入每一个路由中导航栏时,判断当前的页面是否需要显示导航栏。不用显示就将其Style属性设置为display:none;getFocusedRouteNameFromRoute是官网给我们的能够通过route对象得到具体的routeName
SHOW_TAB_BAR_LIST是我定义的一个需要显示导航栏的静态变量。具体代码如下:

const SHOW_TAB_BAR_LIST = ['阅读', '设置', '浏览', 'NovelList'];
const getTabBarStyle = (route: any) => {
  const routeName = getFocusedRouteNameFromRoute(route);
  let display = SHOW_TAB_BAR_LIST.includes(routeName ?? '阅读')
    ? 'flex'
    : 'none';
  return {display};
};

这次滴内容就写到这了,后续计划更新的内容有: (下面的计划都是已经大致完成了💨)