babelのセットアップ覚書

JavaScriptのモジュールシステムが全く理解できなくて困っていたのだが、ようやく友だちになれそうな程度にはわかるようになった。 React Nativeやるときにはimportとかexportを使うのに、Node.jsのときはrequireになるのが解せない。 JavaScriptやるのにこいつらは避けて通れないものなのに、そもそもモジュールの仕組みもわからなくて往生した。 歴史的経緯でそうなっているのはわかったけれども、これからJavaScriptやるならどっちかにまとめたいところ。 今からやるなら新しい構文のimportで統一したいが、Node.jsはimportはそのままでは理解してくれない。 そこでトランスパイルが必要になる。 で、トランスパイルが必要なのもわかったけれども、ではどうやって準備すればいいのかがわからなくてこれまたハマる。 このあたりのセットアップがよくわからなくてJavaScript敬遠していたのもある。 ようやくbabelのセットアップのやり方、意味がわかったので覚書として残しておく。 とりあえずこれでJavaScriptであれこれ気楽に試せるようになった。 セットアップ Node.jsのインストールとかは割愛。 nodeとかnpmは使える状態での手順。 `npm init`でnode moduleのセットアップ babelのインストール`npm i --save-dev @babel/core @babel/cli @babel/node @babel/preset-env` `.babelrc`の設定 `npx babel-node xxx.js`でxxx.jsをbabelでトランスパイルした上でnodeで実行 勉強のためにES6で書いたJavaScriptをとりあえずnodeで動かして動作確認できるようにするだけの目的での話。 実際にプロダクトとして動かす場合は`babel-node`は使わない。 https://babeljs.io/docs/usage/cli/#babel-node 補足 babelのインストールはcore, cli, node, preset-envがあればとりあえずは足りた。 とりあえずnpm i -gは使わない。 babelのバージョンをプロジェクトごとに管理するかどうかはわからないけれども、グローバルにインストールしなくてもnpxを使えばちゃんと動かせるので問題ない。 @babel/coreなどの@babelの部分はscoped packageといって、別にアノテーションではなくnpmのユーザ名である。 npmの仕組み上パッケージ名が早いもの勝ちになってしまうので、例えば私がbabel-some-great-utilみたいな名前でパッケージを上げたりできてしまう。 紛らわしいし、使いたいパッケージ名が使えないなんて問題が起こるので、その対策として生まれた仕組み。 @babel/coreなどはbabelのバージョン7になる。 今回はとりあえず動けばいいので、.babelrcはこれだけで問題ない。 { "presets": ["@babel/preset-env"] } 本来なら動作環境に合わせて設定すべき。 https://babeljs.io/docs/usage/babelrc/ .babelrcではなくpackage.json内に"babel"ブロックを定義することでも代用できる。 この設定ならpackage.json内に書いても問題ない気もする。 スクリプトの実行はnpx babel-node xxx.jsで、トランスパイル→nodeで実行をひとまとめにできる。 ファイルの監視 さらにJSファイルを書き換えて都度コマンドを叩くのは面倒くさいので、変更を監視して自動的に再実行させる。 npm i --save-dev nodemonでnodemonをインストールする。 npx babel-node xxx.js→npx nodemon xxx.js --exec babel-nodeに置き換えて実行する。 これだけ。 package.jsonのscriptを使う 毎回コマンドを打つのは面倒くさいので、package.jsonのscriptブロックを利用して簡略化する。 "scripts": { "start": "nodemon xxx.js --exec babel-node" }, startよりwatchの方が適切だろうか。とにかく、"start"の部分は自分で好きにすればいい。 こうしておくとnpm run startで記述したコマンドが実行される。 package.json内だとnpxコマンドは必要ない。

shields.ioを使ってバッジを表示する

