20210907のiOSに関する記事は4件です。

【React Native】ただ写真ライブラリから写真を取得するだけでなく、加工して表示させる方法

写真ライブラリから写真を取得し、自分の好きなサイズに加工して表示させる ReactNativeで写真ライブラリから写真を取得する方法はいくつかありますが、その中で加工や編集も行えるライブラリを紹介します。 ライブラリのGitHub https://github.com/ivpusic/react-native-image-crop-picker もともとreact-native-image-pickerというライブラリがあり、それを使えば「カメラを起動させるか」「写真ライブラリを開くか」の選択欄も出て、どちらも実装できる便利なものがありましたが、最近のアップデートで選択欄が出なくなったり何かと使いにくなりました。 image-pickerのGitHub https://github.com/react-native-image-picker/react-native-image-picker またこのライブラリで写真を取得してもそのまま表示されるため、実際にアプリに入れてみないと調整が難しいです。 例えば、アイコンを設定する際に写真全体を表示するのではなく、右下の一部分だけを表示したいとなった時に、従来のimage-pickerだと、まず写真ライブラリ使う写真の加工をして、それを保存してから使わないといけません。 そこがimage-crop-pickerを使うことでアプリ側で加工するためのviewを挟んでくれるため、その場で写真の加工を行えます 実際に実装し、両方を比べてみる 実際にimage-pickerとimage-crop-pickerの両方を実装し、比べてみます。 1、ライブラリをインストール react-native-image-crop-picker:yarn add react-native-image-crop-picker react-native-image-picker:yarn add react-native-image-picker このライブラリでは写真ライブラリにアクセスしたり、カメラを起動させるためinfo.plistに設定が必要です。 ios iOSディレクトリ内のinfo.plistに追記してください <key>NSPhotoLibraryUsageDescription</key> <string>${プロジェクト名など} would like to upload photos from your photo gallery</string> <key>NSCameraUsageDescription</key> <string>${プロジェクト名など} requires to access camera for uploading photos to your profile or posts</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>${プロジェクト名など} would like to save photos to your photo gallery</string> <key>NSMicrophoneUsageDescription</key> <string>${プロジェクト名など}requires to access Audio recording to record and uplod videos</string> コマンドラインで (cd ios && pod install)を打ち込む ちなみに()で囲うことで現在のディレクトリから移動せずにpod installしてくれます。 あるあるなのがiosディレクトリにしたままyarn iosをしててエラーになるパターンです。 割と気づかず何でエラーなのか分からなくなってしまいます。 Android AndroidManifest.xmlに以下を追記してください。 <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 2、コーディング プロジェクトを作成し、今回用のファイルを用意します。 ライブラリをインポート import ImagePicker from 'react-native-image-crop-picker'; import { launchCamera, launchImageLibrary } from 'react-native-image-picker'; image-pickerでは写真ライブラリを開きたいときはlaunchImageLibrary、カメラを起動するときはlaunchCameraを使用します。 launchCameraもインポートしている状態ですが、今回は使わないので必要ないです。 余談ですが、アプリなどのアイコンを設定する際に大体カメラを起動するか写真ライブラリから取得するか選択できると思いますが、その場でカメラを起動して撮った写真をアイコンに設定する人なんているんですかね。 僕は一度もカメラを使ったことないし、友人のアイコンを見る限り全員既存の写真を取得して使ってると思います(加工したものをアイコンに使うから)。 image-crop-pickerを実装 このonCropImageをonPressしたタイミングで呼び出せば写真ライブラリから取得できます。 openPickerの中身には現在は画像サイズなど初期の設定しかしてませんが、たくさん種類があるため自分の好みに合わせて色々付け加えてみてください。 https://github.com/ivpusic/react-native-image-crop-picker 取得時にsetImagePath内に格納してますがこれはuseStateで管理している値なので、今はエラーのままで大丈夫です。 const onCropImage = () => { ImagePicker.openPicker({ width: 300, height: 300, cropping: true, }).then(image => { setImagePath(image.path) }); } image-pickerを実装 こちらもoptionsで色々設定できますが今回は説明を割愛します。 https://github.com/react-native-image-picker/react-native-image-picker 表示するためのuriはresponseのassetsの配列内にあるのでそこにある値をuseStateで管理します const options = { mediaType: 'photo', maxWidth: 1000, maxHeight: 1000, quality: 0.8, saveToPhotos: true, }; const choosePhoto = () => { launchImageLibrary(options, (response) => { if (response.didCancel) { console.log('User cancelled image picker'); } else if (response.error) { console.log('ImagePicker Error: ', response.error); } else { console.log(response.assets[0].uri) setImagePath(response.assets[0].uri) } }); } 全体を実装 今回アイコンをタップした際に出てくる選択欄(アクションシート)はライブラリを使って実装してますが、別の記事で実装方法を取り上げてるのでそこを参照ください。 https://qiita.com/flutter_daisuki/items/949869756b3d10944b7f import React ,{useState}from 'react'; import {StyleSheet, TouchableOpacity, View,Image} from 'react-native'; import {ActionSheet} from 'react-native-cross-actionsheet'; import Icon from 'react-native-vector-icons/FontAwesome'; import ImagePicker from 'react-native-image-crop-picker'; import { launchCamera, launchImageLibrary } from 'react-native-image-picker'; export const ImageCropPicker = () => { const [imagePath ,setImagePath] = useState('') const onCropImage = () => { ImagePicker.openPicker({ width: 300, height: 300, cropping: true, }).then(image => { setImagePath(image.path) }); } const options = { mediaType: 'photo', maxWidth: 1000, maxHeight: 1000, quality: 0.8, saveToPhotos: true, }; const choosePhoto = () => { launchImageLibrary(options, (response) => { if (response.didCancel) { console.log('User cancelled image picker'); } else if (response.error) { console.log('ImagePicker Error: ', response.error); } else { console.log(response.assets[0].uri) setImagePath(response.assets[0].uri) } }); } const onPressAction = () => { return ActionSheet.options({ options: [ {text: 'image-picker', onPress:choosePhoto}, {text: 'image-crop-picker', onPress:onCropImage}, ], cancel: {text: 'キャンセル'}, }); }; return ( <View> <TouchableOpacity onPress={onPressAction}> <View style={styles.iconButton}> {imagePath ? ( <Image style={styles.Photo} source={{uri: imagePath}} /> ) : ( <Icon style={styles.icon} name="user-o" size={70} /> )} </View> </TouchableOpacity> </View> ); }; const styles = StyleSheet.create({ iconButton: { borderWidth: 1, width: 100, height: 100, borderRadius: 100, marginLeft: 'auto', marginRight: 'auto', }, icon: { marginLeft: 'auto', marginRight: 'auto', marginTop: 'auto', marginBottom: 'auto', }, Photo: { width: 100, height: 100, borderRadius: 50, }, }); コードを解説するとアイコン全体をtouchableOpacityでタップできるようにし、タップした際にアクションシートを出すようにしています。 またアイコンはuseStateのimagePathがある場合はそのまま写真を表示するようにして、ない場合はIconを表示するようにしています。 三項演算子を使ってますが、めちゃくちゃ使う場面が多いのでぜひ覚えてください。 そして、アクションシート内で上をタップするとimage-pickerの処理が、下をタップするとimage-crop-pickerの処理が動くようになってます。 3、実際にどんな感じか確認してみる 初期画面 タップ時 image-pickerを選択時 ライブラリが開き、右上の滝をタップすると 表示されました! ただ、今回は綺麗に映りましたが、もし写真の一部分だけをアイコンに使いたいのにこうされると思うようにアイコンが設定できないです。 image-crop-pickerを選択時 ライブラリが開き、さっきと同じ滝の写真をタップすると。。。 写真編集用のviewが出てきました! 滝を拡大させて、アイコンいっぱい滝にしよう できました! ユーザーのことを考えるとこっちの方がいいですね✨ 皆さんもぜひ使ってみてください
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React Native】axiosを使ってAPIの共通処理を実装する

