20210908のiOSに関する記事は10件です。

iOSのLINEの内臓ブラウザが、POSTフォームのtarget=_blankで挙動が狂う件

概要 iOSのLINEブラウザの挙動がおかしくてはまりました。 現象 環境:iOSのLINEとYahooの内臓ブラウザ(ほかにもあるかもしれない。) 条件:POSTメソッドのformタグで、target="_blank"が指定されている 結果:formのaction先には遷移するが、formのパラメータはすべて抜け落ちる 再現 1. コード html01.html <html> <head> <meta charset="UTF-8" /> <style type="text/css"> div { border: 1px solid black; margin-top:10px; } </style> </head> <body> <div> targetなしPOSTフォーム <form action="./php01.php" method="POST"> <input name="name" type="text" value="kumanobori" /> <input name="type" type="text" value="kuma" /> <input type="submit" /> </form> </div> <div> targetありPOSTフォーム <form action="./php01.php" method="POST" target="_blank"> <input name="name" type="text" value="kumanobori" /> <input name="type" type="text" value="kuma" /> <input type="submit" /> </form> </div> </body> </html> php01.php <?php echo 'REQUEST_URI: ' . $_SERVER['REQUEST_URI'] . '<br />'; echo 'POST:' . mb_ereg_replace("\r|\n", '', print_r($_POST, true)) . '<br />'; 2. html表示 3. 正常な結果(iOSのLine内臓ブラウザのtargetありの場合以外) 4. 異常な結果(iOSのLine内臓ブラウザのtargetありの場合) 回避策 User-Agentで判定して、 target="_blank" の出力有無を制御しました。 その他 試した環境(以下は全部セーフ) iOS slack内臓 iOS chrome iOS Safari android Yahoo内臓 android LINE内臓 android chrome 上記コード以外で試した条件(以下は全部セーフ) GETメソッドのformの target="_blank" aタグの target="_blank" ポエム LINEブラウザの挙動がおかしいってことで調査したのですが、こんな使い古したオプションで挙動が狂うとは思わず、思い切りはまりました。。。 2021.09.10 追記 スマホのLINE内臓ブラウザだと「新しいウィンドウ」という概念がないわけで、そこに事情があるんだろうなという気はしなくもないです。 でもandroid版はちゃんとしてるしー。(新しいウィンドウは開かないけど、ちゃんと遷移する) で、Yahooアプリに至っては内臓ブラウザがマルチタブ対応してるからそこに事情を斟酌する余地すらないしー。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ProgressViewをCustom ViewModifierで使いやすくする

