20191028のAndroidに関する記事は14件です。

Flutterウィークリー #81

Flutterウィークリーとは?

FlutterファンによるFlutterファンのためのニュースレター
https://flutterweekly.net/

この記事は#81の日本語訳です
https://mailchi.mp/flutterweekly/flutter-weekly-81

※Google翻訳を使って自動翻訳を行っています。翻訳に問題がある箇所を発見しましたら編集リクエストを送っていただければ幸いです。

読み物&チュートリアル

複数の画面とそれらの操作方法

https://blog.codemagic.io/flutter-tutorial-multiple-screens-and-how-to-navigate-them/


Flutterアプリの画面内をナビゲートする方法に関するScott Stollのチュートリアル。

Googleマップを使用したFlutterクラスターマーカー

https://coletiv.com/blog/how-to-cluster-markers-on-google-maps-using-flutter/


AntónioValenteは、マップ内の複数のポイントをクラスター化するのに役立つパッケージであるFlusterの使用方法を示します。

Ultimate JavaScriptとDart構文ガイド

https://flutterigniter.com/ultimate-javascript-dart-syntax-guide/


あなたはJSのバックグラウンドであり、 Dartですか?これは、両方の言語を比較する非常に便利なガイドです。

Flutter Mobile:スクラムポーカーアプリ

https://myracle.hashnode.dev/flutter-mobile-scrum-poker-app-ck1vx6yxl004f3os10qi8u0o2


スクラムポーカーアプリケーションFlutterをゼロから作成する方法に関するMax Weberの素晴らしいチュートリアル。

60 Days of Flutter :メッセンジャーの構築

https://medium.com/@adityadroid/60-days-of-flutter-building-a-messenger-day-60-wrapping-it-up-ae645037610b


Aditya Gurjarは、 Flutter完全なアプリを作成した経験を説明する、この驚くべき26の記事のセットを完成させました。

Flutterスワイプして閉じるを実装するための詳細なダイビング

https://medium.com/flutter-community/an-in-depth-dive-into-implementing-swipe-to-dismiss-in-flutter-41b9007f1e0


Wilberforce Uwadiegwuによる詳細な記事で、リストにスワイプ効果を実装する方法を学びます。

A-My Languageを話せますか?!

https://medium.com/@greg.perry/do-you-speak-a-my-language-587854c2d0a3


グレッグペリーは、さまざまな言語をサポートするアプリを作成するためのすべての手順を詳しく説明します。

Flutter密度グラフを描画する

https://medium.com/flutter-community/drawing-density-charts-in-flutter-7f1c6a14ee1c


Dan Panaiteは、複数の点が散らばったグラフを表示するさまざまな方法を示しています。

国際化? Flutter簡単な翻訳と国際化

https://medium.com/flutter-community/i18n-extension-flutter-b966f4c65df9


Marcelo Glasbergによるこのチュートリアルで、多言語アプリの作成にi18nパッケージを使用する方法を学びます

Flutterパーティクルシステム(パフおよびザップ用)

https://medium.com/flutter-community/particle-systems-for-puffs-and-zaps-with-flutter-d32cdcc97ef3


Ivan Cherepanovによるこのチュートリアルを使用して、UIにクールな輝く効果を追加します

ITテストでの国際化文字列の再利用

https://medium.com/flutter-community/reusing-i18n-strings-for-it-testing-in-flutter-cead2aa5c914


Efthymis Sarmpanisは、テストでローカライズされたリソースが必要な場合の問題の解決策を提案しています。

Dart便利なリストメソッド

https://medium.com/flutter-community/useful-list-methods-in-dart-6e173cac803d


Dart最高のリスト演算子の説明。

ビデオ&メディア

BLoCを使用したFlutterクリーンアーキテクチャの実装

https://skillsmatter.com/skillscasts/14431-flutter-london-october#video


Amr Yousefによるこの講演で、クリーンアーキテクチャアプローチを適用したBLoCの使用方法を学ぶ

Flutter付きの美しいアニメーションアプリバー!

https://www.youtube.com/watch?v=SkkmoT_DZUA&feature=youtu.be


移動するAppBarの作成方法に関するチュートリアル。

DashCastが帰ってきた! (退屈なFlutter開発ショー、Ep。32)

https://www.youtube.com/watch?v=d2gRn6cOEhA&list=PLjxrf2q8roU3ahJVrSgAnPjzkpGmL9Czl&linkId=75812192


RSSの解析やオーディオのストリーミングなど、ポッドキャストアプリの構築に必要なものの例。

DataTable(今週のFlutterウィジェット)

https://www.youtube.com/watch?v=ktTajqbhIcY&list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&index=58&t=0s