APIの共通処理を実装 大規模な開発になるとフロントからたくさんのAPIを叩くことになります。 そこでAPIを叩く際の共通処理を作成し、毎回詳しく記述しなくて済むようにしたいと思います。 今回はaxiosを使って実装していきますのでインストールしておいてください yarn add axios APIの共通処理を実際に作っていく api.tsを作成 import axios from 'axios' export const api = axios.create({ baseURL:'https://jsonplaceholder.typicode.com/', }) // api.interceptors.request.use( // config.headers.authorization= `Bearer ${ここにアクセストークンを入れる}` // ) api.interceptors.response.use( response => { return response }, function(error) { switch(error.response.status) { case 400: case 401: console.log('認証エラーです'); case 404: console.log('URL先がないです'); default: } } ) 実際の開発では認証用にアクセストークンをつけてリクエストを投げると思いますが、今回はjsonplaceholderを使って手軽に検証しているのでコメントアウトにしています。 初めにbaseURLを設定します。 そして、アクセストークンをつける必要がある場合はコードの用にrequest.use内に設定します response.useではAPIから返ってきたレスポンスの処理を書きます。 成功時にはそのままreturnで返し、エラーがある場合はステータスコードに合わせて処理を書くことができます。 これを毎回API毎に記述するのはコード量も増すし、めんどくさいので共通にまとめておくことでわかりやすいですね! 実際にAPIを呼ぶ側の処理を作っていく 新規ファイルを作成し、 import React, {useEffect, useState} from 'react'; import {StyleSheet, Text, FlatList, SafeAreaView} from 'react-native'; import {api} from '../api/api'; export const ApiResearch = () => { const [postsData, setPostsData] = useState([]); const getPostsData = async () => { const res = await api.get('posts'); setPostsData(res.data); }; useEffect(() => { getPostsData(); },[]); return ( <SafeAreaView> <Text style={styles.title} >ここからpostデータです</Text> <FlatList data={postsData} renderItem={({item}) => <Text>{item.title}</Text>} keyExtractor={item => item.id} /> </SafeAreaView> ); }; const styles = StyleSheet.create({ title: { fontSize:20, fontWeight:'bold', paddingBottom:10 } }); まず、先ほど作ったAPIの共通処理をimportし、初期表示時にgetPostDataでAPIを呼ぶように記述しています。 getPostsData内ではimportしたapiの後にgetメソッドを記述し、先程baseURLで設定したURLの続きを記述しています。 これでAPIを呼ぶことができるようになります。 ちなみに表示はFlatListを使って返ってきたレスポンス(配列)をマッピングし、全部表示しています 別のAPIも呼んでみる import React, {useEffect, useState} from 'react'; import {StyleSheet, Text, FlatList, SafeAreaView} from 'react-native'; import {api} from '../api/api'; export const ApiResearch = () => { const [postsData, setPostsData] = useState([]); const [usersData, setUsersData] = useState([]); const getPostsData = async () => { const res = await api.get('posts'); setPostsData(res.data); }; const getUsersData = async () => { const res = await api.get('users'); setUsersData(res.data); }; useEffect(() => { getPostsData(); getUsersData(); },[]); return ( <SafeAreaView> <Text style={styles.title} >ここからpostデータです</Text> <FlatList data={postsData} renderItem={({item}) => <Text>{item.title}</Text>} keyExtractor={item => item.id.toString()} /> <Text style={styles.title}>ここからuserデータです</Text> <FlatList data={usersData} renderItem={({item}) => <Text>{item.name}</Text>} keyExtractor={item => item.id.toString()} /> </SafeAreaView> ); }; const styles = StyleSheet.create({ title: { fontSize:20, fontWeight:'bold', marginBottom:10 } }); 次はjsonplaceholderからuserデータを呼んでいますが、先ほどと同じような記述で簡単に呼び出すことができます 今回はjsonplaceholderで検証したので、わかりにくかったかもしれないですが、実際の大規模の開発だととても恩恵を受けることになるので覚えておいて損はないです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ReactNative】アプリのプロフィール画像を変えるときに下から出てくる選択欄(アクションシートというらしい)を作ってみる