https://shields.io/を使ってバッジを表示する。 今回はDart Packagesで公開されているパッケージのバージョンを表示するバッジを出したかった。 Dart Packagesはshields.ioでサポートされており、https://img.shields.io/pub/v/box2d.svgというような感じでパッケージのバージョンを表示することができる。 ちなみにbox2dの部分がパッケージ名なので、ここを自分が表示したいパッケージ名に書き換えればよい。 この方法で表示されるパッケージのバージョンは、安定版の最新バージョンが表示される。(安定版というのは1.0.0-rc1みたいにセマンティックバージョンの後ろに何もつかないやつのことを指している) https://img.shields.io/pub/v/box2d.svg https://img.shields.io/pub/v/pointycastle.svg 本題 ところでDartはバージョン2への移行時期であり、Flutterで利用する場合には開発版を利用する必要があったりする。 例えばredux_persistやpointycastleなどがそう。 ではこれら開発版のバージョンのバッジを表示するためにはどうしたら良いのだろうというのが今回の本題。 今回はPointy Castleというライブラリの開発版バージョンを表示する。 これを書いている時点での安定版は0.11.1で開発版は1.0.0-rc1となっている。 Dart Packagesでは各パッケージのバージョン情報をjsonで取得することができる。 https://github.com/PointyCastle/pointycastleの最後に.jsonとすればよい。 shields.ioではJSONからクエリを使って直接バッジを作成することができる。https://shields.io/#dynamic-badge クエリはjsonpathを使ったクエリが使える。 今回の場合使うクエリは$.versions[?(@=="1.0.0-rc1")]になる。 https://img.shields.io/badge/dynamic/json.svg?label=pub&url=https%3A%2F%2Fpub.dartlang.org%2Fpackages%2Fpointycastle.json&query=%24.versions%5B%3F(%40%3D%3D%221.0.0-rc1%22)%5D ちなみにこの方法では動的に最新バージョンを取得することはできない。 (クエリをうまいこと扱えばできるのかもしれないが、私にはわからなかった) 例えばクエリを$.versions[?(@.includes("rc"))]とするとバージョンにrcを含むものだけが取得できる。 しかしrcを含むバージョンが複数ある場合、それら全てが列挙されてしまう。 $.versions[?(@.includes("+"))]をクエリに使った場合:

FlutterでBottomAppBarを表示

サンプルはここを確認するとよいと思う。 https://github.com/flutter/flutter/blob/master/examples/flutter_gallery/lib/demo/material/bottom_app_bar_demo.dart このサンプルではFABの位置やノッチの有無などをカスタマイズできるようにしている関係でなんだかややこしそうに見えるが、やることは非常に単純。 Scaffold内のbottomNavigationBarにBottomAppBarを渡す Scaffold内のfloatingActionButtonLocationでFABの位置を指定 ノッチの有無はBottomAppBarのhasNotchで指定 必要なメニュー等はBottomAppBar内のchildに追加 これだけでBottomAppBarを表示できる。非常に簡単。 BottomAppBar内のアイテムを複数指定したい場合、childなのでRowでくるむなどの工夫が必要。 flutterの公式リポジトリをクローンしてきて、material demoを動かすとどんな動きか確認することができる。 ちなみに公式リポジトリ内のexampleを動かすにはここを見ればよい。 flutterの初期設定を済ませていることを前提として、手っ取り早くexampleを実行するために必要なことをまとめるとこうなる。 クローンしたあとbinディレクトリにパスを通す(リポジトリ内の最新版flutterを使うため) `flutter update-packages`を実行して各種依存パッケージの解決を行う IntelliJ IDEAを使っているなら`flutter ide-config --overwrite`を実行することでRun Configurations等の設定をしてくれる 後は実行したいexampleをIDEから選んで実行 binディレクトリにパスを通すと、普段使っているflutter(私の環境だと0.3.2)と公式リポジトリのflutter(これ書いてる時点では0.4.4-pre.8)が混じってしまうのだけど、公式リポジトリを触っているときだけ後者を有効にするみたいな設定の仕方ってあるのだろうか。 ありそうな気がするけど私は知らないので、都度パスを追加して対応している。 追記 別にリポジトリをクローンしてこなくてもPlayストアにアプリが公開されていることを知った。 https://play.google.com/store/apps/details?id=io.flutter.demo.gallery 動きを確認するだけならこっちのほうが手っ取り早い。

