作成の経緯
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時間の海外のチュートリアルを見て作ってしまった方がいいと思いました。
そのため、次に友達との競争をする場合は、簡単なアプリではなく、もう少しアイデアを出してから進めてみたいと思います。