画像のようなタップしたときに下から出てくる選択欄(アクションシート)を実装していきます。 この機能はよくアプリのアイコンや写真を設定する時に使われていると思います。 実際にはiPhoneのappleIDのアイコンやLINEのトップ画を設定するときに使われています プロジェクト作成、必要なライブラリをインストール まずはReact-Nativeプロジェクトを作成します。 ちなみにExpoではなく、素のReactNativeで作っていきます。 作成方法はドキュメントなどを参考に進めてください。 次に必要なライブラリをインストールします yarnの場合yarn add react-native-cross-actionsheet npmの場合npm install react-native-cross-actionsheet iOSだけの実装ならReactNativeの標準に入ってるのでインストールする必要はないです 実はReactNativeの公式にActionSheetIOSという同じようなUIを作れるものがありますが、それだとiOSにしか実装できません。 iOSだけならそれでもいいですが、Androidも作る予定の人はライブラリをインストールしてください。 作り方自体はほとんど一緒です。 実装 今回はアクションシート用のコンポーネントを作成して、それをApp.jsから呼び出しているかたちです import React from 'react'; import { StyleSheet, View, } from 'react-native'; import { ActionSheetPage } from './src/components/ActionSheet'; const App = () => { return ( <View style={styles.screen}> <ActionSheetPage/> </View> ); }; const styles = StyleSheet.create({ screen: { flex:1, justifyContent:'center', alignItems:'center' } }); export default App; 次にアクションシートを実装するコンポーネントを作成していきます。 import React from 'react'; import {TouchableOpacity, View} from 'react-native'; import Icon from 'react-native-vector-icons/FontAwesome'; export const ActionSheetPage = () => { return ( <View> <TouchableOpacity> <View> <Icon name="user-o" size={70} /> </View> </TouchableOpacity> </View> ); }; ベースを作り、TouchableOpacityでタップした時の挙動にアクションシートを使っていきます import React from 'react'; import {StyleSheet, TouchableOpacity, View} from 'react-native'; import {ActionSheet} from 'react-native-cross-actionsheet'; import Icon from 'react-native-vector-icons/FontAwesome'; export const ActionSheetPage = () => { const onPressAction = () => { return ActionSheet.options({ options: [ {text: '写真を撮る', onPress: () => console.log('create')}, {text: '写真を選択', onPress: () => console.log('update')}, ], cancel: {text: 'キャンセル'}, }); }; return ( <View> <TouchableOpacity onPress={onPressAction}> <View style={styles.iconButton}> <Icon style={styles.icon} name="user-o" size={70} /> </View> </TouchableOpacity> </View> ); }; const styles = StyleSheet.create({ iconButton: { borderWidth: 1, width: 100, height: 100, borderRadius: 100, marginLeft: 'auto', marginRight: 'auto', }, icon: { marginLeft: 'auto', marginRight: 'auto', marginTop: 'auto', marginBottom: 'auto', }, }); options内のtextに入れたい文字を入れ、onPressにタップした時の挙動を実装すれば完成です ちなみにAndoroidだとこんな感じ 意外と簡単に実装できます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