Settings Repositoryプラグインを使ってIDEの設定を共有する

いつもOverwrite local/Overwrite remoteが、どっちがどっちなんだっけと使うときに混乱するのでメモ。 どっちがどっち、というのはovwerwrite localが、現在の設定をリモートリポジトリの設定で上書きするのか、現在の設定でリモートの設定を上書きするのか混乱してしまうのである。 Overwrite localは現在の設定をリモートの設定で上書きする、が結論なんだけど。 これがわかりにくいと思うのは私の英語力がないせいなのだろうか。 Settings repositoryの設定について ちなみにSettings Repositoryをご存じない方向けに簡単に紹介。 IntelliJ IDEAで使える設定共有用のプラグイン。 私の場合で言うと、Android Studio(stable/canary)とIntelliJ IDEA community editionを行ったり来たりすることがあるので、このプラグインを使って設定を共有している。 バージョンアップする際に以前の設定を引き継ぐというのはできるが、同時に運用しているときにAで行った設定変更をBでもまたやらないといけない、というのが起こらなくなるので非常に便利だと思う。 利用しているプラグインによっては、そのプラグインの設定ファイルもバックアップ対象になるらしい。 例えば私はIdeaVimを利用しているが、どのファイルのどの位置にカーソルが移動した、という情報までバックアップ対象になってしまっている。 そのため必要に応じて不要な設定ファイルは.gitignoreで管理対象から外すなど工夫が必要。 (私はvim_settings.xmlは管理対象から外している) MacであればFileメニューのところにSettings Repositoryがあるので、GitHubなりBitbucketなりで管理用リポジトリを用意してそのURLを設定すれば使えるようになる。 ちなみにどうもエディタでタブを使わないとか、キーマップの設定でどれを使うかなどまでは合わせてくれないようだ。 例えば私の使っているキーマップはMac OS X 10.5+ copyとなっているのだが、このキーマップ設定自体は共有してくれるものの、これが有効な状態にまでは復元してくれない。 そのため、どのキーマップを使うか、コードスタイルはどれを使うかなどは手動で直さないといけないようだ。

JavaScript再入門中

JavaScriptはやろうかなと手を出した時期があったのだが、そのときは挫折した。挫折したというか、優先度の問題から深入りするのを止めたというのが正しい。

当時はAndroidのコーディングすらまともにできていないのに、JavaScriptに手を出すのは無謀ではないかと言い訳をしていた記憶がある。

Read full post gblog_arrow_right

FlutterでTwitterクライアントを作ってみた