テーブルでユーザーに表示する重要なデータはありますか?列、行を定義し、DataTableでセルのサイズを自動的に設定します!

Flutter AutoSizeText(今週のパッケージ)

https://www.youtube.com/watch?v=OHhBa_1mWlQ&feature=youtu.be


AutoSizeTextパッケージを使用して、制約内のテキストのサイズを自動的に変更します。

Flutter Blocライブラリチュートリアル(1.0.0以降)–反応状態管理クラッシュコース

https://www.youtube.com/watch?v=hTExlt1nJZI


最近リリースされたBLoCライブラリ1.0.0のチュートリアル。

ライブラリ&コード

jama5262 / jiffy

https://github.com/jama5262/jiffy

Jiffyは、日付の解析、操作、および書式設定のためにmomentjsに触発されたFlutterおよびdart Web日付時刻パッケージです

Norbert515 / pimp_my_button

https://github.com/Norbert515/pimp_my_button

パーティクルエフェクトをあらゆるものに追加します。

BLoC 1.0.0

https://bloclibrary.dev/#/

バージョン1.0.0を達成したBLoCライブラリの公式Webサイト

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

RecyclerView内のTextViewをSelectableにする方法

AndroidでRecyclerView内のTextViewをSelectableにする方法です。
今更な感じもあると思いますが、あまり情報がなかったので。

僕の場合は複数のFragmentでRecycledViewPoolを共有しているため、Fragmentを切り替えて戻ってきた時に、再度選択ができない状態になっていました。
また、RecyclerViewのAdapterに設定する方法もありますが、Groupieを使っているためCustomViewを作る形をとりました。

SelectableTextView.kt
class SelectableTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) 
    : AppCompatTextView(context, attrs) {

    init {
        // Selectableにする
        setTextIsSelectable(true)
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        // 再度アタッチされた時にSelectableにならないバグの回避
        isEnabled = false
        isEnabled = true
    }
}

参考

http://y-anz-m.blogspot.com/2012/10/androidtextview.html
http://y-anz-m.blogspot.com/2019/06/recyclerview-textview-textisselectable.html

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

AndroidでiOSのDispatchGroupと同じことをしたい。

複数の非同期処理を同時に流して、全部が完了したタイミングで次の処理を開始したいとき、iOSではDispatchGroupを使って手軽にできるが、同じことをAndroidで実現する方法を調べてこれを見つけた↓
元ネタ: Android how to group async tasks together like in iOS

それを微妙に改変した↓

class DispatchGroup {
    private var count = 0
    private var runnable: (() -> Unit)? = null

    init {
        count = 0
    }

    @Synchronized
    fun enter() {
        count++
    }

    @Synchronized
    fun leave() {
        count--
        notifyGroup()
    }

    fun notify(r: () -> Unit) {
        runnable = r
        notifyGroup()
    }

    private fun notifyGroup() {
        if (count <= 0) {
            runnable?.invoke()
        }
    }
}

使うときは

        val dispatchGroup = DispatchGroup()

        dispatchGroup.enter()
        functionA(completion = {
            print("functionAが完了")
            dispatchGroup.leave()
        })

        dispatchGroup.enter()        
        functionB(completion = {
            print("functionBが完了")
            dispatchGroup.leave()
        })

        dispatchGroup.enter()
        functionC(completion = {
            print("functionCが完了")
            dispatchGroup.leave()
        })

        dispatchGroup.notify {
            print("全部の処理が完了")
        }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FlutterでHello worldを動かすまでの環境構築手順(iOS, Android)

FlutterでHello worldを動かす

仕事でFlutterを扱うことになったので、とりあえずHello world動かすところまでの流れをメモ。

「Flutterとは何ぞや?」って人は公式サイトを見てくれ。
Flutter - Beautiful native apps in record time

環境

Flutter SDKは、Windows、macOS、Linux向けに提供されていますが、本記事ではmacOS上での環境構築手順をまとめます。

OS バージョン
macOS Mojave バージョン10.14.6

Flutter SDKは「v1.9.1+hotfix.4」を使いました。
※バージョンアップ等で本記事の情報が古くなっている場合は、公式ドキュメントを参照してください

Flutter SDKのインストール

まずはFlutter SDKをインストールします。
macOS install - Flutter

Flutter SDKのダウンロード

公式サイトから最新版SDKのzipファイルをダウンロードします。
本記事執筆時点のSDKバージョンは、v1.9.1+hotfix.6となっていました。
スクリーンショット 2019-10-28 14.17.15.png

インストール対象フォルダに移動し、ダウンロードしたzipファイルを解凍します。

$ cd ~/development
$ unzip ~/Downloads/flutter_macos_v1.9.1+hotfix.6-stable.zip

