0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ReactNativeの体験としてStopWatchを作ってみた

Posted at

作成の経緯

ReactNativeのようなクロスプラットフォーム開発がどのようなものなのかが気になったので、作ってみようと思いました。
ReactNativeを選んだのは、最近Reactを学んだからです。

また、友達と競走して作成をしました。

成果物

大体5時間ぐらいかけて作りました。

機能

  • Startを押したとき

    • ストップウォッチが稼働する
    • StartボタンがStopボタンになる
  • Stopを押したとき

    • ストップウォッチが止まる
    • StopボタンがStartボタンになり、Resetボタンが現れる
  • Resetを押したとき

    • ストップウォッチが0になる
    • Resetボタンが消える

ソースコード

### 主なファイル構造

.
├── App.js
└─── components
    ├── Buttons.jsx
    ├── Buttons.jsx
    └── index.js

index.jsはexport用のファイルになります

App.js

ストップウォッチの主な機能を実装しています。

を参考にしつつ、自分で実装を考えてみました。

App.js
import { StatusBar } from 'expo-status-bar';
import React, {useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {StartBtn, StopBtn, ResetBtn, Display} from './components'

const App = () => {

  const [time, setTime] = useState(0)
  const [intervalId, setIntervalId] = useState()

  const startWatch = () => {
    const startTime = new Date().getTime()
    const id = setInterval(() => {
      setTime(new Date().getTime() - startTime + time)
    }, 10)
    setIntervalId(id)
  }

  const stopWatch = () => {
    clearInterval(intervalId)
    setIntervalId(null)
  }

  const resetWatch = () => {
    setTime(0)
  }

  return (
    <View style={styles.container}>
      <Display time={time} />
      <View style={styles.buttons}>
        {time === 0 && (
          <StartBtn startWatch={startWatch}/>
        )}
        {time > 0 && intervalId && (
            <StopBtn stopWatch={stopWatch} />
            )}
        {time > 0 && !intervalId && (
            <React.Fragment>
              <ResetBtn resetWatch={resetWatch}/>
              <StartBtn startWatch={startWatch}/>
            </React.Fragment>
        )}
      </View>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttons: {
    position: 'relative',
  }
});

export default App

Button.jsx

Buttonsのなかにそれぞれのボタンを作成しましたが、これは絶対にButtonというコンポーネントを作って、その引数でスタートボタンやストップボタンを作成するようにすれば良かったと思います。

Buttons.jsx
import React from 'react';
import {StyleSheet, Text,  TouchableOpacity } from 'react-native';

export function StartBtn({startWatch}) {
    return (
      <TouchableOpacity style={buttons.startBtn} onPress={() => startWatch()}>
        <Text style={btnText.start}>Start</Text>
      </TouchableOpacity>          
    )
}

export function StopBtn({stopWatch}) {
    return (
      <TouchableOpacity style={buttons.stopBtn} onPress={() => stopWatch()}>
        <Text style={btnText.stop}>Stop</Text>
      </TouchableOpacity>
    )
}

export function ResetBtn({resetWatch}) {
    return (
      <TouchableOpacity style={buttons.resetBtn} onPress={() => resetWatch()}>
        <Text style={btnText.reset}>Reset</Text>
      </TouchableOpacity>
    )
}

const btnBase = {
    position: 'absolute',
    width: 70,
    height: 70,
    backgroundColor: 'rgba(0,0,0,0.7)',
    borderRadius: 35,
    margin: 4,
    textAlign: 'center',
    justifyContent: 'center',
  }
  
const buttons = StyleSheet.create({
  startBtn: {
    ...btnBase,
    left: 96,
  },
  stopBtn: {
    ...btnBase,
    left: 96,
  },
  resetBtn: {
    ...btnBase,
    right: 96,
  },
})

const btnTextBase = {
  fontSize: 18,
  fontWeight: '500',
  textAlign: 'center',
}

const btnText = StyleSheet.create({
  start: {
    ...btnTextBase,
    color: '#1AFF1A',
  },
  stop: {
    ...btnTextBase,
    color: '#FF1A40',
  },
  reset: {
    ...btnTextBase,
    color: 'white',
  },
  lap: {
    ...btnTextBase,
    color: '#11FF44',
  }
})

Display.jsx

formatDisplayメソッドで、ストップウォッチの表示部分の桁数を揃えるようにしています。

Display.jsx
import React, {useState} from 'react';
import {StyleSheet, Text, View} from 'react-native';

export function Display({time}) {

    const formatDisplay = (number) => {
        // 一桁の場合は、前に0をつける
        // 返却は文字列型になる
        if (number < 10) {
          number = '0' + number
        }
        return number
    }

    return(
        <View style={displays.displayContainer}>
            <Text style={displays.timer}>{formatDisplay(Math.floor(time / (60 * 1000)))}</Text>
            <Text style={displays.colon}>:</Text>
            <Text style={displays.timer}>{formatDisplay(Math.floor(time / (1000)) % 60)}</Text>
            <Text style={displays.colon}>:</Text>
            <Text style={displays.timer}>{formatDisplay(Math.floor((time % 1000) / 10))}</Text>
        </View>
    )
}

const displays = StyleSheet.create({
    displayContainer: {
      flexDirection: 'row',
      justifyContent: 'center',
    },
    timer: {
      width: 100,
      fontSize: 80
    },
    colon: {
      width: 20,
      fontSize: 80
    }
  });

作ってみた感想

簡単なアプリの場合は、調べたら出てきてしまうし、どちらかといえば見た目を整えるのが大変でした。
こういうものは、1時間の海外のチュートリアルを見て作ってしまった方がいいと思いました。

そのため、次に友達との競争をする場合は、簡単なアプリではなく、もう少しアイデアを出してから進めてみたいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?