子供用の学習アプリケーションを作る(1)

# はじめに
昨日、**筋萎縮性側索硬化症(ALS)**と呼ばれる病気についての記事を見かけ、以前より知っている病気ではあったものの**なぜ、この病気になってしまうのかについては、知らなかった。**
ネットで調べてみたところ、様々なサイトで解説されているものの、言葉が難しかったり、文字数が多く読むのが大変であった。

そこで、そのような知識を分かりやすく、まとめ尚且つ大人から子供まで使えるような学習アプリケーションを自作してみました。

## 実装
まず、環境構築については、下記の記事を見ていただければと思います。
[参考: React Nativeをはじめる(環境構築)](https://qiita.com/yoshii0110/items/b6b85767d1e2abeac95a)

### ディレクトリ構成
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/36be7c86-8560-0a86-551e-c4c1f71c6877.png" width="150px">

### 使用したUI component, ライブラリ, フリーイラスト
**UI component**
1.React-native-elements
React-Native-Elementsは、フリーのクロスプラットフォームのUIcomponentです。
色々な開発者が作成したcomponentが集められ、クオリティもかなり高いです。

2.React-native-paper
React-native-paperは、使いやすく設計されているUIcomponentです。
componentは、Googleのマテリアル基準に準拠しているのでデザイン性がかなり高いという感想です。

**ライブラリ**
1.React Navigation
React Navigationは、画面遷移のライブラリです。
なぜ、このライブラリが必要かというと、Reactでは画面遷移のための機能が用意されていないからです。

React Navigationでは３つの方法で画面遷移ができます。

**1.stack：スライドしながら画面遷移する方法**
2.tabs：タブを選択することで画面遷移する方法
3.drawer：画面端から現れるメニューで画面遷移する方法

今回は、**1**の方法で実装を行いました。

**フリーイラスト**
1.manypixels
manypixelsは、フラットなイラストをフリーでdlできます。

#### App.js
このファイルではメインとなるページの処理を記載しています。

```App.js

import 'react-native-gesture-handler';
import * as React from 'react';
import {Image, SafeAreaView, ScrollView, StyleSheet} from 'react-native';
import {Text, Card, Button} from 'react-native-elements';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import AppHeader from './components/header';
import contentsSelect from './components/contentsSelect';

const HomeScreen = ({navigation}) => {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView>
        <AppHeader />
        <Text h2 style={styles.hearderMessage}>
          For explorer who want to know the unknown
        </Text>
        <Text style={styles.hearderMessageBody}>
          ilearnはさまざまなトピックスをまとめ{'\n'}発信する場所だよ。
        </Text>

        <Card>
          <Card.Title>探検をはじめよう！</Card.Title>
          <Card.Divider />
          <Image
            source={require('../public/img/teach.png')}
            style={styles.cardImage}
          />
          <Text style={styles.cardText}>
            医学,科学,数学,コンピュータ・サイエンス,宇宙,{'\n'}歴史をまなぼう。
          </Text>

          <Button
            style={styles.cardButtonText}
            title="出発する🚀"
            onPress={() => navigation.navigate('Contents')}
          />
        </Card>
      </ScrollView>
    </SafeAreaView>
  );
};

const Stack = createStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Contents" component={contentsSelect} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  headerImg: {
    width: 90,
    height: 30,
    top: 60,
  },
  hearderMessage: {
    marginTop: 100,
    textAlign: 'center',
  },
  hearderMessageBody: {
    flex: 1,
    top: 20,
    marginBottom: 60,
    textAlign: 'center',
    fontWeight: 'bold',
    color: '#93a5b1',
  },
  cardImage: {
    width: 350,
    height: 350,
  },
  cardText: {
    marginBottom: 10,
  },
  cardButtonText: {
    marginTop: 20,
    marginBottom: 20,
  },
});

export default App;
```

#### header component
名前から察するようにヘッダーについてまとめたファイルになります。

```header.js
import React from 'react';
import {View, StyleSheet, Image} from 'react-native';

const AppHeader = () => {
  return (
    <View>
      <Image
        source={require('../../public/img/Header.png')}
        style={styles.headerImg}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  headerImg: {
    width: 90,
    height: 30,
    marginLeft: 20,
    top: 30,
  },
});

export default AppHeader;

```
#### contents component
こちらのcontents componentは、ユーザが実際に何のコンテンツについて学びたいかを選ばせるページの処理をまとめています。

```contentsSelect.js
import React from 'react';
import {SafeAreaView, ScrollView, StyleSheet} from 'react-native';
import {Card, Title} from 'react-native-paper';
import AppHeader from './header';

const contentsSelect = () => {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView>
        <AppHeader />
        <Card style={styles.cardPadding}>
          <Card.Content>
            <Title style={styles.cardTitle}>宇宙って？</Title>
            <Card.Cover
              source={require('../../public/img/alien.png')}
              style={styles.cardImg}
            />
          </Card.Content>
        </Card>
        <Card style={styles.cardPadding}>
          <Card.Content>
            <Title style={styles.cardTitle}>ALSって知ってる？</Title>
            <Card.Cover
              source={require('../../public/img/health.png')}
              style={styles.cardImg}
            />
          </Card.Content>
        </Card>
        <Card style={styles.cardPadding}>
          <Card.Content>
            <Title style={styles.cardTitle}>Falcon 9がすごい</Title>
            <Card.Cover
              source={require('../../public/img/startup_isometric.png')}
              style={styles.cardImg}
            />
          </Card.Content>
        </Card>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  cardImg: {
    height: 300,
  },
  cardPadding: {
    marginBottom: 20,
  },
  cardTitle: {
    fontWeight: 'bold',
  },
});

export default contentsSelect;

```

## 動作

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/6e5a0eca-8a7a-ddda-ed5d-ae3167b9c134.gif)


## 次回
次回は、コンテンツ選択した後の詳細画面を作り込んでいこうと思います。

# おわり
かなり気合を入れて作成を始めたので、随時記事も更新していこうと思います。
また、React-vativeをさわってみたい方に対し、開発コードがお役に立てば幸いです。

# 参考
[React-native](https://reactnative.dev/docs/image)
[React-native-elements](https://reactnativeelements.com/)
[React Navigation](https://reactnavigation.org/)
[React-native-paper](https://callstack.github.io/react-native-paper/2.0/index.html)
[manypixels](https://www.manypixels.co/gallery/?page=1&style=image)
[難病情報センター: ALS](https://www.nanbyou.or.jp/entry/52)