パスを通す

SDKを展開しただけではflutterコマンドが使えないので、パスを通します。

$ export PATH="$PATH:`pwd`/flutter/bin"

.bash_profileに直接追記してもOKです。

export PATH="/Users/unsoluble_sugar/flutter/bin:$PATH"

開発用バイナリをダウンロード

必要に応じてプラットフォーム固有の開発バイナリをダウンロードします。

$ flutter precache

flutter doctorを実行する

セットアップ完了のために別途インストールが必要なツールがないか、依存関係をチェックします。

$ flutter doctor

flutter doctorコマンドを実行すると以下のようなログが表示されます。flutterコマンドが使用できない場合は、前述のパスが通っていないケースが多いです。

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.9.1+hotfix.4, on Mac OS X 10.14.6 18G103, locale ja-JP)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[!] Xcode - develop for iOS and macOS (Xcode 11.1)
    ✗ CocoaPods installed but not initialized.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that
        responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To initialize CocoaPods, run:
        pod setup
      once to finalize CocoaPods' installation.
[✓] Android Studio (version 3.5)
[!] Connected device
    ! No devices available

! Doctor found issues in 2 categories.

[!] の付いている項目は準備が完了していない項目です。

Android、Xcode関連はのちほど設定するので無視してください。Connected device もデバッグ時に使用するものなので、いまは気にせず大丈夫です。

[✓] Flutter となっていない場合は、Flutterの設定まわりに何かしら問題が起きている状態です。表示されているメッセージを参照しながら対応しましょう。

基本的には指示通りに不足ツールをインストールしていけば解決します。

バージョン確認

flutter doctorでもflutterのバージョン確認はできますが、flutter --versionコマンドを打つと、使用されているDartのバージョンなども確認できます。

$ flutter --version
Flutter 1.9.1+hotfix.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision cc949a8e8b (4 weeks ago) • 2019-09-27 15:04:59 -0700
Engine • revision b863200c37
Tools • Dart 2.5.0

これでflutter SDKの設定は完了です。

iOSのセットアップ

続いてiOSのセットアップを行なっていきます。

Xcodeをインストールする

Xcodeの最新安定版をインストールします。公式Webサイト、もしくはMac App Storeからダウンロードします。
スクリーンショット 2019-10-28 14.56.01.png

コマンドラインツールの設定

Xcode command-line toolsの設定をします。

$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
$ sudo xcodebuild -runFirstLaunch

一度もXcodeを起動していない場合の初期セットアップや、ライセンスの同意など、必要に応じて進めましょう。

iOSシミュレーターの実行

以下コマンドでiOSシミュレーターを起動します。

$ open -a Simulator

スクリーンショット 2019-10-28 15.08.42.png

Xcode上から [Xcode] > [Open Developer Tool] > [Simulator] で起動することもできます。
スクリーンショット 2019-10-28 15.07.20.png

サンプルアプリの作成

flutter createコマンドで新規プロジェクトを作成します。

$ flutter create my_app

シミュレーターを起動した状態でflutter doctorコマンドを打つと、Connected device項目が[✓]となっていることがわかります。

[✓] Connected device (1 available)

作成したプロジェクトフォルダに移動し、flutter runコマンドを実行しましょう。

$ cd my_app
$ flutter run

起動中のシミュレーター上でアプリが実行されます。

スクリーンショット 2019-10-28 15.11.24.png

右下の「+」ボタンをタップすると、画面中央の数字がカウントアップされるHello worldアプリらしい。

起動確認ができたらiOSのセットアップは完了です。

Androidのセットアップ

iOSの動作確認ができたので、Androidのセットアップも行なっていきます。

Android Studioのインストール

Android Studioをダウンロードしてインストールします。
スクリーンショット 2019-10-28 15.22.19.png

Android SDK等のインストール

Android Studio Setup Wizardに従って、最新のAndroid SDK、Android SDK Platform-Tools、Android SDK Build-Toolsをインストールします。

Android Emulatorを作成

Android Studioを起動し、Welcome画面右下にある [Configure] メニューから [AVD Manager]を開きます。
スクリーンショット 2019-10-28 15.24.05.png

適当にEmulatorを作成し、対象EmulatorのPlayボタンを押します。
スクリーンショット 2019-10-28 15.26.16.png

Emulatorが起動します。
スクリーンショット 2019-10-28 15.28.04.png

Emulatorが起動した状態でflutter runコマンドを実行すると、サンプルアプリが起動します。
スクリーンショット 2019-10-28 15.34.01.png

簡単ですね。

iOS、Androidで同時に動作確認する

おまけ。

iOS Simulator、およびAndroid Emulatorを同時に起動した状態で以下コマンドを打ってみましょう。

