Flutter on the WebでFirebase導入して詰まった

状況

Flutter WebはFirebaseを導入する際、モバイルとは違いJavaScriptを読み込んで使う。そのためindex.htmlに\<script>を仕込むのだが、異変が起きた。

Launching lib\main.dart on Chrome in debug mode...
Building application for the web...
Attempting to connect to browser instance..

flutter runをしてもここから一切動かないのだ。ググったらimportを消せとか色々策があったが効果はなかった。

解決

A . main.dart.jsを読み込んだ後にFirebaseの設定をしようとしていませんか?

はい。

<body>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.8.1/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.8.1/firebase-analytics.js"></script>

<script>
  // Your web app's Firebase configuration
  var firebaseConfig = {
      //略
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  firebase.analytics();
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>

とするのが正解です。

真理

f:id:Nageler:20200208204731p:plain

終わりに

公式の文章はちゃんと読もうね!

下からひょこっと出てくるボタンを作る(Android/Kotlin)

やりたいこと

画面を開いたら下からひょこっとボタンが出てくる

ボタンを下にフリックすると引っ込む

できたもの

よい

前提として

これは

nageler.hatenablog.com

の応用例です。実装の際はこちらも一読すると良いと思います

作ってみる

環境はAndroidStudio+Kotlinです。

ボタンを用意する

画面外下から出したいのでConstraintLayoutを使って下に配置します。

Top_ToBottomOfで画面外配置できるのかなり便利

ボタンを出す

これが本題かな?(そうでもない)

アニメーションには前回も使ったSpringAnimationを使います。

developer.android.com

説明は前の分を見てください。

遅延を付けて出す

画面を出してから少し遅延を付けて出したいので、Kotlinの非同期処理としてCoroutineを利用します。

dependencies {
    //略

    //Physical Based Animation
    implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'

    //Coroutine
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
}

GlobalScopeでCoroutineを立て、1秒delayしてからアニメーションを実行するよう設定します。animation.start()はバックグラウンドスレッドで呼び出すと怒られるのでwithContextでスレッドを変えましょう。

出す長さの計算としてviewHeightとmarginを使っています。

val buttonMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f+16f, resources.displayMetrics)

この一文ですが、SpringAnimationはPixel単位で動かすのでこう書くとDPから変換してくれるらしいです(やらないと端末ごとに移動距離が歪になる)。

引っ込める

利便性のため引っ込める関数も作っておきます。こちらは呼び出されたらすぐ実行するだけなのでCoroutineなしで書きます。

ぐにぐに動かす

前の記事のとおりです。今回は上方向に動いてほしくないので上に指が動いたときのみ制限をかけるようにします。

originAnimationは外部からアクセスしたいのでActivity内に宣言しました。

下へのフリックで引っ込むようにする

フリックの検知にはGestureDetector.SimpleOnGestureListenerを使います。

developer.android.com

class MainActivity : AppCompatActivity() {

    private lateinit var buttonGestureDetector: GestureDetector

    //略
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonGestureListener = object: GestureDetector.SimpleOnGestureListener() {
            override fun onFling(
                e1: MotionEvent?,
                e2: MotionEvent?,
                velocityX: Float,
                velocityY: Float
            ): Boolean {
                println("速度: Y=$velocityY")
                return super.onFling(e1, e2, velocityX, velocityY)
            }
        }

        buttonGestureDetector = GestureDetector(this, buttonGestureListener)

        limitedButton.setOnTouchListener { _, e ->
            //略

            buttonGestureDetector.onTouchEvent(e)
        }

        //略
    }
}

ボタンのフリックした速度が出力されると思います。

適当な速度を超えたら引っ込むようにします。Viewが移動していてもよしなにアニメーションを作ってくれるのがSpringAnimationの素晴らしいところ。

パラメータがいくつかあるのでそれらを調整すれば、それなりの動きになると思います(最初の動画は動きすぎ...)。

最後に

Animationたのしい