FlutterでTwitterクライアントを作ってみた。 レイバン製造機になる未来しか見えないので公開したりはしないけれど。 とりあえずマルチアカウント対応とタイムラインの取得を実装して力尽きた。 twitter_loginなどのライブラリがflutter(dart)でも存在しているようだが、そういうのは利用せずに直接APIとやり取りする形で実装した。 使ったライブラリ crypto Twitter APIを利用する署名計算のため cryptoutils 同上 url_launcher ブラウザ立ち上げのため flutter_redux redux_persist_flutter mockito モックテスト Access Tokenの取得はこの記事を参考にして実行した。 Kotlinで書きたい問題 Androidネイティブから入門した身からすると、dartではなくKotlinで書きたいという気持ちでいっぱい。 はじめはセミコロンのつけ忘れが多発し、その次はインスタンスを生成する際にnewを付け忘れるが多発して困ったからという理由が大きかった。newのつけ忘れは、なくても動く場合と、つけないと動かない場合があって、その違いがいまいち分かっていない。 しかも付け忘れて動かないのは、実行しないとわからないのが更に困りものだった。 Kotlinで書きたい理由は、今だとこの2種類の理由から。 data classが使いたい Null許容・非許容を型で表現したい data classについてはdartのissueに上がっているので、そのうち実装されるかもしれない。 Javaで書くことに比べたらdartでのデータオブジェクトの記述はスッキリしている(getter/setterを定義する必要はない)のだが、data classならequalsメソッドをいちいちオーバーライドしなくても済むとか、そういうところが便利だと思うので、早くdartにもdata class来てほしい。 まあそれは来たらいいな程度の気持ちだけど、null許容・非許容を型で表現したいのは結構切実な問題である。 dartはカジュアルにnullが飛んできすぎな気がする。 dartではあらゆるものがオブジェクトなので、intだろうと初期化されていなければnullとなるので、nullと格闘することが多かった。 このあたりは私の実装の仕方が悪いという面も大きいかもしれない。 が、それにしてもnull許容・非許容が型で表現できるKotlinを知っていると、nullで消耗するのがつらい。 Textにnullが渡ってアプリがクラッシュする→どこでnullが渡ったのか把握しきれないとかいうのが多くてね・・・。 dartのasync/await便利 asyncなメソッドを定義してやればそれだけで非同期処理が記述できてしまうのは非常に便利だと思った。 awaitと組み合わせて複数のリクエストを同期的に書けるのはめちゃくちゃ楽だった。 Androidネイティブだと、RxJavaを使って連結させてやるような処理がシンプルに書けるのはよい。 ネットワークを使った処理がシンプルに書けるのはすごい楽だった。 redux アプリ内の状態を管理するのにreduxを使った。 最初はflutter_reduxから導入の仕方を学んだのだが、redux初見の私にとってはこれは悪手だった。 なぜシングルトンで管理しているはずの状態を、わざわざ_ViewModelに移し替えているのか最初は理解できなくて混乱した。 flutter_reduxはredux.dartとflutterの橋渡しをするライブラリなので、そこを切り離して考えないといけないだろう。 dart.redux dart.redux アプリケーションの状態を1つのクラスに集約する(名前は別になんでもいい。以下利便性のためにAppStateと記述するけど、名前はなんでもいい) 状態クラスはイミュータブルで変更不可にする(重要) AppStateはアプリケーション内で唯一の存在となるStoreが保持する 状態を変更するのはActionで、ActionはStore経由でdispatchする。dartには型があるので、○○Actionみたいなクラスを作っていく。 Actionと状態の変更を対応付けるのがReducer。 Reducerはネストというか、AppStateが持つ各フィールド(個々のアプリケーションの状態。カウンタの値とか、Twitterクライアントならツイートの一覧とか)とReducerを個別に対応させることもできる。 この場合、AppStateの特定のフィールドの値と、それを変更するActionの対だけをそのReducerで管理すれば良くなるので、見通しが良くなる。 Reducerでは変更する状態とActionの組み合わせを使って新たな状態を返す。 AppStateの変化はStoreからStreamとして流れてくる。このStreamはbroadcast streamなので、状態変更に関心を持つやつが、このStreamをlisten()すれば状態変更をキャッチできる。 MiddlewareはStoreにActionがdispatchされて、そのActionがReducerに渡される前に処理を挟むことができるやつ。例えば流れてくるActionをログに保存するとか、状態をファイルに保存するとか、1つのActionを複数のActionに分割するとか。 今回のTwitterクライアントでは、サインインのアクションをMiddlewareで処理して、その結果からAccess Tokenを更新するActionを発行してアプリ内のAccess Tokenを更新するような処理を行った。 dart.reduxのおさらい アプリケーションの全状態を保持する`AppState`を用意する `Store`が`AppState`を保持する `Store`経由で`Action`を投げる `Reducer`が`Action`を元に`AppState`を更新する `Store`の`onChange`を`listen()`することで`AppState`の変更を監視する flutter_redux flutter_reduxが担うのは、各WidgetからStoreへアクセスするしくみを提供すること。 `Store`の保持 保持した`Store`へのアクセス `Store`からの変更の`listen()`の隠蔽 たぶんflutter_reduxを使わなくても、`Store`は結局シングルトンなので、直接アクセスするしくみを作ってしまえばそれで済む(はずだし、そっちのがシンプルでわかりやすい気もする)。 一方で、`AppState`の変更はStreamで流れてくるので、この購読と解除をしなければならない。その部分をflutter_reduxは隠蔽してくれるので自分で管理しなくて済む、というところにメリットがあると思われる。 アプリケーションのルートWidgetをStoreProviderにして、Storeを保持する。 子のWidgetではStoreConnectorを通じてStoreにアクセスする。 StoreConnectorはconverterを経由してAppStateをViewModelに変換する。 ViewModelというのは、該当のWidgetを構築するのに必要なだけの状態を別途切り出したやつというイメージ。 状態変更の度にWidgetの更新が走らないようにする役目もある。 状態を持ってるのにStatelessWidgetになるというのがいまいち理解できなかったが、状態を管理しているのはStoreであってこのWidgetではないからだろうか。 データの永続化 redux_persist_flutterは、reduxで管理するアプリの状態をファイルに書き出して永続化するライブラリ。 今回Twitterクライアントをflutterで作っていて、データの永続化をどうすればいいのかいまいち分からなくてとりあえずこれを使った感じである。 別にシリアライズ方法はなんでもいいのだろうけれど、JSONにパースするようになっていたのでそのようにした。 しかしStoreで管理する状態が増えれば増えるほど、JSONへのパース処理を追加するのが大変になって辛くなっていく。 簡単なKey/Valueのデータであれば、shared_preferencesを使えばいいのだろうが、アプリのデータを保存するのには向かない。 自前でファイルに保存するか、Databaseのライブラリを導入して保存するかといったところなのだろうか。 どっちにしろデータオブジェクトとのマッピング処理を自前で実装しないといけないのが面倒くさいところ。 またデータの暗号化もどうしたらいいのやらという感じでよくわからない。 その他雑感 エラーメッセージがわかりにくいところがツライ。エラーの内容は分かるものの、そのエラーが自分の書いたコードのどの部分で発生しているのかを把握するのに大変労力を必要とする。 UIの記述がツライ。 ネストが深くなりすぎてツライ。 これ絶対後からいじれなくなるやつだと思う。 IDEのサポートが受けられるのはめちゃくちゃメリットだと思う。 IntelliJは偉大だ。 無料で使えるCommunity Edditionが使えるのは偉い。 React NativeだとWebStormになると思うので(IntelliJ系IDE使うなら)、そこはメリットだろう。
Read full post gblog_arrow_right