$ flutter run -d all

複数OSでアプリ挙動を同時確認することが可能です。
スクリーンショット 2019-10-28 15.32.34.png

すごい。

エディタはVSCodeがおすすめ

ちなみにエディタはVSCodeを使っています。
flutter_hot_reload.gif

とりあえずFlutterとDartのプラグイン入れとけば、必要最低限の環境は整います。

VSCode上から新規プロジェクトの作成、エミュレーターの起動、デバッグまでひと通りこなせます。
スクリーンショット 2019-10-28 15.43.06.png
FlutterにはHot reload機能もあるため、変更の確認が容易で高速開発が可能。
Hot reload - Flutter

すごい。

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

画像名を文字列で指定してImageViewに貼り付けるコード(android)

swiftだと画像名で画像を指定して貼り付けられるのですが、そういえばandroidではなかったなと(あるんですかね)

見つからなかった、というか大して探してないのですが何となく作りました。

手順は
①画像名からリソースIDを取得
②リソースIDを使って画像をセット
これだけです。

Util.java
public void setBackgroundResourceByString(Context context, String imgName, View view){
    int resourceId = context.getResources().getIdentifier(imgName, "drawable", context.getPackageName());
    view.setBackgroundResource(resourceId);
}

第一引数にgetContext()などで得たcontextを代入、
第二引数はdrawableに入れられた画像名をストリング型で代入、
第三引数はその画像を貼り付けたimageViewやViewを代入してください
※Viewを継承したクラスなら使えます

ちょっと気持ちが悪いので

Util.java
public int getResourceIdByString(Context context, String imgName){
    return context.getResources().getIdentifier(imgName, "drawable", context.getPackageName());
}

このくらいのメソッドが無難かもですね

ちなみに多分ですが、drawableはcolorやstringとして登録されている色や文字のリソースIDを取得することもできるかと

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

[ TomCat ] [ Android ] サーバクライアント通信4 ランダムな整数を返す

今回はサーバ(TomCat)からランダムな整数を取得する方法について記す。
TomCatのインストールとサンプル表示は
[インストール]
https://eng-entrance.com/java-servlet-tomcat-install
[サンプル表示]
https://searchman.info/java_eclipse/1040.html
を参考にして頂きたい。

上記のサンプル表示ができている前提で話を進める。

Random

サーバ側のプログラムはjavaで書かれている。
javaでは乱数を扱うためにRandomクラスを用いる。
まずRandomクラスをインポートする。

    import java.util.Random;

乱数を扱うためには以下のように書く。

    Random random = new Random();
    int randomNumber = random.nextInt(9);

このようにしてrandomNumberは0以上9未満の乱数を受け取ることができる。

さらに以下のようにコードを追加し、
これをクライアントに取得させる。

    PrintWriter out = response.getWriter();
    out.println(RandomNumber);
    out.close();

クライアントがサーバからHTTP通信により値を取得する方法は
前回の記事
https://qiita.com/QiitaD/items/79228417a68c51090a4e
を参考にして頂きたい。

サンプルコード

以下がサンプルコードである。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Random;

 public class HelloWorld extends HttpServlet {
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
                          throws IOException, ServletException {

    Random random = new Random();
    int randomNumber = random.nextInt(9);


    PrintWriter out = response.getWriter();
    out.println(RandomNumber);
    out.close();
    }
}

まとめ

サーバクライアント通信の当初の目的であった
「サーバから乱数を取得するプログラム」を完成させることができた。
4回に渡って綴ってきたので、
興味のある方はぜひ参考にして頂きたい。
以上。

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

AndroidViewの表示・非表示を切り替えるView.INVISIBLEとView.GONEの違い

Viewの表示・非表示を切り替える方法

Viewの表示・非表示を切り替えるには、view#setVisibility(int visibility)メソッドを使用します。
visibility引数には可視状態を表す定数を指定します。

TextView exampleView = (TextView) findViewById(R.id.example_view);
exampleView.setVisibility(View.INVISIBLE);

上記のように書くことができます。

INVISIBLEとGONEの違い

  • View.INVISIBLE
    非表示にする。非表示にした領域は詰めない。viewが見えないだけで、領域は占める。
  • View.GONE
    非表示にする。 非表示にした領域を詰める。 viewがそもそもなかったように振舞う。

※初期値はView.VISIBLE(表示する)に設定されている。

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

NativeScriptを用いたVue.jsモバイルアプリ開発の環境構築

概要

NativeScriptを用いてVue.jsモバイルアプリを作る際の環境構築の手順をまとめました.

  • NativeScript・・・本物のモバイルネイティブアプリをJavaScriptで開発するためのオープンソースフレームワーク
  • NativeScript-Vue・・・Vue.jsを使ってモバイルアプリを作成するためのNativeScriptのプラグイン