はじめに SwiftUIには、ローディング中とかにぐるぐるするインジケーターがProgressViewとして用意されています。 大抵こういうViewは共通化されると思うので、使いやすくするためにProgressViewの Custom ViewModifierを作ってみました。 普通にViewにしてもいいと思ったのですが、 Viewにすると多分こうなってしまうと思います↓ 使う側では、毎回ZStackで囲わないといけないので、面倒な気がします。 ZStack { VStack { Text("Hello World") } if showProgressView { CustomProgressView() } } そうではなくこうやって使えた方が、ZStackとか不要だし便利だろうと思ったので、ViewModifierで実装してます。↓ VStack { Text("Hello World") .customProgressView(showProgressView: $showProgressView) } 成果物 よくあるローディング中画面が表示されています。 動画で見たい場合は、以下のGithubリポジトリで公開しているので、そのREADMEを確認ください。 ColorをProgressViewの前の階層に入れているので、この画面が表示されているときは後ろは操作不可にしてます。 ProgressViewだけでは、後ろは操作不可にしてくれませんので、自分で実装必要でした。 実装を見ればわかりますが、 「読み込み中」のテキストや色、背景色は自由にカスタマイズできます。 実装 まずCustom ViewModifierの実装です。 import SwiftUI struct CustomProgressView: ViewModifier { @Binding var showProgressView: Bool func body(content: Content) -> some View { // contentはこのカスタムViewModifierを使用する対象Viewのプロキシ ZStack { content if showProgressView { // ProgressViewの背景をタップ不可にするために、Colorを使用 Color.gray.opacity(0.2) VStack(spacing: 6) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .gray)) .scaledToFit() .frame(width: 22, height: 22) Text("読み込み中") .foregroundColor(Color.gray) .font(.caption2) } } } } } 最初contentを書くのを忘れてしまい、ProgressViewは表示されるが背景にあるはずのViewが全く表示されないという現象で悩んでました。 contentは 修飾する対象のViewのプロキシ だそうなので、これがないと修飾する対象のViewが表示されないのは当然でした。。 なので、当然if文の外にcontentが存在してる必要があります。 そうでないと、showProgressViewがfalseの時には修飾する対象のViewも一緒に非表示になってしまいます。 ちなみにTextのViewを使わなくても、 ProgressView("読み込み")というようにテキストを設定できるのですが、 フォントサイズや色など細かくカスタマイズしたい場合は、TextのViewを自分で作らないといけないみたいです。 ProgressView(Text("読み込み").font(.caption2))というようには書けなかったです。 では次に、ViewのExtensionを実装します。 extension View { func customProgressView(showProgressView: Binding<Bool>) -> some View { self.modifier(CustomProgressView(showProgressView: showProgressView)) } } これで、初めに書いたように .customProgressView(showProgressView: $showProgressView) とModifierをつければ例の画面が表示できるようになります。 これがない場合は .modifier(CustomProgressView(showProgressView: $showProgressView)) と書くことになると思います。(実際にこれで動作確認はしていないのですが動くはず。。) これはこれでいいかもですが、私はラップした方が他の標準Modifierと同じように使えてシンプルかなと思っています。 今更な説明ですが、親View側でshowProgressViewの真偽を切り替えることになると思うので、@Bindingを使っています。 では早速使ってみる。 struct ContentView: View { @ObservedObject private var viewModel = ContentViewModel() var body: some View { VStack(spacing: 50) { Text("テスト1") Text("テスト2") } .background(Color.yellow) .frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height) .customProgressView(showProgressView: $viewModel.showProgressView) .onAppear { viewModel.onAppear() } } } viewModelクラスのプロパティとして、showProgressViewを@Publishedで持っています。 class ContentViewModel: ObservableObject { @Published var showProgressView = false func onAppear() { showProgressView = true // 3秒後待ってインジケータを削除(実際はAPI通信したり、画像取得したり) DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { self.showProgressView = false } } } 今回は3秒待つだけにしていますが、実際はAPIと通信したりとかとにかく何か時間がかかる処理が実装されることになると思います。 その処理完了の前後でshowProgressViewの真偽を切り替え、その値を監視することによって、 今回のローディング画面の切り替えを行なっています。 参考にした記事 SwiftUIのViewModifierを使ってViewをカスタマイズする 【SwiftUI】カスタムModifierの作成 How to create custom View modifiers for better code reusability in SwiftUI→かなり参考にさせていただきました。ProgressViewではなくもっとUI的に凝ったローディング画面を作りたい場合にはこの記事がおすすめです。 おわりに Custom ViewModifierを勉強する良い機会になりました。 まだまだSwiftUI初心者ですが、ちょっとずつ進歩してることを願ってます。 誤り、もっと良いやり方あるなどありましたら、是非コメントで教えてください 誰かの役に立てば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

よくあるインジケーターを、ProgressViewとカスタム ViewModifierで使いやすくする

はじめに SwiftUIには、ローディング中とかにぐるぐるするインジケーターがProgressViewとして用意されています。 大抵こういうViewは共通化されると思うので、使いやすくするためにProgressViewの カスタム ViewModifierを作ってみました。 普通にViewにしてもいいと思ったのですが、 Viewにすると多分こうなってしまうと思います↓ 使う側では、毎回ZStackで囲わないといけないので、面倒な気がします。 ZStack { Text("Hello World") if showProgressView { CustomProgressView() } } そうではなくこうやって使えた方が、ZStackとか不要だし便利だろうと思ったので、ViewModifierで実装してます。↓ Text("Hello World") .customProgressView(showProgressView: $showProgressView) 成果物 よくあるローディング中画面が表示されています。 動画で見たい場合は、以下のGithubリポジトリで公開しているので、そのREADMEを確認ください。 ColorをProgressViewの前の階層に入れているので、この画面が表示されているときは後ろは操作不可にしてます。 ProgressViewだけでは、後ろは操作不可にしてくれませんので、自分で実装必要でした。 実装を見ればわかりますが、 「読み込み中」のテキストや色、背景色は自由にカスタマイズできます。 実装 まずカスタム ViewModifierの実装です。 import SwiftUI struct CustomProgressView: ViewModifier { @Binding var showProgressView: Bool func body(content: Content) -> some View { // contentはこのカスタムViewModifierを使用する対象Viewのプロキシ ZStack { content if showProgressView { // ProgressViewの背景をタップ不可にするために、Colorを使用 Color.gray.opacity(0.2) VStack(spacing: 6) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .gray)) .scaledToFit() .frame(width: 22, height: 22) Text("読み込み中") .foregroundColor(Color.gray) .font(.caption2) } } } } } 最初contentを書くのを忘れてしまい、ProgressViewは表示されるが背景にあるはずのViewが全く表示されないという現象で悩んでました。 contentは 修飾する対象のViewのプロキシ だそうなので、これがないと修飾する対象のViewが表示されないのは当然でした。。 なので、当然if文の外にcontentが存在してる必要があります。 そうでないと、showProgressViewがfalseの時には修飾する対象のViewも一緒に非表示になってしまいます。 ちなみにTextのViewを使わなくても、 ProgressView("読み込み")というようにテキストを設定できるのですが、 フォントサイズや色など細かくカスタマイズしたい場合は、TextのViewを自分で作らないといけないみたいです。 ProgressView(Text("読み込み").font(.caption2))というようには書けなかったです。 では次に、ViewのExtensionを実装します。 extension View { func customProgressView(showProgressView: Binding<Bool>) -> some View { self.modifier(CustomProgressView(showProgressView: showProgressView)) } } これで、初めに書いたように .customProgressView(showProgressView: $showProgressView) とModifierをつければ例の画面が表示できるようになります。 これがない場合は .modifier(CustomProgressView(showProgressView: $showProgressView)) と書くことになると思います。(実際にこれで動作確認はしていないのですが動くはず。。) これはこれでいいかもですが、私はラップした方が他の標準Modifierと同じように使えてシンプルかなと思っています。 今更な説明ですが、親View側でshowProgressViewの真偽を切り替えることになると思うので、@Bindingを使っています。 では早速使ってみる。 struct ContentView: View { @ObservedObject private var viewModel = ContentViewModel() var body: some View { VStack(spacing: 50) { Text("テスト1") Text("テスト2") } .background(Color.yellow) .customProgressView(showProgressView: $viewModel.showProgressView) .onAppear { viewModel.onAppear() } } } viewModelクラスのプロパティとして、showProgressViewを@Publishedで持っています。 class ContentViewModel: ObservableObject { @Published var showProgressView = false func onAppear() { showProgressView = true // 3秒後待ってインジケータを削除(実際はAPI通信したり、画像取得したり) DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { self.showProgressView = false } } } 今回は3秒待つだけにしていますが、実際はAPIと通信したりとかとにかく何か時間がかかる処理が実装されることになると思います。 その処理完了の前後でshowProgressViewの真偽を切り替え、その値を監視することによって、 今回のローディング画面の切り替えを行なっています。 参考にした記事 SwiftUIのViewModifierを使ってViewをカスタマイズする 【SwiftUI】カスタムModifierの作成 How to create custom View modifiers for better code reusability in SwiftUI→かなり参考にさせていただきました。ProgressViewではなくもっとUI的に凝ったローディング画面を作りたい場合にはこの記事がおすすめです。 おわりに Custom ViewModifierを勉強する良い機会になりました。 まだまだSwiftUI初心者ですが、ちょっとずつ進歩してることを願ってます。 誤り、もっと良いやり方あるなどありましたら、是非コメントで教えてください 誰かの役に立てば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

よくあるインジケーター表示切り替えを、ProgressViewとカスタム ViewModifierで使いやすくする

はじめに SwiftUIには、ローディング中とかにぐるぐるするインジケーターがProgressViewとして用意されています。 大抵こういうViewは共通化されると思うので、使いやすくするためにProgressViewの カスタム ViewModifierを作ってみました。 普通にViewにしてもいいと思ったのですが、 Viewにすると多分こうなってしまうと思います↓ 使う側では、毎回ZStackで囲わないといけないので、面倒な気がします。 ZStack { Text("Hello World") if showProgressView { CustomProgressView() } } そうではなくこうやって使えた方が、ZStackとか不要だし便利だろうと思ったので、ViewModifierで実装してます。↓ Text("Hello World") .customProgressView(showProgressView: $showProgressView) 成果物 よくあるローディング中画面が表示されています。 動画で見たい場合は、以下のGithubリポジトリで公開しているので、そのREADMEを確認ください。 ColorをProgressViewの前の階層に入れているので、この画面が表示されているときは後ろは操作不可にしてます。 ProgressViewだけでは、後ろは操作不可にしてくれませんので、自分で実装必要でした。 実装を見ればわかりますが、 「読み込み中」のテキストや色、背景色は自由にカスタマイズできます。 実装 まずカスタム ViewModifierの実装です。 import SwiftUI struct CustomProgressView: ViewModifier { @Binding var showProgressView: Bool func body(content: Content) -> some View { // contentはこのカスタムViewModifierを使用する対象Viewのプロキシ ZStack { content if showProgressView { // ProgressViewの背景をタップ不可にするために、Colorを使用 Color.gray.opacity(0.2) VStack(spacing: 6) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .gray)) .scaledToFit() .frame(width: 22, height: 22) Text("読み込み中") .foregroundColor(Color.gray) .font(.caption2) } } } } } 最初contentを書くのを忘れてしまい、ProgressViewは表示されるが背景にあるはずのViewが全く表示されないという現象で悩んでました。 contentは 修飾する対象のViewのプロキシ だそうなので、これがないと修飾する対象のViewが表示されないのは当然でした。。 なので、当然if文の外にcontentが存在してる必要があります。 そうでないと、showProgressViewがfalseの時には修飾する対象のViewも一緒に非表示になってしまいます。 ちなみにTextのViewを使わなくても、 ProgressView("読み込み")というようにテキストを設定できるのですが、 フォントサイズや色など細かくカスタマイズしたい場合は、TextのViewを自分で作らないといけないみたいです。 ProgressView(Text("読み込み").font(.caption2))というようには書けなかったです。 では次に、ViewのExtensionを実装します。 extension View { func customProgressView(showProgressView: Binding<Bool>) -> some View { self.modifier(CustomProgressView(showProgressView: showProgressView)) } } これで、初めに書いたように .customProgressView(showProgressView: $showProgressView) とModifierをつければ例の画面が表示できるようになります。 Extensionでラップしない場合は .modifier(CustomProgressView(showProgressView: $showProgressView)) と書くことになると思います。(実際にこれで動作確認はしていないのですが動くはず。。) これはこれでいいかもですが、私はラップした方が他の標準Modifierと同じように使えてシンプルかなと思っています。 今更な説明ですが、親View側でshowProgressViewの真偽を切り替えることになると思うので、@Bindingを使っています。 では早速使ってみる。 struct ContentView: View { @ObservedObject private var viewModel = ContentViewModel() var body: some View { VStack(spacing: 50) { Text("テスト1") Text("テスト2") } .background(Color.yellow) .customProgressView(showProgressView: $viewModel.showProgressView) .onAppear { viewModel.onAppear() } } } viewModelクラスのプロパティとして、showProgressViewを@Publishedで持っています。 class ContentViewModel: ObservableObject { @Published var showProgressView = false func onAppear() { showProgressView = true // 3秒後待ってインジケータを削除(実際はAPI通信したり、画像取得したり) DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { self.showProgressView = false } } } 今回は3秒待つだけにしていますが、実際はAPIと通信したりとかとにかく何か時間がかかる処理が実装されることになると思います。 その処理完了の前後でshowProgressViewの真偽を切り替え、その値を監視することによって、 今回のローディング画面の切り替えを行なっています。 参考にした記事 SwiftUIのViewModifierを使ってViewをカスタマイズする 【SwiftUI】カスタムModifierの作成 How to create custom View modifiers for better code reusability in SwiftUI→かなり参考にさせていただきました。ProgressViewではなくもっとUI的に凝ったローディング画面を作りたい場合にはこの記事がおすすめです。 おわりに Custom ViewModifierを勉強する良い機会になりました。 まだまだSwiftUI初心者ですが、ちょっとずつ進歩してることを願ってます。 誤り、もっと良いやり方あるなどありましたら、是非コメントで教えてください 誰かの役に立てば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】よくあるインジケーター表示切り替えを、ProgressViewとカスタム ViewModifierで使いやすくする

はじめに SwiftUIには、ローディング中とかにぐるぐるするインジケーターがProgressViewとして用意されています。 大抵こういうViewは共通化されると思うので、使いやすくするためにProgressViewの カスタム ViewModifierを作ってみました。 普通にViewにしてもいいと思ったのですが、 Viewにすると多分こうなってしまうと思います↓ 使う側では、毎回ZStackで囲わないといけないので、面倒な気がします。 ZStack { Text("Hello World") if showProgressView { CustomProgressView() } } そうではなくこうやって使えた方が、ZStackとか不要だし便利だろうと思ったので、ViewModifierで実装してます。↓ Text("Hello World") .customProgressView(showProgressView: $showProgressView) 成果物 よくあるローディング中画面が表示されています。 動画で見たい場合は、以下のGithubリポジトリで公開しているので、そのREADMEを確認ください。 ColorをProgressViewの前の階層に入れているので、この画面が表示されているときは後ろは操作不可にしてます。 ProgressViewだけでは、後ろは操作不可にしてくれませんので、自分で実装必要でした。 実装を見ればわかりますが、 「読み込み中」のテキストや色、背景色は自由にカスタマイズできます。 実装 まずカスタム ViewModifierの実装です。 import SwiftUI struct CustomProgressView: ViewModifier { @Binding var showProgressView: Bool func body(content: Content) -> some View { // contentはこのカスタムViewModifierを使用する対象Viewのプロキシ ZStack { content if showProgressView { // ProgressViewの背景をタップ不可にするために、Colorを使用 Color.gray.opacity(0.2) VStack(spacing: 6) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .gray)) .scaledToFit() .frame(width: 22, height: 22) Text("読み込み中") .foregroundColor(Color.gray) .font(.caption2) } } } } } 最初contentを書くのを忘れてしまい、ProgressViewは表示されるが背景にあるはずのViewが全く表示されないという現象で悩んでました。 contentは 修飾する対象のViewのプロキシ だそうなので、これがないと修飾する対象のViewが表示されないのは当然でした。。 なので、当然if文の外にcontentが存在してる必要があります。 そうでないと、showProgressViewがfalseの時には修飾する対象のViewも一緒に非表示になってしまいます。 ちなみにTextのViewを使わなくても、 ProgressView("読み込み")というようにテキストを設定できるのですが、 フォントサイズや色など細かくカスタマイズしたい場合は、TextのViewを自分で作らないといけないみたいです。 ProgressView(Text("読み込み").font(.caption2))というようには書けなかったです。 では次に、ViewのExtensionを実装します。 extension View { func customProgressView(showProgressView: Binding<Bool>) -> some View { self.modifier(CustomProgressView(showProgressView: showProgressView)) } } これで、初めに書いたように .customProgressView(showProgressView: $showProgressView) とModifierをつければ例の画面が表示できるようになります。 Extensionでラップしない場合は .modifier(CustomProgressView(showProgressView: $showProgressView)) と書くことになると思います。(実際にこれで動作確認はしていないのですが動くはず。。) これはこれでいいかもですが、私はラップした方が他の標準Modifierと同じように使えてシンプルかなと思っています。 今更な説明ですが、親View側でshowProgressViewの真偽を切り替えることになると思うので、@Bindingを使っています。 では早速使ってみる。 struct ContentView: View { @ObservedObject private var viewModel = ContentViewModel() var body: some View { VStack(spacing: 50) { Text("テスト1") Text("テスト2") } .background(Color.yellow) .customProgressView(showProgressView: $viewModel.showProgressView) .onAppear { viewModel.onAppear() } } } viewModelクラスのプロパティとして、showProgressViewを@Publishedで持っています。 class ContentViewModel: ObservableObject { @Published var showProgressView = false func onAppear() { showProgressView = true // 3秒後待ってインジケータを削除(実際はAPI通信したり、画像取得したり) DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { self.showProgressView = false } } } 今回は3秒待つだけにしていますが、実際はAPIと通信したりとかとにかく何か時間がかかる処理が実装されることになると思います。 その処理完了の前後でshowProgressViewの真偽を切り替え、その値を監視することによって、 今回のローディング画面の切り替えを行なっています。 参考にした記事 SwiftUIのViewModifierを使ってViewをカスタマイズする 【SwiftUI】カスタムModifierの作成 How to create custom View modifiers for better code reusability in SwiftUI→かなり参考にさせていただきました。ProgressViewではなくもっとUI的に凝ったローディング画面を作りたい場合にはこの記事がおすすめです。 おわりに Custom ViewModifierを勉強する良い機会になりました。 まだまだSwiftUI初心者ですが、ちょっとずつ進歩してることを願ってます。 誤り、もっと良いやり方あるなどありましたら、是非コメントで教えてください 誰かの役に立てば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React Native】AlertやらDialogやらmodalやら似たようなやつのそれぞれ特徴をまとめました。

似たような使い方をするAlertとDialogとModalの違い ログインに失敗した時のエラーメッセージやユーザーに確認をとる時に使われるUIの作り方は何種類かあります。 その中で今回はReactNativeの標準に入っているAlert、ModalとライブラリのDialogの三つのそれぞれの違いをまとめました。 基本的にこの三つはほとんど同じUIで挙動や実装方法も同じです。ただ、Dialogじゃないとできないことなどもありましたので資料にしました。 ライブラリをインストール dialog yarn add react-native-dialog Github:https://github.com/mmazzarolo/react-native-dialog 実装 プロジェクトを作成し、各ライブラリをインポートします。 import React from 'react'; import {Alert, Button, View,Modal} from 'react-native'; import Dialog from "react-native-dialog"; 1、Alert 初めにAlertを作っていきます import React from 'react'; import {Alert, Button, View,Modal} from 'react-native'; import Dialog from "react-native-dialog"; export const AlertDialog = () => { const onPressAlert = () => { Alert.alert( 'アラートを出しました', 'テキストテキストテキストテキスト', [ { text: 'Cancel', onPress: () => console.log('アラートのcancelをタップした時の挙動を書く'), style: 'cancel', }, {text: 'OK', onPress: () => console.log('アラートのOKをタップした時の挙動を書く')}, ]); }; return ( <View> <Button title="Alert" onPress={onPressAlert} /> </View> ); }; Buttonをタップした時にAlertを表示させます。 配列の一つ目にstyle:'cancel'と書かれていますが、これは表示する文字の色、太さを変更することができます。 cancelだと太文字に、destructiveだと赤文字になります。 こんな感じで表示されます。  次に配列内のボタンを一つ増やしてみます。 Alert.alert('アラートを出しました', 'テキストテキストテキストテキスト', [ { text: 'setting', onPress: () => console.log('アラートのsettingをタップした時の挙動を書く'), style: 'destructive', }, { text: 'Cancel', onPress: () => console.log('アラートのcancelをタップした時の挙動を書く'), style: 'cancel', }, { text: 'OK', onPress: () => console.log('アラートのOKをタップした時の挙動を書く'), }, ]); すると。。。。 配列内が三つ以上の時は縦並びになります。 ここで一つ気になる点があります。 配列は一番目に「setting」、二番目に「Cancel」、三番目に「OK」としているのに実際はCancelが一番下になってます。 これは「Cancel」内のstyleに’cancel’としていると思いますが、cancelというstyleを当てると、例え一番目に入れていても表示する時は自動的に一番下になります。 便利っちゃー便利かな。 ちなみに配列を一つだけにするとこんな感じです Alertの特徴 1、アラートの上に出すタイトル(テキスト)のスタイリングができない →もし色やフォントサイズを変更したくても変えれないです。 2、タイトルに画像やアイコンを入れられない →基本テキストした入れないと思いますが、画像を入れたくても入れれないです。 3、手軽に実装できるので特に変わった実装が必要じゃない時はこれで十分かな →できることは少ないですが、Alertの内容だけで十分なことがほとんどだと思うので、基本的にはこれを使えばいい 補足ですが、実装するときにアラートの第二引数(テキスト)を入れたくなくて消してしまうと Alert.alert('アラート',[ { text: 'setting', onPress: () => console.log('アラートのsettingをタップした時の挙動を書く'), style: 'destructive', }, { text: 'Cancel', onPress: () => console.log('アラートのcancelをタップした時の挙動を書く'), style: 'cancel', type:'login-password', }, { text: 'OK', onPress: () => console.log('アラートのOKをタップした時の挙動を書く'), }, ], ); こんな感じに思ったUIにならないので、二行目にテキストが必要ない場合でも Alert.alert('アラート','',[ { text: 'setting', onPress: () => console.log('アラートのsettingをタップした時の挙動を書く'), style: 'destructive', }, { text: 'Cancel', onPress: () => console.log('アラートのcancelをタップした時の挙動を書く'), style: 'cancel', type:'login-password', }, { text: 'OK', onPress: () => console.log('アラートのOKをタップした時の挙動を書く'), }, ], ); こんな感じで空にしといてください! Dialog 実装していきます import React,{useState} from 'react'; import {Alert, Button, View,Modal} from 'react-native'; import Dialog from 'react-native-dialog'; export const AlertDialog = () => { const [visible,setVisible] = useState(false) return ( <View> <Button title="Alert" onPress={()=>setVisible(true)} /> <View> <Dialog.Container visible={visible}> <Dialog.Title>ダイアログを出しました</Dialog.Title> <Dialog.Description> あああああああああああああああああああああああああああああああああああ </Dialog.Description> <Dialog.Button label="Cancel" color='red' onPress={()=>setVisible(false)} /> <Dialog.Button label="OK" onPress={()=>setVisible(false)} /> </Dialog.Container> </View> </View> ); }; Alertではタップした時にAlertを出すようにしましたが、Dialogではvisibleがtrueの時に表示、falseで非表示にします。 ですのでuseStateを使ってtrueかfalseかを制御します。 Buttonをタップした時にtrueにし、ダイアログ内のボタンをタップすることでfalseとなり、非表示になります こんな感じで表示されます。Alertとほぼ同じですね。 では色々Dialogの特徴を紹介していこうと思います。 <View> <Dialog.Container visible={visible}> <Dialog.Title style={{fontSize:30,marginBottom:40}}>ダイアログを出しました</Dialog.Title> <Dialog.Description> あああああああああああああああああああああああああああああああああああ </Dialog.Description> <Dialog.Button label="Cancel" color='red' onPress={()=>setVisible(false)} /> <Dialog.Button label="OK" onPress={()=>setVisible(false)} /> <Dialog.Button label="Setting" bold={true} onPress={()=>setVisible(false)} /> </Dialog.Container> </View> まずスタイリングですがtitleにもstyleを当てることができます。またボタンの方はカラーや太さを調整することができます。 こんな感じに表示されます。 Alertの時は三つボタンがあると縦並びになりましたが、Dialogだと横並びに続いていきます。 さらにこんな事もできます <View> <Dialog.Container visible={visible}> <Dialog.Title style={{fontSize:30,marginBottom:40}}> <Icon name="user-o" size={70} /> </Dialog.Title> <Dialog.Input placeholder='名前' /> <Dialog.Button label="Cancel" color='red' onPress={()=>setVisible(false)} /> <Dialog.Button label="OK" onPress={()=>setVisible(false)} /> <Dialog.Button label="Setting" bold={true} onPress={()=>setVisible(false)} /> </Dialog.Container> </View> Dialog.title内をテキストではなく、アイコンを表示させています。 Alertではできませんでしたが、画像やアイコンも入れることができるんです。 そのほかにもDialog.inputでテキスト入力欄をダイアログにつけることができます! Dialogの特徴 1、Alertよりできることが多い 2、スタイルを当てることができる 3、画像やアイコンを入れることができる Modal 最後のModalです、実装していきます import React, {useState} from 'react'; import {Alert, Button, View, Modal, StyleSheet, Text} from 'react-native'; import Dialog from 'react-native-dialog'; import Icon from 'react-native-vector-icons/FontAwesome'; export const AlertDialog = () => { const [modalVisible, setModalVisible] = useState(false); return ( <View> <Button title="タップ" onPress={() => setModalVisible(true)} /> <View> <Modal animationType="slide" transparent={true} visible={modalVisible} onRequestClose={() => { Alert.alert('Modal has been closed.'); setModalVisible(!modalVisible); }}> <View style={styles.centeredView}> <View style={styles.modalView}> <Text style={styles.modalText}>Hello World!</Text> <Button title="閉じる" onPress={() => setModalVisible(false)} /> </View> </View> </Modal> </View> </View> ); }; const styles = StyleSheet.create({ centeredView: { flex: 1, justifyContent: 'center', alignItems: 'center', marginTop: 22, }, modalView: { margin: 20, backgroundColor: 'white', borderRadius: 20, width:300, padding: 35, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.25, shadowRadius: 4, elevation: 5, }, button: { borderRadius: 20, padding: 10, elevation: 2, }, buttonOpen: { backgroundColor: '#F194FF', }, buttonClose: { backgroundColor: '#2196F3', }, textStyle: { color: 'white', fontWeight: 'bold', textAlign: 'center', }, modalText: { marginBottom: 15, textAlign: 'center', }, }); 特徴はAlertやDialogと違い、ほぼほぼスタイリングで自分で実装しているところです。 よくも悪くも自分の理想のものを作ることができます。 UIはこんな感じになります。 表示方法はDialogと同様にtrueの時は表示、falseで非表示としています。 ボタンをタップした時、モーダルは下から出てきます。 これはModalタグ内のanimatedTypeで設定しています。 現在はslideにしていますが、noneにすることでAlertやDialogと同じような感じで表示されます。 二つ目のtransparentはtrueかfalseで設定します。 trueの場合:モーダルを出した時に背景をもともと設定している色のままにする falseの場合:モーダルを出すときは背景色を決めていても画面全体を真っ白にする modal内はViewタグを使って一からスタイリングしているため、自分の思うようなものを作ることができますが、AlertやDialogに比べてめんどくさいです。 Modalの特徴 1、UIは自分で一から構築 2、自由度は高いがAlertやDialogに比べて実装がめんどくさい。 結論 以上三つの似たUIを作ってみましたが、僕的にはDialogが一番使いやすいと思いました。 ただ、OKとキャンセルを出すだけだったらAlertで十分です。 Modalは使うことはないかなと思いました。Dialogを使えばやりたいことはできると思いますので。 ぜひ参考にしてください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS13 / iOS14 /iOS15 で、AppDelegateのライフサイクルは違うよ 14がおかしいんだけど

以前書いた記事 で、OSによってコロコロ変わるライフサイクルに苦しめられてることをぼやかずに分析だけしたのですが、iOS15でもまたまたライフサイクルが変わっています。いい加減にしてほしい! 結論から言うと、iOS14だけおかしかったのです。iOS13もか。 iOS15では、iOS12以前のライフサイクルに戻っているようです。 iOS15 -[AppDelegate application:didFinishLaunchingWithOptions:] -[ViewController viewDidLoad] -[ViewController viewWillAppear:] -[ViewController viewDidAppear:] -[AppDelegate applicationDidBecomeActive:] -[ViewController applicationDidBecomeActiveNotification:] iOS14(iOS14.5) -[AppDelegate application:didFinishLaunchingWithOptions:] -[AppDelegate applicationDidBecomeActive:] -[ViewController viewDidLoad] -[ViewController viewWillAppear:] -[ViewController viewDidAppear:] viewDidLoadとかで applicationDidBecomeActiveNotification へのObserverを貼ったところで、既にapplicationDidBecomeActiveは呼ばれているので、初回はapplicationDidBecomeActiveNotificationを受け取れない! iOS13 -[AppDelegate application:didFinishLaunchingWithOptions:] -[ViewController viewDidLoad] -[ViewController viewWillAppear:] -[AppDelegate applicationDidBecomeActive:] -[ViewController applicationDidBecomeActiveNotification:] -[ViewController viewDidAppear:] iOS11 / iOS12 -[AppDelegate application:didFinishLaunchingWithOptions:] -[ViewController viewDidLoad] -[ViewController viewWillAppear:] -[ViewController viewDidAppear:] -[AppDelegate applicationDidBecomeActive:] -[ViewController applicationDidBecomeActiveNotification:]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】QRコードの分割情報を取得する

iOSアプリでQRコードを読み込もうとしたら、QRコードが分割されている場合があることを知りました。 お薬手帳や車検証などにも使われているみたいです。 iOSアプリでその分割情報を取得する「これだ!」って方法が見つからなかったのでまとめておきます。 「いやいや、もっといい方法があるよ」という方はコメントいただけると助かります。。。 分割QRコードについて QRコードがなんぞやっていうのは割愛します。 ググってくださいませ。 今回伝えたいのは、QRコードは分割されることがあるということです。 上記のような2つのお薬手帳用のQRコードは2つ揃って必要な情報を取得できます。 1つのQRコードが保持できる情報量は決まっているため、 上限を超える情報量を出力するためにQRコードは分割できるって話です。 分割情報はどこにある? QRコードをバイナリにすると分かります。 バイナリ情報 説明 1バイト目の最初4ビット 3だと分割QRコード 1バイト目の後ろ4ビット 分割されているQRコードの位置(0開始) 2バイト目の最初4ビット 分割されているQRコードの最大位置 2バイト目の後ろ4ビット パリティ1 3バイト目の最初4ビット パリティ2 はい、シンプルですね。 見ての通りですが、分割情報が4ビットしかないので最大16分割までしかできません。 例 ここに「00110000 00011001 00110010~」で始まるQRコードがあるとします。 16進数にすると「30 19 32~」となります。 先程の表に照らし合わせると、 1バイト目の最初4ビットが3なので、このQRコードは分割されていると分かります。 1バイト目の後ろ4ビットが0なので、分割QRの1番目だと分かります。(0スタートなので1番目です) 2バイト目の最初4ビットが1なので、QRコードの総数は2つだと分かります。 2バイト目の後ろ4ビットと3バイト目の最初4ビットは、パリティです。2つ目のQRコードと同じになるのでIDっぽく使えます。 ちなみに、上記のQRコードの2つ目のバイナリ(16進表記)は以下の通りとなります。 「31 19 34~」 Swiftでどう取得するのか? AVFoundationでQRコードを読み取るときのデリゲートメソッド内に取得方法を記載します。 func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { if let metadataObject = metadataObjects.first { guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return } guard let readableObjectForQRCode = readableObject.descriptor as? CIQRCodeDescriptor else { return } // 16進数のQRコード情報を取得 let hexQRCodeData = readableObjectForQRCode.errorCorrectedPayload.map { String(format: "%02X", $0)} // 分割コードかチェック(trueなら分割コード) let isSeparatedQRCode = hexQRCodeData.first!.hasPrefix("3") // 分割コードの総数を取得 ​​​​​​​​let secondByteFirstHex = hexQRCodeData[1].prefix(1) + 1 ​​​​​​​​let total = Int(secondByteFirstHex, radix: 16)! // 分割コードの位置を取得 let ​​​​firstByteSecondHex = hexQRCodeData[0].suffix(1) let position = Int(firstByteSecondHex, radix: 16)! } } AVFoundationでQRコードを読み取る方法は以下記事を参考 https://qiita.com/ikaasamay/items/58d1a401e98673a96fd2 https://dev.classmethod.jp/articles/ios-avfoundation/ https://dev.classmethod.jp/articles/ios-avfoundation-avcapturemetadataoutput-qrcode/ まとめ そのうちAppleがいい感じのメソッドを提供しそうな気もする。 でも、とりあえずQRコードの仕様が分かればそんな難しくないので別に不要な気もする。 いずれにせよ困っている人の参考になれば幸い! 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSでWKWebViewとSFSafariViewControllerの使い分けiOSでWKWebViewとSFSafariViewControllerの使い分けiOSでWKWebViewとSFSafariViewControllerの使い分けiOSでWKWebViewとSFSafariViewControllerの使い分けiOSでWKWebViewとSFSafariViewControllerの使い分け

テスト投稿
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Flutter】カウンターアプリに書かれたコメントを解説する

flutter create で新しく Flutter プロジェクトを作ると自動生成されるのが「カウンターアプリ」であることは、Flutter を触ったことがある方であればピンとくるのではないかと思います。 Flutter アプリ開発者にとっての初めの一歩とも言うべきカウンターアプリですが、その main.dart に書かれているコメントを読んだことがあるでしょうか。私は毎回全置換で消しています。 ただ改めて考えてみると、このコメントも Flutter フレームワークの開発チームが Flutter アプリ開発者のためにわざわざ書いてくれたもの だと思いますので、この記事ではそのコメント全てを翻訳しながらしっかりと内容を確認してみたいと思います。 また、初学者向けの簡単な解説も交えつつ書いていければと思いますので、何かの役に立てれば嬉しいです。 ではどうぞ。 class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { まずは MyApp クラスの宣言の下、8 行目に記載された内容です。 (意訳) この Widget はアプリケーションの根っこです。 Flutter では、 Widget をツリー構造で下へ下へとつなげていくことで UI を構築します。カウンターアプリにおける MyApp という Widget はそのツリー構造のまさに開始地点(根っこ)であるということがここに記載されています。 @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } MyApp の build() メソッドの中、 14 行目からのコメントには以下のようなことが書かれています。 (意訳) これはアプリケーションのテーマです。アプリケーションを "flutter run" コマンドで実行してみてください。青いツールバーが表示されるはずです。では、アプリは起動したまま、下に書かれた primarySwatch の値を Colors.green に変更して "ホットリロード" を実行してみてください(コンソールから "flutter run" で実行している場合は "r" キーを押します。 Flutter に対応した IDE で実行している場合は単純にファイルを保存すればホットリロードが実行されます)。カウンターがゼロに戻ることなく、つまりアプリがリスタートすることはありません。 ここでは ThemeData がアプリ全体のテーマ(色など)を保持するオブジェクトであることと "ホットリロード" の説明がされています。 ホットリロードはご存知の通り、 Flutter の目玉とも言える機能です。ここで指示された通りに primarySwatch の値を Colors.blue から Colors.green に変えてファイルを保存するだけで、アプリを再起動することなく UI が変化することが体験できるようになっています。 Flutter フレームワークの開発チームとしても、まず初めにこのホットリロードを体験してほしい、ということなのだろうと推測できます。 class MyHomePage extends StatefulWidget { MyHomePage({Key? key, required this.title}) : super(key: key); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; @override _MyHomePageState createState() => _MyHomePageState(); } 次はさらに下に下がったところ、 33 行目から始まるコメントです。 (訳) この Widget はアプリケーションのホームページです。これは stateful、つまり State という(この下に定義された)オブジェクトを持っており、State には見た目を変化させるためのフィールドが定義されています。 この MyHomePage という Widget クラスは、その State の設定値を保持するクラスです。このクラスは親(つまり MyApp) から受け取った値(ここでは title)を保持していて、この title は State の build() メソッドで使われています。 Widget のサブクラスのフィールドは常に "final" でなければなりません。 ここは Flutter で動的に変化する UI を構築するためのひとつの手段である StatefulWidget の説明がされています。 StatefulWidget は Widget が設定値を保持し、 State の build() でそれを使うことで、例えばここでは親である MyHomePage から受け取ったタイトル文字列が AppBar に表示されるようになっています。 Widget に定義するフィールドは常に final でなければならないという点も重要です。 Widget は「不変な」(immutable)クラスであるため、保持するフィールドの値を変えることはできません。 Widget は「不変な値(設定値)を保持するオブジェクト」としての役割に徹する ことで Flutter フレームワークは Widget オブジェクトの(オブジェクト生成後の動的な)変化を気にする必要がなくなり、それをスムーズな UI 描画のための最適化に利用しています。 一方で、ユーザーの操作などによってフィールドの値を動的に変化させたい場合はその値を State に保持 させます。State は Widget とは違い、 一度生成したオブジェクトをなるべく使い回す ために設計されたクラスです。アプリの操作に合わせて UI を変化させるためのデータもこの State オブジェクトが保持するのが Flutter における基本的なやり方です。1 さて、先に進みます。 class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { // This call to setState tells the Flutter framework that something has // changed in this State, which causes it to rerun the build method below // so that the display can reflect the updated values. If we changed // _counter without calling setState(), then the build method would not be // called again, and so nothing would appear to happen. _counter++; }); } これは先ほど出てきた State クラスのコードです。 StatefulWidget には必ずペアになる State が存在し、 MyHomePage という Widget のペアになるのがこの _MyHomePageState である、というわけです。 さて、 53 行目から始まるコメントを確認します。 (意訳) この setState を呼び出すことで、 Flutter フレームワークに対して State が保持する何らかの値が変化したことを伝えます。これにより、下に定義した build() メソッドが再度呼び出され、変更後の値が画面上の表示内容に反映されます。もし _counter の値を setState() を呼び出すことなく変化させた場合、 build() メソッドが呼び出されずに UI も何も変化しません。 State が保持する値を変更する場合、必ず setState() をセットで呼び出さなければならない(正確には、 値を変化させる関数を setState() メソッドの引数に渡す)ことが記載されています。 Flutter フレームワークは State のフィールドの値が変化したこと自体を検知することはできません。 setState() が呼ばれることによって初めて「値が変わって UI の更新が必要になった」と判断し、 build() をもう一度呼び出すことで画面を更新します。 さて、次はその build() メソッドの中のコメント、 64 行目です。 @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( (意訳) このメソッドは setState が呼び出されるたびに実行され直します。例えば、上に定義された _incrementCounter メソッドの実行が完了された後などです。 フラッターフレームワークはこの build メソッドが高速に呼び出されるように最適化されています。つまり、Flutter アプリの開発者は UI の更新のために個別の Widget に対して何かの更新操作を行うのではなく、必要なタイミングでこの build メソッドを呼び出して全体をリビルドできるようになっています。 これは Kotlin や Swift といったいわゆる「ネイティブの」アプリ開発を経験した方にとっては見慣れない考え方なのではないかと思います。 Flutter では、一度生成した「テキスト」や「画像」などを表すオブジェクトに対して「表示内容を変更する」ようなメソッドを呼び出すことはしません。 替わりに、 build() メソッドを呼び出し直して Widget オブジェクトそのものを全て取り替える ことで画面を更新する作りになっています。 その際、 Widget の構築に利用しているフィールドの値が変わっていれば build() メソッドのロジックの実装に従って生成される Widget オブジェクトも変化し、結果として UI が変化する 、という考え方です。 ここで勘違いしてはいけないのは、 Widget オブジェクト自身はレイアウト計算や UI の描画を担当するオブジェクトではないということです。先ほどのコメントで書いてあった通り、Widget は「設定値」を保持するだけのオブジェクトですので、画面全体の Widget オブジェクトを再生成したからといって画面全体が再描画されるわけではありません。ここが Kotlin や Swift の View というものとは違う点です。 再生成された Widget と古い Widget を比較し、 UI の変更が必要な最低限の部分だけを再描画する 、という最適化を Flutter フレームワークは行っています。つまり、アプリ開発者はとにかく新しい値を保持した Widget オブジェクトを生成すれば、あとは必要なものだけを Flutter フレームワークが判断して使ってくれる、という考え方で build() メソッドを実装します。 次は 72 行目です。 return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title) (意訳) ここで、 MyApp の build() メソッドの中で生成され、 MyHomePage オブジェクトを経由して受け取った文字列を使って AppBar のタイトルをセットしています。 Widget が保持する値を State で利用する場合は、この例のように widget.xxx でアクセス可能です。ここでは、 MyApp から受け取った "Flutter Demo Home Page" という文字列が widget.title に格納されていて、それが AppBar の中に表示されるタイトルとして利用されるわけです。 body: Center( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. (意訳) Center はレイアウトのための Widget です。子となる Widget をひとつだけ受け取り、親に対して中央寄せになるように配置します。 Flutter では「テキスト」や「画像」といった表示物だけでなく、それを配置するためのレイアウトの設定を保持するのも Widget の役割です。 Center はそのようなレイアウト用の Widget のひとつであることが説明されています。 child: Column( // Column is also a layout widget. It takes a list of children and // arranges them vertically. By default, it sizes itself to fit its // children horizontally, and tries to be as tall as its parent. // // Invoke "debug painting" (press "p" in the console, choose the // "Toggle Debug Paint" action from the Flutter Inspector in Android // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) // to see the wireframe for each widget. // // Column has various properties to control how it sizes itself and // how it positions its children. Here we use mainAxisAlignment to // center the children vertically; the main axis here is the vertical // axis because Columns are vertical (the cross axis would be // horizontal). mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ (意訳) Column もレイアウトのための Widget です。Column は子のリストを受け取り、それを縦に並べます。デフォルトでは、子の幅がちょうど収まるだけの幅と、親と同じだけの高さを確保します。 "debug painting" を実行することで(コンソールでは "p" キーを押します。Android Studio の場合は Flutter インスペクタの "Toggle Debug Paint" アクションを選択してください。Visual Studio の場合は"Toggle Debug Paint" コマンドを選択します) それぞれの子Widget のワイヤーフレームを確認できます。 Column にはどのように自身のサイズを決定し、どのように子を配置するかを設定する多くのプロパティが用意されています。ここでは、 mainAxisAlignment を指定することで子を縦方向で中心寄せで配置しています。なお、 "main axis" とは、 Column においては縦方向の軸を意味します。(また、 "cross axis" は横方向です) 先ほどの Center は子を1つだけ受け取る Widget だったのに対し、 Column は複数の子 Widget を受け取る Widget で、それを縦に並べる役割を持っています。 main axis と cross axis の用語は UI を構築する上で頻繁に出てくるので覚えておくとよいでしょう。 children を縦に並べる Column においては、 main が縦、 cross が横方向となりますが、 children を横に並べる Row においては、 main は横、 cross が縦方向となります。 ここでは、Flutter の "Debug Painting" 機能についても説明されています。実際にコメントの指示通りに実行してみると、以下のように子要素の範囲や Column 自身の幅、高さが画面上に可視化され、これを元にレイアウトを調整できるようになっているというわけです。 さて、次で最後のコメントです。 floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods (意訳) この末尾のカンマは build メソッドの自動フォーマットを良い感じにするためのものです。 Flutter は Widget をツリー構造で構築する仕組みになっている都合上、 build() メソッドは Widget の入れ子になることが多いです。つまり、ソースコード的にネストがどんどん深くなっていきます。 そのネストをきれいな階段上にフォーマットするための目印として、標準で用意されているコードフォーマッタはカッコの後ろのカンマを手がかりにします。そのため、基本的にはきれいにフォーマットするためにカンマはつけた方が良い旨が書かれています。 なお、このネストが深くなることに対して違和感を感じるアプリ開発者も多いようですが、考えようによっては Web ページの HTML も Android ネイティブの XML も、 UI を構築するための記述はネストすることが多いですし、また ネストしているからこそ各部分の記述がページの大枠を示すものなのか、それとも細かな一部のパーツを表すものなのかがネストの深さから推測しやすい 、というメリットがあったりします。 このあたりは慣れの問題もあると思いますが、とにかく Flutter ではネストするのが基本で、それをきれいに階段上に整形するためにカンマをつけるのは重要である、ということです。 以上です。 自動生成されたカウンターアプリのコードは Flutter の初学者も読む関係でここに書かれたコメントは Flutter の特徴を手っ取り早く掴むためにかなり厳選された内容になっています。 特にわれわれ日本人にとっては無視されがちな英語のコメントではあると思いますが、一方でこのコメントに従って手を動かしてみることで、効率よく Flutter の仕組みをざっと把握し、また用意されたツールや仕組みを体験できる内容になっていることがわかったのではないかと思います。 すでに何かしらの記事やドキュメントを見ながら Flutter を触っている方も多いと思いますが、一度スタート地点に戻ってここに書かれた内容を追ってみてはいかがでしょうか。 他のやり方もいろいろと存在し、それは「状態管理」という名称で説明されています。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む