Android Studio2.x時代のプロジェクトを3.0環境へ更新

ストアに公開しているアプリは2018年8月までにtargetSdkVersionを26以上にする必要がある。その関係で以前にリリースしたアプリを更新しているのだが、その際に最初のハードルとなるのが古いAndroid Studioで作ったプロジェクトを現在のバージョンに更新する作業である。 最近何回も同じことをやっているので、備忘録的に書いておく。 基本的には全部Migrate to Android Plugin for Gradle 3.0.0に書いてあるので、そのとおりにやるだけである。 書いている途中でAndroid Studio 3.1が正式版になった。が、3.0から3.1への更新はそんなに大きく変更しなくても済むので、基本は3.0へのマイグレーションガイドに書いてあることに対応すればよいはず。 Gradleのバージョン更新 まず始めにGradle(Gradle wrapper)のバージョン更新を行う。Android Studio3.0は最低でもGradle4.1以上が必要。(3.1はGradle4.4以上) gradle wrapperの更新はgradle-wrapper.propertiesファイルを書き換えてgradle syncを行うだけ。 私は./gradlew wrapper --gradle-version=<Gradleのバージョン>コマンドで更新している。これで更新したらシェルスクリプトの更新もかかる場合があるので、こっちのほうがいいのかなという雰囲気で選んでいるだけだったりする。 コマンドで更新した場合、distributionUrlで指定されるgradle wrapperが4.x-bin.zipといった感じでバイナリのみのものになる。Android Studioはallにしとけと変更を促してきて、結局手書きでdistributionUrlを書き換えることになるので、普通にマイグレーションドキュメントにあるようにgradle-wrapper.propertiesを書き換えるだけでいいと思う。 ちなみに利用するgradleのバージョンだが、私の場合Twitterで見かけたGradleのリリースツイートを見て覚えてるバージョンを利用している。今だと4.6。 使えるバージョンはhttps://gradle.org/releases/で確認できる。基本的には最新使っとけばいいんじゃないだろうか。 build.gradleの更新 android gradle pluginのバージョンを更新 repositoryに`google()`を追加する(先にGradle wrapperのバージョンを上げておく必要がある) 利用しているgradle pluginのバージョン更新 プロジェクトで利用しているgradle pluginのバージョンが古い場合、原因がよくわからないエラーが多発する。例えばNo signature of method: com.android.build.gradle.internal.scope.VariantScopeImpl.getGenerateRClassTask() is applicable for argument types: () values: []とか。こういうのは利用しているgradle pluginを最新のバージョンに更新すると解消されることが多かった。 基本的にAndroid Studioが利用しているプラグインの新しいバージョンがあれば教えてくれるはず(網掛けになって新しいバージョンがあることを示唆してくれる)ので、それに従ってgradle pluginのバージョンを上げてみると解決する場合が多いだろう。 エラーメッセージで検索してもこれといった解決策が見つからないという場合には、利用しているプラグインのバージョンを上げることを試してみよう。 ライブラリプロジェクトを利用している場合 昔はライブラリプロジェクトを利用している場合、publishNonDefault trueを設定して、アプリケーションモジュールをdebugビルドするときは、ライブラリプロジェクトもdebugビルドにするなんて指定をしている人もいただろう。 この設定をしている場合、Android Studio3.xにアップデートするにあたってちょっとした手直しが必要になる。 Android Studio3.0からはライブラリモジュールのビルド設定は、利用するアプリケーションモジュールのものと同じものが利用されるようになった。appモジュールでdebugビルドを選んだら、自動的に依存しているライブラリモジュールもdebugビルドでビルドされる。 そのため以下の手直しが必要。 ライブラリモジュール publishNonDefault trueの記述を削除する。 アプリケーションモジュール 例えば以下のように記述していたとする。 debugCompile project(path: ":library", configuration: "debug") releaseCompile project(path: ":library", configuration: "release") この場合、この2行は不要になるので削除。その後あらためてimplementation project(":library")とライブラリモジュールへの依存を記述する。 buildTypeを増やしている場合 追加でbuildTypeに手を加えている場合(デフォルトのdebugとrelease以外に定義している場合)、増やしたbuildTypeの定義にmatchingFallbacksという行を追加してやる必要がある。 これはそのbuildTypeが使われるときに、それが存在しないライブラリプロジェクトなどがどのbuildTypeを使えばいいかを指定するものだ。 Android Wearアプリを利用しているプロジェクト ライブラリモジュールと同様の問題と変更が行われている。publishNonDefault trueが要らなくなって、debugWearApp ...という記述群がwearApp(":wear")の1行で済むようになった。 プロダクトフレーバーを利用している場合 新しくflavorDimensionsを最低1つは定義しないといけなくなった。 productFlavorは何らかの基準で使い分けているはずなので、その基準を定義すれば良い。例えばhttps://github.com/gen0083/FilteredHatebuこのプロジェクトは、ネットワークのレスポンスという観点からmockとprodというプロダクトフレーバーを定義している。 ネットワークの観点で切り分けているので、flavorDimensions "network"という感じで定義してやる。 後はproductFlavorの定義の部分で、どのdimensionに属する定義なのかを指定してやればいい。flavorDimensionsが1つしかないのであれば省略可能である。 私は最初勘違いしていたのだが、これは決して各フレーバーごとに異なるdimensionを割り当てなければならないということではない。このプロジェクトでは最初mockにtest、prodにdefaultというdimensionを割り当てたのだが、そうするとプロダクトフレーバーはmockProdDebugという形になってしまい、mockとprodを切り替えられなくなってしまった。切り替えて使うものについては、同じdimensionを割り当てないといけない。 apt → annotationProcessorへの置き換え これは確かmustだったような気がする。(気がするというのは、最近更新したプロジェクトの中にはaptを使っているものがなかったので) 古いプロジェクトだとgradle pluginを使ってアノテーションによるコード生成ライブラリを使っていたと思うが、その機能は公式に取り込まれているので、gradle pluginの削除とaptをannotationProcessorに置き換えてやる。
Read full post gblog_arrow_right