環境

  • Mac OS X 10.14.6
  • Node.js v12.12.0
  • NativeScript 6.1.2
  • NativeScript-Vue 2.4.0

手順

NativeScriptのシステム要件のセットアップする

下記ページに従い,macOSでNativeScriptアプリをビルドして実行するために必要なすべてのシステム要件をセットアップします.
最後の手順でtns doctorコマンドを実行して問題が検出されなければ次のページに進む前に本記事に戻り,次の手順に進んでください.

NativeScript Advanced Setup — macOS - Native
Script Docs

「結局英語で書かれた公式ドキュメントかよ,読むの面倒だからQiita記事探してるんだよ」と思った方もいるかもしれません.しかし私の経験上,今回のような導入手順や環境構築に関しては最初から公式サイトを読みにいくのが最も時間を無駄にせずに済みます.

また,Androidエミュレータ(AVD)のセットアップ手順において,いくつか選択肢が示されていますが,もしAndroid Studioを使う場合は,以下の手順で日本語化できます.

MacでAndroid Studioを日本語化する - ソフラボの技術ブログ

NativeScript-Vueをインストールし開発を開始する

下記ページに従い,NativeScript-Vueのインストール,プロジェクト作成,ビルドを行います.幸いこちらは日本語ですね.

クイックスタート - NativeScript-Vue

tns run android --bundleコマンドでAVDが立ち上がれば成功です.
ちなみにこれはPixel 2のAVDを使用した場合です.

スクリーンショット 2019-10-22 15.41.21.png

動作確認

app/components/App.vueにmsg: "Hello!"と書かれた箇所があるので,それを編集してみてください.

スクリーンショット 2019-10-28 10.20.30.png

画面に表示されているメッセージが自動で変わると思います.以上で環境構築は終わりです.

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

よく使うadbコマンドメモ

はじめに

タイトル通り、私がよく使うadbコマンドをメモしておきます。

使用ツール

  • コマンドプロンプトまたはAndroid Studio
  • お好きなAndroid端末
  • Android端末とPCをつなぐケーブル

よく使うadbコマンド

PCとAndroid端末をケーブルでつないで、
コマンドプロンプトまたはAndroid Studioで実行してみましょう。
Android Studioは下方でBuildとかLogcatが表示されるところにTerminalタブがあり、
そこで実行できます。

adbから画面の設定を出す

adb shell am start -a android.settings.DISPLAY_SETTINGS

アプリのパスを探す

adb shell pm list packages -f | findstr アプリに含まれる文字列

アプリのアンインストール

adb uninstall アプリのパス

PCとAndroid端末間のファイルのやり取り

Android→PCへファイルを送る

adb pull /sdcard/Download/ファイル名.txt .\

PC→Androidへファイルを送る

adb push ファイル名.txt /sdcard/Download/

logcatをPCに保存する

logcatを保存するファイル名の拡張子は.txtとか好きなのでよいみたいです。

adb logcat > ファイル名.log
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最小構成のreact-nativeをとりあえず動かす 

まずはreact-nativeを最小構成で動かすまでをメモ

$ npm i -g react-native-cli
$ react-native init hello # helloはプロジェクト名
. . . 
Done in 33.80s.

  Run instructions for iOS:
    • cd /home/oreore/dev/test/hello && react-native run-ios
    - or -
    • Open hello/ios/hello.xcodeproj in Xcode or run "xed -b ios"
    • Hit the Run button

  Run instructions for Android:
    • Have an Android emulator running (quickest way to get started), or a device connected.
    • cd /home/oreore/dev/test/hello && react-native run-android

react-native run-androidを実行しろとのこと

$ react-native run-android
. . .
ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation.

JAVA_HOMEとjavaコマンドがないらしい。AndroidStudioインストール時にopenjdkが入っていたはずなので、せっかくなのでそれを利用する。
javaのpathはAndroidStudioの、File > Project Structureから確認可能。

コメント 2019-10-28 110614.png

パスとか入れる。

$ vim .bashrc

JAVA_HOME=/usr/local/android-studio/jre
export PATH="$PATH:/usr/local/android-studio/jre/bin"

$ source .bashrc

java確認

$ java -version
openjdk version "1.8.0_202-release"

いい感じなので、再度run-android実行

$ react-native run-android
. . .
error Failed to launch emulator. Reason: No emulators found as an output of `emulator -list-avds`.


FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':app'.
> SDK location not found. Define location with an ANDROID_SDK_ROOT environment variable or by setting the sdk.dir path in your project's local properties file at '/home/oreore/dev/test/hi/android/local.properties'.

