React Native でスマホアプリ作るぞパート2

前回(React Nativeでスマホアプリ開発してみる)の続きです。

エラーも出たままだったりして若干やっつけなんだけども
ぼちぼち次に取り掛かりたいのと、ブログ更新したくなったので!

はじめてのフロントエンド開発

のDEMOアプリを作ってるときにはすでにだいたいの構造はできてたので後はコーディングするだけだったんですが、やっぱりぜんぶReactでやるのはけっこう大変だと感じたわ。

Reactだけでやると大変やでというのを感じればいいなと思います。

できあがりはこんな感じで、あきらかに書籍のDEMOアプリの感じが漂っていますね。

Javaで作った方のアプリはこんな感じでした。

JavaとJavaScriptでなんか違うかなというと、挙動に差がでるようなアプリじゃないのでとくに違いはないです。。

なのでせっかくなのでIOSでも試してみました。
iphone持ってないので仮装端末ですが。

すんなりいくと思ったけど通信でエラーが出た。
というのもIOSはデフォルトでHTTPを許可してないもよう。
ここでReact Native内にあるIOSの設定を変更する箇所をいじくります。

IOS > [app name] > Info.plist
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

あまり良くない気がしますが、テストアプリだし。

差が出るような機能をつかってないのでなんともなんともやけど、操作感もandroid版と大した差はないね。

最後にコード。

Java版はどんなだったかというのは日本語でさらっと書いときます。
実際には3個のアプリが入ってるんですが、ごちゃごちゃ度合いでいうとReactで書いたコードの方がごちゃごちゃしてますw

RetrofitのInterfaceがあって、いくつかのGETを定義してます。
んで、それぞれの欲しいデータの型を定義したクラスがいくつかあり。
メニューバーに使うFragmentというのがあり。
んでから、それぞれのアプリごとのActivityのクラスと、XMLにバインディングしてる
ViewModelがあります。そんな感じ。

Reactの方はこんな感じです。

// index.js
import { AppRegistry } from 'react-native';
import App from './App';

AppRegistry.registerComponent('HogeWeather', () => App);
// App.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StackNavigator,
  DrawerNavigator
} from 'react-navigation';
import {
  Platform,
  Text,
  StyleSheet,
  View,
  FlatList,
  Image,
  TextInput,
  Button,
  TouchableOpacity,
} from 'react-native';

import styles from './style';
import WeekUv from './WeekUv';
import DayUv from './DayUv';

const AppDrawerNavigator = DrawerNavigator({
  UVDaylyCheck: {
    screen: StackNavigator({ Home: { screen: DayUv } }, { initialRouteParams: { channelName: 'Uv Check' } }),
    navigationOptions: { drawerLabel: 'UV Dayly Check' },
  },
  UVWeeklyCheck: {
    screen: StackNavigator({ Home: { screen: WeekUv } }, { initialRouteParams: { channelName: 'Uv Check' } }),
    navigationOptions: { drawerLabel: 'UV Weekly Check' },
  }
});

export default class App extends Component<{}> {

  render() {
    return (
      <AppDrawerNavigator />
    );
  }
}
// DavUv.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { type NavigationScreenProp } from 'react-navigation';
import {
	Platform,
	Text,
	StyleSheet,
	View,
	FlatList,
	Image,
	TextInput,
	Button,
	TouchableOpacity,
} from 'react-native';
import styles from './style';

const baseURL = 'http://api.openweathermap.org';

const uvOneDayURL = '/data/2.5/uvi?appid=hoge&lat=34.70&lon=135.50';

const weatherURL = '/data/2.5/weather?q=hoge,jp&appid=hoge&units=metric';


type Props = {
	navigation: NavigationScreenProp<*>,
};

type State = {
	messagesDayUvd: Array<DayUvd>,
	messagesDayMain: Array<DayMain>,
	messagesDaySys: Array<DaySys>,
	messagesDayWea: Array<DayWea>,
};

type DayUvd = {
	lat: number,
	lon: number,
	date_iso: number,
	date: number,
	value: number,
}

