前回の続き
https://qiita.com/O_Hiroki/items/ad9653e5ed9e3ee84e85
環境などの下地はできたのでちゃんと画面を作っていきます。
前回こんな感じの画面にしようと決めてそれに向けて実装することにします。
ちょっと違うけどできました。まあいいでしょう。
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Button, ScrollView, TouchableOpacity, Image, Dimensions, } from 'react-native';
import { Link } from "expo-router";
import { useRouter, } from 'expo-router'
export default function App() {
const router = useRouter();
const userId = 'user_id1'
const screenWidth = Dimensions.get('window').width - 20;
const scrollViewStyle = {
width: screenWidth,
}
const moveToRoom = (roomId: string) => {
router.push({
pathname: "/(app)/[id]",
params: {
id: roomId,
},
});
}
const rooms = [
{
room_id: '1',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '2',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '3',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '4',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '5',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '6',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '7',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '8',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '9',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '10',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '11',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
{
room_id: '12',
users: [
{
user_id: 'user_id2',
user_name: 'user_name2'
},
]
},
]
return (
<>
<View style={styles.topStyle}>
<Text style={styles.title}>ルーム選択</Text>
</View>
<View style={styles.container}>
<ScrollView contentContainerStyle={scrollViewStyle}>
{
rooms.map((room) => {
return (
<TouchableOpacity style={styles.roomStyle} onPress={() => moveToRoom(room.room_id)}>
<Image source={require('../../assets/ellipse.png')} style={styles.avator}></Image>
<View style={styles.nameArea}>
<Text>{room.users[0].user_name}</Text>
<Text numberOfLines={1}>会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容会話の内容</Text>
</View>
</TouchableOpacity>
)
})
}
</ScrollView>
<StatusBar style="auto" />
</View>
</>
);
}
const styles = StyleSheet.create({
topStyle: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'flex-start',
},
scrollView: {
width: '100%',
},
avator: {
width: 80,
height: 80,
},
title: {
fontSize: 30,
},
nameArea: {
flexDirection: 'column',
marginLeft: 6,
marginTop: -20,
},
roomStyle: {
marginLeft: 10,
marginRight: 10,
paddingRight: 70,
height: 100,
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'row',
},
container: {
flex: 8,
width: '100%',
height: '100%',
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'flex-start',
flexDirection: 'column'
},
});
こんな感じで作りました。多分ベストではない気がします。
通常のフロントエンド開発と異なる部分
通常のフロントエンド開発と異なる点が何点かでてきました。
divは存在しない
divやspan、aといった要素はreact nativeでは存在しないようです。
代わりに
div -> View
span, a -> Text
というコンポーネントたちを使用するみたいです。
スクロールできる要素はViewへのスタイリングではできない
通常であればdivにoverflow: scrollでもつけておけばその要素内で勝手にスクロールしてくれますがreact nativeではScrollViewというコンポーネントを使用するみたいです。
これがまた困惑したんですがScrollViewではstyle={hoge}のような書き方はできずcontentContainerStyleに対してスタイルを渡すみたいです。
ViewにonPressは使えない
divにonClickをつける感覚でViewにonPressを渡してみたんですがどうにもうまくいかず。調べてみたところViewに対してonClickはつけられないみたいでした。
divにonClickをつけるというのは会話一覧のそれぞれの相手ユーザーのカードをクリックする、というイメージでした。これではどうにもダメらしくTouchableOpacityを使うと付けられるみたいです。
text-overflowが存在しない
会話の内容を表示するところで枠をオーバーした場合に...にしたかったんですがtext-overflowなんてものはなくTextコンポーネントにnumberOfLines={x}を指定するらしいです。こっちの方が便利ですね。
個人的に詰まった部分
端っこの見切れ
画像を撮っていなかったんですがルームを選択するTouchableOpacityの右側が見切れていました。右端が見えない状態ですね。width:100%で上の要素ではなく画面全体の幅になっているのかな?という感じでした(詳細まではみていないのでわかりませんが)
paddingで強引に左に端を寄せて解決しました。これの綺麗な解決方とかあったら教えて欲しいです。
scrollViewの幅を100%にしても広がらない
scrollViewの幅を横に最大まで広げたかったんですがwidth: 100%を指定しても広がらず。
結局Dimensionsから画面の幅を取得して設定しましたがあまり気に入らないですね
一応ルーム選択画面はさっくり作れたので他の画面も作ってみて詰まったところがあればメモろうと思います。
次はfirebaseを導入してみます。