flutterやるならぜひ登録しておきたいLive Template

Flutterを触り始めたのだが、とにかくWidgetのレイアウト変更がツライと感じていた。 AndroidでいうところのViewのレイアウトがコードでゴリゴリ書いていく感じになっているので、インデントが深くなってツライ。Widgetの考え方もAndroidのViewとはちょっと違う(レイアウトに関する設定はレイアウト情報を持つWidgetでくるむとか) ゼロから作る分にはまだいいのだが、一度作ったレイアウトに対して、「このTextにmargin付け加えたい」となったときがツライ。シンプルなレイアウトならまだいいが、Widgetが何個も登場したり、何回層もネストされてたりすると正直触りたくない。 例えばこんな感じ。 @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("FriendlyChat"), ), body: new Column( children: <Widget>[ new Flexible( child: new ListView.builder( padding: const EdgeInsets.all(8.0), reverse: true, itemBuilder: (_, index) => _messages[index], itemCount: _messages.length, ), ), new Divider(height: 1.0,), new Container( decoration: new BoxDecoration( color: Theme.of(context).cardColor, ), child: new Text("hoge"), ), ], ), ); } これはまだかわいいものだが、それでもめんどうくさい。 そこでLive Templateを追加して、IntelliJのSurrond With機能を使って簡単にWidgetを囲えるようにしてみた。Flutterのチュートリアルを試したりするのに活躍するのでかなり捗ると思う。 Live Templateを定義 Preference > Editor > Live Templateが定義場所。 定義する場所は別にどこでもいいのだろうけれど、Flutterに関することなのでFlutterのところに追加した。 new Column( children: <Widget>[ $SELECTION$ ] ), Dartファイルに適用されるように指定して、Reformat according to styleにチェックも入れておく。 new Container( child: $SELECTION$ ), childを1つしか取らないWidgetでラップする場合に使うやつもついでに追加。使っているのがColumnとContainerであることに特に意味はない。まあそこは必要に応じてクラス名を書き換えればいいだろうから気にしない。 Live Templateを定義したら、後は囲いたいWidgetを選択した状態で、Surround with機能を呼び出し(私の環境だとcmd+opt+t)、定義したLive Templateを適用すればよい。楽ちん。 Live Templateは初めて活用したので、もっとこうした方がいいよというのがあったら教えて欲しい。 追記: 記事を書き終わった後で、そもそも標準でWidgetをラップする機能が存在していることを知った。ラップしたいWidgetのクラス名にカーソルをあわせた状態で、Intention Actions(Macならopt+enterで出るやつ)を使うとWidgetを別のWidgetでラップすることができる。わざわざLive Templateを追加する必要はなかった・・・。