出来上がったコードはGitHubにあげてあります(Branch切ってるだけなので見にくい)。

github.com

指で"少し引っ張れる"Animationを付ける(Android/Kotlin)

正式名がよく分からない

Material Designなどではあまり見かけませんが、必要性が出てきたので作ってみました。

何に使うのか

業務にて動きのある/指で動かせるボタンを作る機会があったのですが、動かせる範囲を制限したくこのような動きを考えました。これについては他の記事で話しましょう。

作ってみる

環境はAndroidStudio+Kotlinです。

SpringAnimation

今回、指を離した後に戻る部分のアニメーションにはSpringAnimationを使っています。これはAndroidで使えるAnimationのうちの一つ、「Physical based Animation」の一種で、簡単にバネの動きをViewに対して実装できます。

developer.android.com

app/build.gradleに以下を追加しましょう。

dependencies {
    //略

    implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
}

指に追随させる

指の動きに合わせてViewを動かすには、ViewのonTouchListenerを利用します。

developer.android.com

limitedButton.yに座標(pixel)を書き込むことでボタンを移動できるのですが、ここではtouchGapYとstartRawYを使って制御しています。

ボタンのY座標には"親の"Viewの左上からの座標を指定しなければならないのに対しe.rawYで取得できるのは"画面の"左上からの座標です。この分のズレを吸収するためにViewが押された瞬間に2つの差分を取ってtouchGapYに保持します。そして動いたときにはtouchGapYを引いてあげればちょうど良くなるということです。

MotionEvent.ACTION_DOWN -> {
      touchGapY = e.rawY - limitedButton.y
      startRawY = e.rawY
}

MotionEvent.ACTION_MOVE -> {
     limitedButton.y = e.rawY - touchGapY
}

動きの限界を設定する

本題です。限界を設定するにしても動きがスムーズでなければ不自然になってしまいます。そこで私はarctanを使って滑らかさを作りました。なにかの値に収束する関数であればなんでもいいと思います。

2/πに収束するのだと不便なので正規化してこのような関数を用意しましょう。

適当に動かした分(startY-rawY)に応じた量(α)でボタンが動くようにします。

これでlimitを超えない範囲でいい感じに動いてくれるようになります。実際に動かしながらvariationの値などを変えるとよいです。

離したら戻るようにする

ここまでだとただ単に動きの悪いDraggableButtonです。先のSpringAnimationを付けてみましょう。

次の関数を用意します。

まずSpringAnimationの引数で対象と終点を設定します。終点の種類には以下のようなものがあります。

DynamicAnimation. 説明
ALPHA 透明度を設定
TRANSLATION_(X|Y|Z) 現在座標からの移動距離(px)を指定
(X|Y|Z) 画面の左上からの絶対位置を指定
SCALE_(X|Y) 拡大縮小を設定

次にAnimationの物理的な特性である剛性(spring.sfiffness)と減衰率(spring.dampingRatio)を指定します。

  • 剛性を上げる -> 勢いが強くなる
  • 減衰率を下げる -> 終点に達するまでの揺れが多くなる

公式が詳しいので目を通すのがよいです。

指を離したときに関数を呼ぶようにすれば完成です!

MotionEvent.ACTION_UP -> {
    goBack2MyRoots(startRawY - touchGapY)
}

ついでにX座標にも動かせるようにしたのが以下のコードです。冒頭のGIFもこれですね。

参考

android.jlelse.eu

出来上がったコードはGitHubにあげています。

github.com

Flutter Web で最速Modern Web App公開

Flutter Webが本体に帰ってきた

Flutterは今までAndroid, iOSに両対応したMobile Appが作れるフレームワークとしていましたが、Flutter1.9から別に開発されてきていた「Flutter for Web(Hummingbird)」が統合され、晴れてFlutter Webとなりました!

これでAndroid, iOSと同列でWebアプリにも同一コードで対応できるようになったわけです。(まだテクニカルプレビューなので注意)