ANDROID_SDK_ROOTを入れてる

$ vim .bashrc

export ANDROID_SDK_ROOT=/home/oreore/Android/Sdk

$ source .bashrc

run-android再実行

$ react-native run-android
. . .
BUILD SUCCESSFUL in 33s
28 actionable tasks: 28 executed
info Connecting to the development server..

成功してエミュレーターが立ち上がった。

コメント 2019-10-28 122630.png

画面は黒いが初期状態なのでこれで成功しているはず。次はreduxとか入れてhello worldしよう。

追記:
黒い画面は正しく起動できていなかった。
理由は不明だがandroid/app/src/main/assetsディレクトリがなく、indexファイル的なのもなかった。ので、作成する

$ mkdir android/app/src/main/assets
$ react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res 
$ react-native start

welcome画面きた!
image.png

メモ:
error SHA-1 for filenpm i -g react-native-cliで直った

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

AndroidのWebView復帰処理について

Android WebView を利用したときの、復帰処理まとめ

  • アプリ内でブラウザを表示する際に利用するWebViewコンポーネントを利用した際の、画面復帰処理まとめです。

WebViewの復帰をさせよう

状態の保持をするときは

  • WebViewには、表示状態を保持するためのsaveStateが用意されているので、これを使って復帰処理をします。
  • 使用しているActivityFragmentonSaveInstanceStateの引数を利用してデータの保持を行います。
WebviewFragmentSample.kt
override fun onSaveInstanceState(outState: Bundle) {
        webView?.saveState(outState)
        super.onSaveInstanceState(outState)
    }

状態の復帰をするときは

  • ActivityであればonCreateFragmentであればonCreateViewの引数savedInstanceState :Bundle?を利用しましょう。
  • このsavedInstanceStateにすでに保持されたデータがあれば何らかのデータが引き渡されます。(なにもデータがなければnullです)
  • savedInstanceStateWebViewrestoreStateに渡してあげることで復帰処理が行われます。
注意点
  • WebViewloadUrl処理は同期処理では無いです。なので復帰したからといってURLが引き継がれているという保証が無いことに注意しましょう
  • コードはこのあたりから見れます。
  • urlのデータをHandlerMessageを利用して、WebViewCoreに送信して処理を実施しているので、必ずしも同期的に処理が完了する保証がなさそうです。
    • なので、restoreState後に正しくURLが入っているかを確認し、入っていなければ再度セットするようにしておくのが良いと思います。
WebviewFragmentSample.kt
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    if (savedInstanceState != null) {
        webView?.restoreState(savedInstanceState)
    }
    if (webView?.url == null) {
        webView?.loadUrl(url)
    }
    ・・・省略・・・
}

最後に

  • 対応を見逃しそうなonSaveInstanceStateの話でした、画面の復帰処理は忘れがちな部分だったりしますので、しっかり入れておきましょうって話でした

これからも、良いアプリ開発を目指して:dancers:

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

少ない開発リソースでAndroidアプリをダークモードに対応した話

初めに

現在、開発しているArtStickerというアプリで、ダークモードの対応をしました。
リリースまでの流れや、技術的な事などを共有したいと思います。

チームの開発状況

まず現在のチーム状況です。

  • Androidエンジニア: 1名
  • デザイナー: 1名

リソースは少ないけど、やりたいことはたくさんあるので、ダークモードの優先度は低い。
でも、勉強を兼ねてダークモードに対応したいという状況でした。
ということで、デザイナーさんのできる限り負担をかけずに、ダークモードに対応しようと考えました。

工数を減らすために

デザインの管理は基本的にSketchで行っています。通常の機能開発では、デザイナーさんにSketch上でデザインを作ってもらってから開発を進めていますが、今回はできる限りその作業を削りました。

リリースまでの流れ

以下のような流れで進めました。

Step 1. 最低限必要な実装をしてゴールまでの距離を確認
Step 2. デザイナーさんとDark Themeの勉強会を開く
Step 3. Step 2ですり合わせたイメージを元に実装をすすめる
Step 4. デザインチェック
Step 5. リリース

Step 1. 最低限必要な実装をして、ゴールまでの距離を確認

まずは、ダークモードの対応の全体感を掴むために、シンプルな設定を入れます。

  • NotNight/Night Modeを切り替えられる DayNight のThemeをActivityに設定
style.xml
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
  • Debugビルドのときのみ、OSのTheme設定に従うようにApplicationクラスで設定
MyApplication.kt
override fun onCreate() {
    super.onCreate()
    AppCompatDelegate.setDefaultNightMode(
        if (BuildConfig.DEBUG) {
            AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
        } else AppCompatDelegate.MODE_NIGHT_NO
    )
}
  • night用の最低限のリソースファイルを作り、最低限の設定を追加