カスタムフォトウォッチVer2の紹介

Android搭載のスマートウォッチ向け、自分の好きな画像を文字盤に設定することのできるアプリがカスタムフォトウォッチです。 アプリ実行に必要なもの Android搭載のスマートウォッチ スマートウォッチとペアリングしたAndroidのスマホ(今のところiPhone対応の予定はありません) スマートウォッチのウォッチフェイスをカスタマイズするアプリなので、スマートウォッチがないと意味をなしません。スマホだけでは単なる画像編集アプリのような何かにしかならないのでご注意を。 Android搭載スマートウォッチはiPhoneともペアリングして使えますが、今のところこのアプリはiOSには対応していません。 カスタムフォトウォッチはスマホとスマートウォッチの両方にインストールする必要があります。 以前のバージョンであればスマホからインストールすれば、ペアリングしているスマートウォッチにもアプリが自動的にインストールされていましたが、Ver2からはそれぞれ個別にインストールが必要になっていますのでご注意ください。 実行に必要なソフトウェア GooglePlay開発者サービス Wear OS by Google(スマホとスマートウォッチのペアリングを行うアプリ) これらはスマートウォッチとスマホとの間の通信処理を行うために必要となっています。インストールされていてもバージョンが古い場合にアプリがうまく動作しないおそれがあります。バージョンが古い場合はアプリから更新を促すメッセージが表示されると思うので、各アプリの更新をお願いします。 メッセージを無視しても使うことはできると思いますが、スマホから設定した画像がスマートウォッチに表示されないなど、データの同期がうまくいかないおそれがありますのでご注意ください。 使い方 スマホ側 まずは画像を追加しましょう。右下のプラスボタンを押せば画像を追加できます。 スマホ側からスマートウォッチに設定したい画像を取り込み、文字盤に表示する時刻や日付などの情報を設定します。スマホに保存されている画像データや、カメラからその場で撮影した画像などを取り込むことができます。 中央に表示されている枠がスマートウォッチの文字盤に設定される範囲になります。拡大・縮小などで位置を調整してみてください。拡大・縮小の他回転(90度単位ですが)や反転もサポートしています。位置が決まったら切り取りをおこなってください。 このアプリでは時刻の表示位置などを細かくカスタマイズできるので、画像に合わせて最適な位置に調整していただけます。 以上の手順で画像データを用意すれば自動的にスマートウォッチに同期されます。 スマートウォッチ側 まずはウォッチフェイスにカスタムフォトウォッチを設定してください。スマートウォッチの文字盤で左右にスワイプするとウォッチフェイスの変更ができると思います。そこからカスタムフォトウォッチを選択してください。 スマホから設定した画像に切り替えるには、設定ページを開いてください。カスタムフォトウォッチをウォッチフェイスに設定した状態で、スマートウォッチの画面を長押しすれば開くと思います。 もしくはウォッチフェイス選択画面でカスタムフォトウォッチの下に歯車アイコンが表示されるので、それを押すと設定画面が開きます。 設定画面を開くとスマホで設定した画像が一覧で表示されます。切り替えたい画像を選んでもらえばスマートウォッチの文字盤が設定した画像に切り替わります。 以前までのバージョンでは、スマホで画像を設定したら自動的にその画像に切り替わっていましたが、Ver2からはスマートウォッチで切り替えるようになりました。 FAQ スマホで作成したデータがスマートウォッチにない 同期メニューを実行していただくことで改善する可能性があります。同期メニューはスマホ側のアプリの右上メニューからアクセスできます。 同期メニューを実行しても反映されない場合、以下の可能性が考えられます。 Google Play開発者サービスのバージョンが古い・インストールされていない スマートウォッチ・もしくはスマホ側のアプリが古い スマホおよびスマートウォッチそれぞれでGoogle Play Storeにアクセスして、アプリの更新がないか確認をお願いします。 削除したはずのデータがスマートウォッチ側に残っている 同じく上記の同期メニューの実行で改善されると思います。 スマートウォッチの画像が真っ暗になる・時刻しか表示されない 以前のバージョンからアップデートを行った場合に発生する場合があります。 基本的にはスマホから同期のメニューを実行していただいた後に、スマートウォッチ側の設定画面(画面長押し、もしくはウォッチフェイス選択画面の歯車アイコンをタップ)を開いて画像を選択していただければ改善されると思います。 設定画面すら開けない場合、一度スマートウォッチ側のカスタムフォトウォッチをアンインストールしていただき、再度インストールし直していただくと改善するかと思います。 サポート窓口 ストアページに記載しているメールアドレスまでご連絡ください。 https://play.google.com/store/apps/details?id=jp.gcreate.product.customphotowatch