2023.08.18
BLOG
【ReactNative】映画情報アプリを作ろう!/#3ライブラリを使って画面遷移編
2023-02-10
Youtubeでお送りしているReactNativeをつかった「映画検索アプリ」制作も3回目です。
■過去回はこちら
#1環境設定と画面を作ろう編
#2APIを使って映画一覧画面を作ろう編
前回はAPIを使ってアプリに映画一覧画面を作ることができました。
今回のテーマは画面遷移のライブラリを使って映画詳細画面を作っていきます!
分かりやすく言うと一覧画面のポスター画像をタップすると詳細情報の画面に飛ばすということですね。
以前、ニュースアプリを作成した時にも使いましたが、面遷移をするにはReact Navigationというライブラリが必要になります。
実はReact Native自体には画面遷移が備わっていないので、推奨されているこのライブラリのインストールが必要です。
動画ではインストール方法から詳細画面の作成、実際に画面遷移の実装などご紹介しています!
ファイル数が増えて書くコードの量も増えているので、以下のコードを参考に是非チャレンジしてみてください!
01:08 React Navigationのインストールコマンド
npm install @react-navigation/native
01:15 Native-Stackのインストールコマンドnpm install @react-navigation/native-stack
06:50 追加したstyleconst styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#202328'
},
textBox: {
paddingHorizontal:30,
paddingVertical: 5
},
title: {
color: '#fff',
fontSize: 26,
fontWeight: 'bold'
},
movieReleaseDate: {
color: '#ccc',
marginBottom: 10
},
overview: {
color: '#fff',
fontSize: 18
},
movieImage: {
height: 480,
resizeMode: 'contain'
},
vote: {
flexDirection: 'row',
marginTop: 10,
alignItems: 'center'
},
voteCount: {
color: '#ccc',
marginLeft: 3
},
star: {
color: 'yellow',
backgroundColor: 'transparent',
textShadowColor: 'black',
textShadowOffset: {width: 1, height: 1},
textShadowRadius: 2,
}
})
07:12 react native starsのインストールコマンドexpo install react-native-stars
expo install prop-types
今回の最終コードはこちら!コピぺでも作れちゃいます!
★App.jsimport { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import MovieList from './screens/MovieList';
import MovieDetail from './screens/MovieDetail';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="MovieList" component={MovieList} options={{
title: "映画一覧",
headerStyle: {
backgroundColor: '#202328',
},
headerTintColor: '#fff'
}}/>
<Stack.Screen name="MovieDetail" component={MovieDetail} options={{
title: "映画詳細",
headerStyle: {
backgroundColor: '#202328',
},
headerTintColor: '#fff'
}}/>
</Stack.Navigator>
</NavigationContainer>
)
};
★MovieDetail.jsimport { Text, View, ScrollView, StyleSheet, Image } from "react-native";
import Star from "react-native-stars";
import Ionicons from "@expo/vector-icons/Ionicons";
export default function MovieDetail(props) {
const { movie } = props.route.params;
return (
<ScrollView style={styles.container} >
<Image style={styles.movieImage} source={{uri: `https://image.tmdb.org/t/p/w780${movie.poster_path}`}}></Image>
<View>
<Text style={styles.title}>{movie.title}</Text>
<View style={styles.vote}>
<Star
default={(movie.vote_average/2)}
count={5}
half={true}
fullStar={<Ionicons name="star-sharp" style={styles.star}></Ionicons>}
emptyStar={<Ionicons name="star-outline" style={styles.star}></Ionicons>}
halfStar={<Ionicons name="star-half-sharp" style={styles.star}></Ionicons>}
>
</Star>
<Text style={styles.voteCount}>{movie.vote_count}</Text>
</View>
<Text style={styles.movieReleaseDate}>{movie.release_date}</Text>
<Text style={styles.overview}>{movie.overview}</Text>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#202328'
},
textBox: {
paddingHorizontal:30,
paddingVertical: 5
},
title: {
color: '#fff',
fontSize: 26,
fontWeight: 'bold'
},
movieReleaseDate: {
color: '#ccc',
marginBottom: 10
},
overview: {
color: '#fff',
fontSize: 18
},
movieImage: {
height: 480,
resizeMode: 'contain'
},
vote: {
flexDirection: 'row',
marginTop: 10,
alignItems: 'center'
},
voteCount: {
color: '#ccc',
marginLeft: 3
},
star: {
color: 'yellow',
backgroundColor: 'transparent',
textShadowColor: 'black',
textShadowOffset: {width: 1, height: 1},
textShadowRadius: 2,
}
})
★MovieList.jsimport { StyleSheet, Text, View, ScrollView, FlatList, Image, TouchableOpacity } from 'react-native';
import { requests } from '../request';
import axios from 'axios';
import { useState, useEffect } from 'react';
export default function MovieList({ navigation }) {
const [nowPlaying, setNowPlaying] = useState({});
const [commingSoon, setCommingSoon] = useState({});
const [populars, setPopulars] = useState({});
const [topRated, setTopRated] = useState({});
const [picupMovies, setPicupMovies] = useState({});
useEffect(() => {
async function getMovies() {
try {
const nowPlayingMovies = await axios.get(requests.NOW_PLAYING);
setNowPlaying(nowPlayingMovies.data.results);
const commingSoonMovies = await axios.get(requests.COMMING_SOON);
setCommingSoon(commingSoonMovies.data.results);
const popularsMovies = await axios.get(requests.POPULARS);
setPopulars(popularsMovies.data.results);
const topRatedMovies = await axios.get(requests.TOP_RATED);
setTopRated(topRatedMovies.data.results);
} catch (error) {
console.log(error);
}
}
async function getPickUpMovie() {
try {
const result = await axios.get(requests.NOW_PLAYING);
const number = Math.floor(Math.random() * (result.data.results.length - 1) + 1);
setPicupMovies(result.data.results[number]);
} catch (error) {
console.log(error);
}
}
getMovies();
getPickUpMovie();
}, []);
return (
<ScrollView style={styles.container}>
<TouchableOpacity onPress={() => navigation.navigate("MovieDetail", {movie: picupMovies})}>
<View style={styles.pickupContainer}>
<Image style={styles.pickupImage} source={{uri: `https://image.tmdb.org/t/p/w780${picupMovies.poster_path}`}}></Image>
<Text style={styles.pickupTitle}>{picupMovies.title}</Text>
</View>
</TouchableOpacity>
<Text style={styles.listName}>公開中の映画</Text>
<FlatList
data={nowPlaying}
keyExtractor={item => item.id}
horizontal={true}
flashScrollIndicators
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate("MovieDetail", {movie: item})}>
<View style={styles.movieContainer}>
<Image style={styles.movieImage} source={{uri: `https://image.tmdb.org/t/p/w300${item.poster_path}`}}></Image>
<Text numberOfLines={1} style={styles.movieTitle}>{item.title}</Text>
</View>
</TouchableOpacity>
)}>
</FlatList>
<Text style={styles.listName}>公開予定の映画</Text>
<FlatList
data={commingSoon}
keyExtractor={item => item.id}
horizontal={true}
flashScrollIndicators
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate("MovieDetail", {movie: item})}>
<View style={styles.movieContainer}>
<Image style={styles.movieImage} source={{uri: `https://image.tmdb.org/t/p/w300${item.poster_path}`}}></Image>
<Text numberOfLines={1} style={styles.movieTitle}>{item.title}</Text>
</View>
</TouchableOpacity>
)}>
</FlatList>
<Text style={styles.listName}>人気の映画</Text>
<FlatList
data={populars}
keyExtractor={item => item.id}
horizontal={true}
flashScrollIndicators
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate("MovieDetail", {movie: item})}>
<View style={styles.movieContainer}>
<Image style={styles.movieImage} source={{uri: `https://image.tmdb.org/t/p/w300${item.poster_path}`}}></Image>
<Text numberOfLines={1} style={styles.movieTitle}>{item.title}</Text>
</View>
</TouchableOpacity>
)}>
</FlatList>
<Text style={styles.listName}>高評価の映画</Text>
<FlatList
data={topRated}
keyExtractor={item => item.id}
horizontal={true}
flashScrollIndicators
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate("MovieDetail", {movie: item})}>
<View style={styles.movieContainer}>
<Image style={styles.movieImage} source={{uri: `https://image.tmdb.org/t/p/w300${item.poster_path}`}}></Image>
<Text numberOfLines={1} style={styles.movieTitle}>{item.title}</Text>
</View>
</TouchableOpacity>
)}>
</FlatList>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#202328'
},
pickupContainer: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
pickupImage: {
height: 350,
width: '45%',
resizeMode: 'contain'
},
pickupTitle: {
color: '#fff',
fontSize: 24,
fontWeight: 'bold',
width: '45%',
marginLeft: 5
},
listName: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold',
},
movieContainer: {
width: 130,
marginBottom:30
},
movieImage: {
height: 200,
marginRight: 10,
resizeMode: 'contain'
},
movieTitle: {
color: '#ccc',
fontSize: 14
}
});
株式会社ロックシステム
「ブラック企業をやっつけろ!!」を企業理念にエンジニアが働きやすい環境をつきつめる大阪のシステム開発会社。2014年会社設立以来、残業時間ほぼゼロを達成し、高い従業員還元率でエンジニアファーストな会社としてIT業界に蔓延るブラックなイメージをホワイトに変えられる起爆剤となるべく日々活動中!絶賛エンジニア募集中。
他の記事へ
2022.10.07
【PHP初心者でもできる!】簡単RPG風バトルゲーム作成!変数/演算子/条件分岐
2022.09.28
初心者でも分かる!PHPのいろんな演算子を学ぼう!【算術/代入/比較演算子】
2022.07.29
#5【遂に完成!】PHP、MySQLインスタ風アプリを作る【画像更新、コメント機能】
2021.11.15
【11月号】プライベートが大事!メンバーに聞いた『余暇の時間なにしてる?』
2017.07.31
ロックシステムの風通しの良さやフランクな社風を大事にしたい。
2024.03.11
【簡単ゲームプログラミング】ブロック崩しゲームをつくってみよう!-#3 ブロック崩しゲーム完成!編-【HTML・CSS・JavaScript】
2018.04.11