/values/colors.xml
  <color name="colorPrimary">@color/white</color>
  <color name="colorPrimaryDark">@color/black</color>
  <color name="colorAccent">@color/black</color>
/values-night/colors.xml
  <color name="colorPrimary">@color/black</color>
  <color name="colorPrimaryDark">@color/white</color>
  <color name="colorAccent">@color/gray_cccccc</color>
  • 動作確認をする
    • Android 10の端末やエミュレーターで、ダークモードの設定を変え、動作を確認します

Step 2. デザイナーさんとDark Themeの勉強会を開く

  • Material DesignのDark Themeの読み合わせをする
    • 今回は日本語に翻訳をかけて、段落毎に順番に読み、議論しながらすすめました
  • Material DesignのDark Themeのレイヤーの考え方を理解することがポイントです
    • Light ThemeとDark Themeでelevationの考え方を統一します
    • ベースカラーを決め、その上に白をベースに以下の透明度を設定したレイヤーを重ね、各dp毎の色を作成します
    • Material DesignのDefault Elevationから各コンポーネントの色を決定します


ベースカラーと白のレイヤーのイメージ


レイヤー毎の色のイメージ

  • 開発中のアプリだったらという前提でレイヤーや使用する色の意識合わせをする
    • 自然とそういう流れになると思いますが議論します
  • 他のアプリのダークモードをいくつか見てみる
    • ダークモードに対応したアプリが増えてきているので、ゴールを共有します
  • ダークモードが増えた場合の運用負荷について議論する
    • デザインの管理を今後どうするか共有します

Step 3. すり合わせたイメージを元に実装をする

最低限の色の定義を行う

  • ベースカラーと各レイヤー毎の色を仮置で定義します
/values/colors.xml
    <color name="black_00dp">#0f0f0f</color>
    <color name="black_01dp">#1a1a1a</color>
    <color name="black_02dp">#1c1c1c</color>
    <color name="black_03dp">#1e1e1e</color>
    <color name="black_04dp">#202020</color>
    <color name="black_05dp">#222222</color>
    <color name="black_06dp">#242424</color>
    <color name="black_08dp">#282828</color>
    <color name="black_12dp">#2f2f2f</color>
    <color name="black_16dp">#383838</color>
    <color name="black_24dp">#484848</color>
  • テキストカラーをLightなアプリのルールに従って定義します
/values-night/colors.xml
    <color name="textColor">@color/white</color>
    <color name="textColorPrimary">@color/white</color>
    <color name="textColorSecondary">@color/gray</color>
  • 各コンポーネントの色を定義します
/values-night/colors.xml
    <color name="colorBorder">@color/black_01dp</color>
    <color name="colorSurface">@color/black_02dp</color>
    <color name="colorCardLayout">@color/black_03dp</color>
    <color name="colorAppBarLayout">@color/black_04dp</color>
    <color name="colorTabLayout">@color/black_04dp</color>
    <color name="colorBottomNavigationView">@color/black_08dp</color>
    <color name="colorDialog">@color/black_24dp</color>

Viewに設定していく

  • 使用する色の方針が決まったら、Viewに設定します
  • 共通のコンポーネント毎に、styleにまとめながら実装すると、きれいに書くことができます
  • 既存のLightモードの実装がいまいちな場合はリファクタリングしながら設定します
values/styles.xml
    <style name="App.Widget.AppBarLayout" parent="Widget.Design.AppBarLayout" >
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@color/colorAppBarLayout</item>
    </style>
fragment_home.xml
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        style="@style/App.Widget.AppBarLayout">

Vector Drawableの対応方法

  • Context Menuに設定したVector Drawableは以下のように android:tint="?attr/colorControlNormal"vector tagに設定するとNightModeの設定に従って色が変更されます
  • この時、設定したThemeの android:textColorSecondary に従って色が決定します
ic_like_off_black.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="11dp"
    android:height="10dp"
    android:viewportWidth="11"
    android:viewportHeight="10"
    android:tint="?attr/colorControlNormal">
    <!--  省略 -->
</vector>

pngやwebp画像の対応方法

  • 自動で設定することはできないため、 drawable-night 配下に同じファイル名でリソースを置きます

設定画面に、切り替えメニューを作る

今回は設定画面にメニューを追加し、Dialogを表示してモードを切り替えられるようにしました。

  • 変更後の実装
SettingsFragment.kt
class SettingsFragment : Fragment(), NightModeDelegate {

