ローディング中

react nativeで一人前のiOSアプリ開発者を目指す 第5回 天気予報アプリを改良する

こんにちは、個別指導塾コミット塾長、AWESOME開発担当の船津です。
今回はネイティブのgeolocationAPIを使って天気予報アプリを少し改良してみたいと思います。

目次

やりたいことは…

最初に開くと、現在地を取得して天気を表示してくれる。
都市名を入力するとその地域の天気を表示してくれる
「現在地から天気を取得するボタン」を設置

作成するファイルは以下の3つ

index.ios.js アプリ登録
forecast.js 天気予報表示
Firstproject.js APIを操作したり、フォームを作ったり

index.ios.js forecast.jsについては第二回とほぼ変わらないのでこちらを見て下さい。

初めてアプリを作る方はまず
react-native init FirstProjectをしてください

それではFirstProject.jsの中身を見ていきます。

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  TextInput,
  View,
  Image,
  TouchableHighlight
} from 'react-native';

var Forecast = require('./Forecast');
var forecastContent = null;
// アドレスを変数にしておきます
var API_STEM = 'http://api.openweathermap.org/data/2.5/weather?';
// APIキーも変数にしておきます
var API_KEY = 'hogehogehoge';


class FirstProject extends Component {
  constructor() {
    super();
    this.state = {
      zip: '',
      forecast: null
    };
    this._getForcastForZip = this._getForcastForZip.bind(this);
    this._getCurrentPosition = this._getCurrentPosition.bind(this);
    this._getForcastForCoords = this._getForcastForCoords.bind(this);
  }
	// アプリを開いた時に_getCurrentPositionを呼び出します。
  componentDidMount() {
    this._getCurrentPosition();
  }
  // 天気予報APIから情報を取得します
  _getForcast(url,cb){
    fetch(url)
      .then((response) => response.json())
      .then((responseJSON) => {
        this.setState({
          forecast: {
            main: responseJSON.weather[0].main,
            description: responseJSON.weather[0].description,
            temp: Math.floor(responseJSON.main.temp - 273),
            city: responseJSON.name
          }
        });
      })
      .catch((error) => {
        console.warn(error);
      });
  }
  // zipコード、もしくは都市名を入力した時の処理です。
  _getForcastForZip(event){
    var zip = event.nativeEvent.text;
    this.setState({
      zip:zip
    });
    this._getForcast(<code>${API_STEM}q=${zip}&amp;amp;amp;APPID=${API_KEY}</code>);
  }
	// 位置情報を引数として天気予報APIから情報を取得します。
  _getForcastForCoords(lat, lon){
    this._getForcast(<code>${API_STEM}lat=${lat}&amp;amp;amp;lon=${lon}&amp;amp;amp;APPID=${API_KEY}</code>);
  }
  // iosのネイティブAPIを利用して現在地を取得し、setStateで値を保持、天気予報APIの呼び出しまで行います。
  _getCurrentPosition(){
    navigator.geolocation.getCurrentPosition(
      (initialPosition) =&amp;amp;gt; {
        this.setState({
          latitude: initialPosition.coords.latitude,
          longitude: initialPosition.coords.longitude,
        });
        this._getForcastForCoords(this.state.latitude,this.state.longitude);
      },
      (error) =&amp;amp;gt; alert(error.message),
      {enableHighAccuracy:true, timeout: 20000, maximumAge:1000}
    );
  }
  
	// ほぼ第2回と同じですが、都市名をcityとしてsetStateしています。
render() {
    if (this.state.forecast !== null) {
      forecastContent = <Forecast
      main={this.state.forecast.main}
      description={this.state.forecast.description}
      temp={this.state.forecast.temp}
      city={this.state.forecast.city}/>;
    }
    return (
      <View style={styles.container}>
        <Image
          source={{uri: 'https://s3‑ap‑northeast‑1.amazonaws.com/wp-content/uploads/2016/06/21145923/RIMG0202-450x600.jpg'}}
          resizeMode='cover'
          style={styles.backdrop}>
          <View style={styles.overlay}>
            <View style={styles.row}>
              <Text style={styles.mainText}>
                Current Weather For
              </Text>
              <View style={styles.zipContainer}>
                <TextInput
                  placeholder="Please input city name or zip code"
                  style={[styles.zipCode, styles.mainText]}
                  returnKeyType="go"
                  onSubmitEditing={this._getForcastForZip}/>
              </View>
            </View>
            // react nativeではボタンはtouchabkeHighlightで表現するようです。現在地の位置情報から天気予報APIを呼び出します。
            <TouchableHighlight onPress={this._getCurrentPosition} style={styles.button}>
              <Text>
                Use Current Location
              </Text>
            </TouchableHighlight>
            {forecastContent}
          </View>
        </Image>
      </View>
    );
  }
}

var baseFontSize = 16;
var styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    paddingTop: 30,
  },
  backdrop: {
    flex: 1,
    flexDirection: 'column',
    alignSelf: 'stretch',
  },
  overlay : {
    paddingTop: 5 ,
    backgroundColor: '#000000',
    opacity: 0.5 ,
    flexDirection: 'column',
    alignItems: 'center',
  },
  row: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'nowrap',
    alignItems: 'flex-start',
    padding: 30,
  },
  mainText: {
    fontSize: baseFontSize,
    color: '#fff',
    alignItems: 'center',
  },
  zipContainer: {
    flex: 2,
    borderColor:'#ade248',
    borderBottomWidth: 1,
    borderRadius: 4,
    marginLeft: 5,
    marginTop: 3,
  },
  zipCode: {
    width: 100 ,
    height: baseFontSize,
  },
  button: {
    flex: 2,
    padding: 15,
    marginBottom: 20,
    borderWidth: 2,
    borderColor: 'white',
    opacity: 0.8,
    borderRadius: 4,
    backgroundColor: 'white',
  }
});

module.exports = FirstProject;

完成するとこのような画面になります。

こちらが初期の画面、現在地の天気予報を取得して表示します。

スクリーンショット 2016-07-05 17.37.08

こちらが都市名を入力した後、ちゃんと変わりますね。

スクリーンショット 2016-07-05 17.54.05

真ん中のボタンを押すとまた初期の表示に戻ります。

位置情報の取得を別ファイルで管理しようとしましたが、あまりうまくいかなかったので一つのファイルにまとめてあります。
this.propsやthis.stateの使い分け、外部コンポーネントとの値の受け渡し方法、呼び出し方はまだまだわかっていない部分が多いです。またそのあたりの知識がまとまってきたらブログにしようと思います。

改善点

純正アプリのように色々な地点の天気をタブで切り替えられるようにしたいですね。

次回はカメラAPIを使用していきます。

ホームページ・デザイン制作のご相談・ご依頼は

079-451-5881

68ED4C65-BA1E-46D0-A7AC-B9869923C696 Created with sketchtool. A07C553F-CF16-4B7D-94FE-D36AE0A6297D Created with sketchtool. 37B7D8F4-7A18-4725-9EC6-595ABDF69D64 Created with sketchtool. 95DFB680-1EDF-4199-BC4A-BB6752EBA23C Created with sketchtool. 02DDF754-E1DB-4EF2-B6BB-C884722938C4 Created with sketchtool. NEW! 1A95E369-6469-4C46-B38F-F83410B928B0 Created with sketchtool. Group 5Group 2Group 4Group 3E4FC8CF2-721D-4699-8162-18E886C432C1 Created with sketchtool.