DeployGateのコマンドラインツールのインストールでコケた
こんなログが出た
"xcrun clang -o conftest -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/universal-darwin19 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/backward -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -g -Os -pipe -DHAVE_GCC_ATOMIC_BUILTINS conftest.c -L. -L/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib -L. -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/usr/local/lib -arch x86_64 -lruby.2.6 " In file included from conftest.c:1: In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby.h:33: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10: fatal error: 'ruby/config.h' file not found #include "ruby/config.h" ^~~~~~~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10: note: did not find header 'config.h' in framework 'ruby' (loaded from '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks') 1 error generated. checked program was: /* begin */ 1: #include "ruby.h" 2: 3: int main(int argc, char **argv) 4: { 5: return 0; 6: } /* end */
Xcodeのコマンドラインツールのパスが違ってたので直したらインストールできた
$ sudo xcode-select -switch /Library/Developer/CommandLineTools
これだけ。
あらざ〜す
MacのhomebrewでOpenSSLがビルドエラーになる場合の対処方法|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
RiverPodをやってみた
Flutterの設計で一番悩ましいのが、ViewとModelの連携。状態遷移だと思われる。
2020年の初頭からFlutterやりはじめて、「Provider + ChangeNotifier」でやってた。これでも全然動く。
ただ、Providerは必ずcontext
を経由する必要があるので、ウィジェットの階層構造に気をつけないといけないとか、データを変更した後にnotifyListeners
を自分で呼ばないといけないとか、そういう面倒さがあった。
値を再代入するだけで、当該UIのウィジェットが再ビルドされたらそれで良いのだけども、GUI(デスクトップアプリやスマホアプリ)を作る場合にそこが一番面倒。
RIverpodの便利なところは、提供されるProviderがimmutableに設計されているため、グローバルに定義しても良い点。BuildContextに依存しない点の2点がでかい。
riverpod版
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:state_notifier/state_notifier.dart'; final counterProvider = StateNotifierProvider((_) => CounterNotifier()); class CounterNotifier extends StateNotifier<int> { CounterNotifier(): super(0); void increment () => state++; } class CounterPage extends HookWidget { Widget build(BuildContext context) { final v = useProvider(counterProvider.state); final counter = useProvider(counterProvider); return Scaffold( body: Center( child: Text(v.toString(), style: TextStyle(fontSize: 24)), ), floatingActionButton: FloatingActionButton( onPressed: () => counter.increment(), child: Icon(Icons.add), ), ); } }
StatefulWidget + State + setState
import 'package:flutter/material.dart'; class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return new Scaffold( body: Center( child: Text('$_counter', style: TextStyle(fontSize: 24)) ), ), floatingActionButton: new FloatingActionButton( onPressed: _incrementCounter, child: new Icon(Icons.add), ), ); } }
この2つを見比べると、パッと見るだけでも以下のことがわかる。
- ユーザーの操作に伴い
setState
を書きまくるコードはだいぶ辛い。 - StateNotifierでは
state
を再代入するだけに徹する。公開される値がstate
しか無いのがミソ。- 再代入するとはいえ、State
の T
の持ってる色んなプロパティの状態をキープしつつイミュータブルにしたいので、freezedパッケージを使うのよね、と。
- 再代入するとはいえ、State
個人的には、notifyListener()
を意識しなくて良いのが好きなので、StateNotifier
を推していきたい。
- スクロールの管理
- テキストボックスの値の代入
- 引数ありの画面遷移
この辺がクリア(自分の中で噛み砕ければ)できれば、Riverpodいける。がんばろう。
FlutterでTextFieldに非同期で取得した結果を初期値に入れたい
色々探してやっとわかった..
initState
に直接await
って書くことは出来ない。そりゃそうだな。ビルドが終わってから状態を変え、再ビルドするという方法を探していた。
class MyWidget extends StatefulWidget { @override State createState() => new MyWidgetState(); } class MyWidgetState extends State<MyWidget> { var _result; @override void initState() { loadAsyncData().then((result) { setState(() { _result = result; }); }); } @override Widget build(BuildContext context) { if (_result == null) { return new Container(); } return new TextField(initialValue :result); } }
要約するとこうなる。
initState
の中にsetState
を用意して、非同期の結果をメンバ変数にいれるsetState
もいつ呼ばれるかわからんが、呼ばれるとbuild
がもっかい走るので、result
の状態に応じてビルドするWidgetを変える。
うーん、今回はStateFulWidgetにしたけど、ProviderとStatelessWidgetでも同じことができる気がする... あとでやってみよう。
PrismのDialogServiceでDIしたViewModelが毎回初期化される
PrismのDialogService
でDIしたViewModelに限って、毎回ViewModelのコンストラクタが呼ばれるという現象がありました。
prism:ViewModelLocator.AutoWireViewModel="True"
にしているのにね。この設定にした場合、ViewModelのインスタンスはSingletonになってくれるが、DialogService
で呼び出す小画面に限りなぜか・・・
- バージョン: Prism.Wpf 7.2.0.1422
結論から言えば、このコードを書けばSingletonになってくれた。
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<OrdeSearchPageViewModel>(); }
RegisterSingleton で、型に対象のVMのクラスを指定するだけだった。Prismの沼かもしれん。
Flutterでカメラで画像を撮って保存したい
まー、ありますわね。そーゆーのがね。
要件としては、写真撮ってメモを追加して何件かリストにしてPOSTだから、取った写真をリスト表示できることが必要。これが意外と難しくてワロタ。
最終的に、こういう風にするしかなさげ。
image_picker
プラグインで画像をカメラでとって、path_provider
にて、application内のディレクトリに保存してパスを持っておく- ギャラリーに移す場合は、
gallary_saver
でファイルをコピーする。 image_gallay_saver
はバグがあって動かないようだ。
まとめ
ギャラリーに直接保存してしまうと、保存先のファイルパスが取れない。戻り値がboolになるのは、gallary_saverの仕様。
Future<bool> takePhoto() async { final ImagePicker picker = ImagePicker(); final PickedFile _image = await picker.getImage(source: ImageSource.camera); return GallerySaver.saveImage(_image.path) }
true/falseより、保存先のパスが一番欲しいよねw issueに上がってるけど、できないのかな。FlutterのMethodChannel#invokeMethod
は
あ、あとこのライブラリでやると、画像がギャラリーに保存できなかった。issueも上がってる。
こんだけのコードなんだけどね。多分MethodChannelの使い方が間違っているのだろう。
import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/services.dart'; class ImageGallerySaver { static const MethodChannel _channel = const MethodChannel('image_gallery_saver'); /// save image to Gallery /// imageBytes can't null static Future saveImage(Uint8List imageBytes, {int quality = 80, String name}) async { assert(imageBytes != null); final result = await _channel.invokeMethod('saveImageToGallery', <String, dynamic> { 'imageBytes': imageBytes, 'quality': quality, 'name': name }); return result; } /// Save the PNG,JPG,JPEG image or video located at [file] to the local device media gallery. static Future saveFile(String file) async { assert(file != null); final result = await _channel.invokeMethod('saveFileToGallery', file); return result; } }
image_gallery_saver/image_gallery_saver.dart at master · hui-z/image_gallery_saver · GitHub
そんなかんじ。
Flutterのjson_serializableで無限ループになったら
おきまりの flutter pub run build_runner build
を叩くと、エンドレスにビルドが走って終わらなくなった・・・。@JsonSerializable
アノテーション以外のファイルまで見に行ってる。widget_test.dart
を見に行くアホがおるかい。
英語でググってみたところ、このissueがあった。
どうやら、analyzer
というFlutter内部で利用されるライブラリのバグのようで、0.39.17
→ 0.39.14
にダウングレードしたら、ビルドできました...
ダウングレードするには、pubspec.yaml
にこの記述を加筆するだけ。
dependency_overrides: analyzer: '0.39.14'
追記 2020.9.17
analyzer 0.40.2 で修正されたようです。めでたしめでたし。
Vue.jsでは親子関係の画面をネストされたルーティングで対応する
例えば、お申し込みフォームが複数の画面に分かれているが、「1つの画面操作」として捉えて、データを管理したい場合等。
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // /user/:id/profile がマッチした時に // UserProfile は User の <router-view> 内部で描画されます path: 'profile', component: UserProfile }, { // /user/:id/posts がマッチした時に // UserPosts は User の <router-view> 内部で描画されます path: 'posts', component: UserPosts } ] } ] })
chilren属性を使うだけ。便利。