    fun showChangeNightModeDialog() {
        ChangeNightModeDialogFragment.instance(nightMode).also {
            it.onClickNightMode = { selectedNightMode ->
                val shouldUpdateState = nightMode != selectedNightMode
                if (shouldUpdateState) {
                    // SharedPreferencesに設定を保存
                    actionCreator.selectNightMode(selectedNightMode)
                    // NightModeを変更
                    updateNightMode(selectedNightMode)
                    // Activityを再生成
                    navigator.navigateToMainWithClearTop(activity)
                }
            }
            it.show(childFragmentManager, ChangeNightModeDialogFragment::class.java.simpleName)
        }
    }
  • 変更処理詳細
NightModeDelegate.kt
interface NightModeDelegate {

    fun updateNightMode(nightMode: NightModeType) {
        AppCompatDelegate.setDefaultNightMode(
            when (nightMode) {
                NightModeType.NotNight -> AppCompatDelegate.MODE_NIGHT_NO
                NightModeType.Night -> AppCompatDelegate.MODE_NIGHT_YES
                NightModeType.FollowDeviceTheme -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
            }
        )
    }
}
  • アプリ起動時の設定
MyApplication.kt
class ArtStickerApplication : Application, NightModeDelegate {

  override fun onCreate() {
      super.onCreate()
      updateNightMode(currentNightMode)
  }
}

今回は、Night Modeをオフ(NotNight)の状態を初期値としました。

オーバードローのチェック

  • オーバードローが少なくなるように実装します
    • ダークモードに限った話ではないですが、開発者向けオプションの「GPUオーバードローをデバッグ」をONにして、無駄なオーバードローが発生していないか確認します

デザイナーさんに共有する

  • 数画面作り、デザイナーさんに共有し、調整します
  • ダークモードにした時に別のリソースにする必要のある画像を洗い出し、必要に応じて作成を依頼します
  • 概ね良さそうであれば最後まで実装します

Step 4. デザインチェック

  • 最後に、デザイナさんに一通りチェックしてもらいます
    • Step 3で作成した色の設定を共有し調整してもらいます
      • 色の設定が変わってもViewのレイヤー構造が変わらなければ、大きな変更はせずに済みます
    • 画面毎に、フィードバックをもらいます
    • 修正したら、再度確認してもらい精度を上げていきます

Step 5. リリース

  • 各AndroidのVersionでテストをして、リリースします

最後に

  • 少ないリソースのなかで、Android版のダークモードに対応することができました
  • デザインの管理をコンポーネント毎の色の管理に留めることで、デザイナーさんの負荷を下げることができました
  • Material Designに従い、共通のコンポーネントの色を統一し、共通のView毎にstyleを定義することで、開発の時間や、テストの負荷を下げることができました
  • 実績として、Step 1 〜 Step 4までで、片手間で作業をして2週間程度で完了しました (アプリやチームによって、作業量が変わるため、あまり参考にならないかもしれません)
  • すすめ方によっては、チームのメンバーに迷惑をかけることもあると思うので、コミュニケーションは十分にとることが大事だと感じました
  • 社内のメンバーにダークモードをプレビューしたところ、反応がよく実装してよかったと感じています
  • 参考までに、ArtStickerを是非使ってみてください(現在はAndroid版のみダークモードに対応しています)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PreferenceManagerが@Deprecatedで困った話

AndroidStudioで何も考えずにPreferenceManagerを使っていると以下のようなアラートが発生してちょっと困りました。

スクリーンショット 2019-10-28 8.09.53.png

APIレベル29で廃止されたからあんまり使わないでねってことらしいです。
そのうち使えなくなるよーとのこと。
まあ、当分は使えるみたいですけど。
AndroidX Preference Library を使えとのことです。
以下、AndroidX Preference Libraryの使いかた。

build.gradleに追加

build.gradle(appの方)のdependenciesに
implementation 'androidx.preference:preference:1.0.0'を追加すればOK。

build.gradle
dependencies {
    implementation 'androidx.preference:preference:1.0.0'
}

変更したら、忘れずにSyncしましょう!!

import先の変更

import android.preference.PreferenceManagerに
ただ「x」を追加するだけ。以上。

○○○.kt
- import android.preference.PreferenceManager
+ import androidx.preference.PreferenceManager

参考:
https://maku77.github.io/android/fw/preference-fw.html

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

androidxでswiperefreshlayoutを使う。

最新の環境でswiperefreshlayoutを使うためのメモ。
gradleに↓を追加。
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
使い方は他の記事を参考にしてください。

(古い情報だとandroid.support.v4.widget.SwipeRefreshLayoutを使ったやり方しか見つからなかった。。。)
古いライブラリを使う場合は、migrationを参考にしよう。
https://developer.android.com/jetpack/androidx/migrate
https://github.com/firebase/firebase-android-sdk/issues/742

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