type DayMain = {
	temp: number,
	pressure: number,
	humidity: number,
	temp_min: number,
	temp_max: number,
}

type DaySys = {
	type: number,
	id: number,
	message: number,
	country: string,
	sunrise: number,
	sunset: number,
}

type DayWea = {
	id: string,
	main: string,
	description: string,
	icon: string,
}

export default class DayUv extends Component<Props, State> {
	static navigationOptions = ({ navigation }: { navigation: NavigationScreenProp<*> }) => ({
		title: `${navigation.state.params.channelName}`,
		headerLeft:
			<TouchableOpacity style={{ padding: 8 }} onPress={() => navigation.navigate('DrawerToggle')}>
				<Image style={{ width: 32, height: 32 }} source={require('./images/menu.png')} />
			</TouchableOpacity>
	})
	constructor(props: Props) {
		super(props);
		this.state = {
			messagesDayUvd: [],
			messagesDayMain: [],
			messagesDayWea: [],
			messagesDaySys: []
		};
		this.changeUTtoDate = this.changeUTtoDate.bind(this);
		this.cautionMessage = this.cautionMessage.bind(this);
		this.changFtoC = this.changFtoC.bind(this);
		this.changeDate = this.changeDate.bind(this);
	}

	changFtoC = (v: number) => {
		return (v - 32) / 1.8;
	}

	cautionMessage = (value: number) => {
		if (value < 2.0) {
			return "ひくい";
		} else if (value < 5.9) {
			return "ふつう";
		} else if (value < 7.9) {
			return "たかい";
		} else if (value < 10.9) {
			return "超たかい";
		} else {
			return "やばい";
		}
	}

	changeUTtoDate = (value: number) => {
		var d = new Date(value * 1000);
		var year = d.getFullYear();
		var month = d.getMonth() + 1;
		var day = d.getDate();
		var valueOfDay = (d.getDay());
		var dayofweek = ["日", "月", "火", "水", "木", "金", "土"];
		var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

		return (year + '年' + month + '月' + day + '日' + dayofweek[valueOfDay] + '曜日');
	}

	changeDate = (v: number) => {
		var d = new Date(v * 1000);
		var hour = ('0' + d.getHours()).slice(-2);
		var min = ('0' + d.getMinutes()).slice(-2);

		return (hour + ' : ' + min);
	}

	componentDidMount() {
		fetch(baseURL + uvOneDayURL)
			.then((response) => response.json())
			.then((json) => {
				this.setState({
					messagesDayUvd: json
				})
			})
			.catch((error) => {
				alert(error)
			});
		fetch(baseURL + weatherURL)
			.then((response) => response.json())
			.then((json) => {
				this.setState({
					messagesDayMain: json.main,
					messagesDaySys: json.sys,
					messagesDayWea: json.weather[0]
				})
			})
			.catch((error) => {
				alert(error)
			});
	}

	render() {
		return (
			<View style={styles.container}>
				<View style={styles.header}>
					<Text style={styles.title}>
						UV情報と今日の天気
					</Text>
				</View>
				<View style={styles.body}>
					<Text style={styles.bodyFont}>{this.changeUTtoDate(this.state.messagesDayUvd.date)}の天気</Text>
					<Text style={styles.bodyFont}>{this.state.messagesDayWea.main}</Text>
					<Text style={styles.bodydesc}>{this.state.messagesDayWea.description}</Text>
					<View>
						<Text style={styles.tableBody}>紫外線量:{this.state.messagesDayUvd.value} - {this.cautionMessage(this.state.messagesDayUvd.value)}</Text>
					</View>
					<Text style={styles.bodyFont}>気温 			:{this.state.messagesDayMain.temp}</Text>
					<Text style={styles.bodyFont}>日の出		:{this.changeDate(this.state.messagesDaySys.sunrise)}</Text>
					<Text style={styles.bodyFont}>日の入		:{this.changeDate(this.state.messagesDaySys.sunset)}</Text>
				</View>
			</View >
		);
	}
}