早速やっていく

まずはflutter 1.9以上が必要なのでアップデートしましょう。

(私の環境が変なのはあしからず)

>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel master, v1.12.5-pre.21, on Microsoft Windows [Version 10.0.18362.476], locale ja-JP)

[√] Android toolchain - develop for Android devices (Android SDK version 29.0.1)
[√] Chrome - develop for the web
[√] Android Studio (version 3.5)
[√] VS Code (version 1.40.2)
[√] Connected device (2 available)

• No issues found!

そうしたら File > New > New Flutter Project... から新しいプロジェクトを作ります。

f:id:Nageler:20191129172120p:plain
new flutter project

BMIを計算するアプリを作ります

f:id:Nageler:20191129172636p:plain:h500

Projectが作成されると、ディレクトリにWebが追加されているのが分かると思います。

f:id:Nageler:20191129172852p:plain:w300

適当にコードを変更して、Chromeからデバッグしてみましょう。

コマンドラインから、

>flutter run -d chrome

でできます。

f:id:Nageler:20191129175134p:plain:h500

できました。ここまでWeb向けのコードは一切書く/書き換えていません。HotReloadも使えます。

公開してみる

Flutter WebはコードをJSにトランスパイルしてWebページの作成を実現しています。要は静的ページです。と、いうことは、

GitHub Pagesで無料で公開できる!

というわけです。やっていきましょう。

>flutter build web

でトランスパイルします。すると build > web にファイルが生成されます。

f:id:Nageler:20191129175807p:plain:h500

そうしたらGitHubで適当にRepositoryを作り、Webの階層からpushしましょう(rebuildしたら消えるので別に移動した方が良い)。

f:id:Nageler:20191129180241p:plain:h500

Pushが完了したら、GitHubのページに行き、Settings > GitHub Pages でmasterブランチを選びます。

f:id:Nageler:20191129180500p:plain:h500

1分も待てば公開されます。当然独自ドメインも使えますよ。

https://organic-nailer.github.io/calc_bmi_web_app/

今回作ったのがこれです。記事書きながらでも1時間かかりませんでした。

...わかりますかこの速度感!!これはやばいですよ(アプリ開発者の感想)

まとめ

いかがでしたか?

まだテクニカルプレビューですが触る限り大きなバグは見られず、試用程度なら十分に使えると思いました。Stableになるのが非常に楽しみです。

ちなみにFlutter Webでいくつかアプリを作っているので、よければ遊んでみてください

この2つは1日で作成

動物将棋 https://doubutsu.fastriver.dev/#/

ルーレット https://roulette.fastriver.dev/#/

Android版から移植

クラタン https://clatan.fastriver.dev/#/

今回作ったアプリのコードはGitHubに転がしておきます。参考にどうぞ

github.com

Huaweiのスマホのテーマを自作する

Huaweiこそ至高

EMUIの魅力の一つとして、テーマ(見た目)を自由に変えられるということがあります。Huaweiのテーマストアなり、Playストアなりでテーマを手に入れて適用することで、通知バーやロック画面、ランチャーなどを変更することができます。

悩み

割と有料のテーマが多い。

自分にピッタリ合う物が見つからない。

適用すると文字が読めなくなりがち。

ほならね?

ストアで提供されてるものであればSDKが配布されてるはずなので、自分で作れるだろ、と。やっていきましょう。

Toolのインストール

developer.huawei.com

ここから Huawei Theme Tool Suite のzipをダウンロード、インストール。私はWindows Defenderに文句を言われました。

f:id:Nageler:20190818011400j:plain

hwtToolがそれです。

f:id:Nageler:20190818011523p:plain

作成

左の Themes->New で新規作成できます。もしくは.hwtファイルをimportして編集することもできます。

f:id:Nageler:20190818011849p:plain

色々と編集ができる。

ロック画面は結構自由度高めに編集できるよう(触ってない)で、他は色を指定したり画像を指定することでテーマを作れます。手元にHuawei端末があればPCにつないでその場で動かすこともできます。GUIで簡単に作れて素晴らしいですね。

 