型キャスト(as, as!, as?)について

Swiftの勉強をしていて、asが出て来ることが多いので、自分なりに調べてまとめてみました。 参考記事 ・https://fukatsu.tech/swift-cast ・https://qiita.com/entry909/items/3c4c9a20bce0c903dc39 ・http://blog.andgenie.jp/articles/803 キャストについて キャストとは、asという演算子を用いて変数や定数を具体的な型にはめ込むことです。 asについて asは、演算子の一種で2種類の変換を実行することができます。 保証変換 強制変換 保証変換 保証変換とは、別の型に変換するときに、コンパイラ可能な場合キャストの成功が保証されるような変換です。 例えば、アップキャストというのがあって、クラスの継承やプロトコルの準拠などの階層関係がある型同士においてキャストを行うものです。 let str = "アイウエオ" let any = str as Any 強制変換 強制変換とは、変換するときにコンパイラで安全性が保証できないので実行時にエラーを引き起こす可能性があるキャストのことです。この強制変換では、ダウンキャストというものがあります。 ダウンキャストとは ダウンキャストとは、as!、as?のに種類があって、as!は強制的にコンパイラの安全性を無視してキャストを行います。 let any: Any = "アイウエオ" let str = any as! String //String型"アイウエオ" let num = any as! Int //Int型にキャスト失敗(実行時エラー) as?は、キャスト自体が成功するかわからない時に使います。 成功時はOptional型になり、失敗時はnil型になります。 let any: Any = "アイウエオ" let str = any as? String //Optional("アイウエオ") let num = any as? Int //nil
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む