// WeekUv.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { type NavigationScreenProp } from 'react-navigation';
import {
	Platform,
	Text,
	StyleSheet,
	View,
	FlatList,
	Image,
	TextInput,
	Button,
	TouchableOpacity,
} from 'react-native';
import styles from './style';

const baseURL = 'http://api.openweathermap.org';

const uvURL = '/data/2.5/uvi/forecast?lat=34.70&lon=135.50&appid=hoge&cnt=6';

type Props = {
	navigation: NavigationScreenProp<*>,
};

type State = {
	messages: Array<Message>,
};

type Message = {
	lat: number,
	lon: number,
	date_iso: number,
	date: number,
	value: number,
}

type MessageCellProps = {
	message: Message
};

const MessageCell =
	(props: MessageCellProps) =>
		<View>
			<View style={styles.table}>
				<Text style={styles.tableDate}>日にち:{changeUTtoDate(props.message.date)}</Text>
				<Text style={styles.tableBody}>紫外線量:{props.message.value} - {cautionMessage(props.message.value)}</Text>
			</View >
		</View>

let cautionMessage = (value) => {
	if (value < 2.0) {
		return "ひくい";
	} else if (value < 5.9) {
		return "ふつう";
	} else if (value < 7.9) {
		return "たかい";
	} else if (value < 10.9) {
		return "超たかい";
	} else {
		return "やばい";
	}
}

let changeUTtoDate = (value) => {
	var d = new Date(value * 1000);
	var year = d.getFullYear();
	var month = d.getMonth() + 1;
	var day = d.getDate();
	var valueOfDay = (d.getDay());
	var dayofweek = ["日", "月", "火", "水", "木", "金", "土"];
	var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

	return (dayofweek[valueOfDay] + ' , ' + day + ' , ' + monthName[month] + '  ' + year);
}

export default class WeekUv extends Component<Props, State> {
	static navigationOptions = ({ navigation }: { navigation: NavigationScreenProp<*> }) => ({
		title: `${navigation.state.params.channelName}`,
		headerLeft:
			<TouchableOpacity style={{ padding: 8 }} onPress={() => navigation.navigate('DrawerToggle')}>
				<Image style={{ width: 32, height: 32 }} source={require('./images/menu.png')} />
			</TouchableOpacity>
	})
	constructor(props: Props) {
		super(props)
		this.state = { messages: [] };
	}

	componentDidMount() {
		fetch(baseURL + uvURL)
			.then((response) => response.json())
			.then((json) => {
				this.setState({ messages: json })
			})
			.catch((error) => {
				alert(error)
			});
	}

	render() {
		return (
			<View style={styles.container}>
				<View style={styles.header}>
					<Text style={styles.title}>
						1週間のUV情報
        </Text>
				</View>
				<View>
					<FlatList
						style={styles.list}
						data={this.state.messages.slice()}
						renderItem={({ item }) => <MessageCell message={item} />}
					/>
				</View>
			</View >
		);
	}
}


import { StyleSheet } from 'react-native';

export default StyleSheet.create({
	container: {
		flex: 1,
		backgroundColor: '#f5deb3',
	},
	header: {
		borderBottomWidth: 10,
		borderColor: '#f4a460',
		margin: 16,
	},
	title: {
		fontSize: 26,
		color: '#000000',
		marginLeft: 10,
	},
	table: {
		width: "95%",
		backgroundColor: "#f1dab0",
		marginLeft: "5%",
		marginBottom: 10,
		borderColor: '#F0F0F0',
	},
	tableBody: {
		fontSize: 24
	},
	tableDate: {
		fontSize: 16
	},
	body: {
		margin: 10
	},
	bodyFont: {
		fontSize: 23
	},
	bodydesc: {
		borderBottomWidth: 1,
		fontSize: 20,
		borderColor: '#f4a460',
		marginBottom: 10,
	}
});


つぎはデータ管理つかいたいね。

Related Posts


投稿者: Takeken

インターネット利用者のITリテラシーを向上したいという設定の2次元キャラです。 サーバー弄りからプログラミングまで手を付けた自称エッセイストなたけけんの物語。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です