...と思いきや

実際には一部分しか作れない

このテーマ、全部一括で変更できそうに思えますが、実はアプリ単位でテーマを設定してます。なので最大でも左に表示されているアプリ(launcher, contacts, messaging)+システムUI(通知バーなど)しか変更できません。私としては設定アプリのテーマを弄りたかったのですができませんでした。

まだ手はある

実はhwtToolで新規作成・importしたテーマは /hwtTool/res 下に配置されています(ex: C:\Program Files (x86)\hwtTool\res)。そこに色を指定したxmlや画像が入っているので、直接弄ることでもテーマを作ることができるのです。というよりもそもそも.hwt自体がただのzip圧縮なのでTool Suiteなんぞ無くともテーマは作れるんですね。

問題

ただ製作するにあたって一つだけ問題があります。ドキュメントが見つからない。

日本語はおろか英語にも多分存在しません(中国語ならある?)。Huawei DeveloperもhwtToolの使い方しか載せていませんでした。

fqdeboer.net

www.xda-developers.com

頑張っている人たちはいるようですが私は解読する気力がないです...

私は諦めました

通知バーのデザイン変えたい!くらいなら好きな色にできるので有用だと思います。

エセダークモード

誰かドキュメントの作成...ないしは発掘お願いします!(他力本願)



Windows Terminal(Preview)でコピー&ペースト

注意

これは2019年8月14日時点の記事です。まだPreview版なのですぐ仕様が変更される可能性があります。

環境:Windows Terminal (Preview) 0.3.2171.0

コピペができない

Windowsコマンドライン(cmd)ではコピペは通常のctrl+c,ctrl+vででき、WSLを実行中などでもctrl+shift+c,ctrl+shift+vで可能なのですが、Windows Terminalは標準でコピペがブロックされています。

なぜ

ctrl+cはWindowsではコピーのコマンドですが、Linux(他でも?)ではSIGINTシグナルを送信してプロセスを終了するという役割を持っています。なのでコマンドが被らないため無効にされていたんですね。

解決法

しかしコピペできないのは不便(面倒)です。と思ったらissueで色々議論されていました。

github.com

結論からすれば v0.3.2142.0 から設定できるようになったみたいです。

github.com

ということで設定していきます。

Windows Terminal→上の「∨」みたいなところ→設定

or Ctrl+,

でprofiles.jsonが開かれます。その中のglobals > keybindingsに以下を追加します。

{
    "globals" : 
    {
        //略
        "keybindings" : 
        [
            //略

            {
                "command" : "copy",
                "keys" :
                [
                    "ctrl+shift+c"
                ]
            },
            {
                "command": "paste",
                "keys": [
                    "ctrl+shift+v"
                ]
            }
        ],
        //略
    },
 //略
}

 keysの部分は好きなショートカットでOKです。これを保存すればコピペができるようになります(再起動必要なし)。

AndroidのScrollViewで一番下までスクロールできない現象

問題

コンテンツを全て表示させる目的でScrollViewを使うことは多いと思います。

しかし

のように書くと

下までスクロールできずCardViewが切れてしまいます。

なんなのか

いろいろ試してみたところ、事象としてはCardViewの上のmarginの分下が切れているように思われます。ScrollViewのスクロール長さの決定にChildのmarginは含まれていない...?

marginを0にすると問題は起こりません

解決策

LinearLayoutで中身をラップする

しっかり下のmarginまで表示されました。

 

後記

ドキュメントを見ると

A view group that allows the view hierarchy placed within it to be scrolled. Scroll view may have only one direct child placed within it. To add multiple views within the scroll view, make the direct child you add a view group, for example LinearLayout, and place additional views within that LinearLayout.

 

developer.android.com

とあるので、childが一つならラップしなくてもいいはずなんですが...

 

SampleはGitHubに上げています。

github.com