20200523のAndroidに関する記事は5件です。

【Flutter】flutter_native_splashを使ったときに、Androidでスプラッシュ画面からアプリ画面に遷移する際、画面が真っ黒になる件の対応

経緯

こちらを参考にFlutterにスプラッシュ画面を導入してみたのですが、Androidでスプラッシュ画面からアプリ画面に遷移する際、一時的に画面が真っ黒になる事象が起きました。
本当はフェードインアニメーションでアプリ画面に遷移するはずなのですが...
(iOSは未検証)

バージョンなど

Flutter:(Channel stable, v1.17.0, on Microsoft Windows [Version 10.0.18362.836], locale ja-JP)
Dart:2.7
flutter_native_splash:0.1.9

解決方法

android/app/src/main/AndroidManifest.xml<activity android:name=".MainActivity" ...>タグの中に下記<meta-data>タグを追加すると直りました。

<meta-data
    android:name="io.flutter.embedding.android.SplashScreenDrawable"
    android:resource="@drawable/launch_background" />

<meta-data>タグ追加後のXMLはこんなイメージです。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.appname">
    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
         calls FlutterMain.startInitialization(this); in its onCreate method.
         In most cases you can leave this as-is, but you if you want to provide
         additional functionality it is fine to subclass or reimplement
         FlutterApplication and put your custom class here. -->
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="appname"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!-- splash後に画面が黒くなる件の対応 ここから -->
            <meta-data
                android:name="io.flutter.embedding.android.SplashScreenDrawable"
                android:resource="@drawable/launch_background" />
            <!-- splash後に画面が黒くなる件の対応 ここまで -->
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

参考

https://github.com/henriquearthur/flutter_native_splash/issues/54
5/5にlance-aurorさんが書いている内容をマネてみると直りました。(感謝です...)

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

[Flutter] Apple Watchの呼吸アプリのアニメーションを作ります。

こんにちは~Dreamwalkerです。
もう夏ですね。暑いです

始める前に

呼吸アプリを利用している方いらっしゃいますか?
ストレス溜まっている時、とてもおすすめです。

こんな形のアプリなんですが、
image.png
Use the Breathe app https://support.apple.com/en-us/HT206999 

この呼吸アプリのアニメーションをFlutterでやってみまいと思います。

コード

CustomPaint Widgetを使います。

CustomPaintの中にはPainterというのが必要です。

image.png

Painter

image.png

Animation

アニメーションはCurvedAnimationを活用します。
MixinとしてSingleTickerProviderStateMixinをState Classにつきます。
アニメーションを使いたいなら必要な事になります。

まず、アニメーションコントローラーを宣言します。
image.png

あと、initStateのメソッドの中にインスタンス化します。
image.png

今回使ったCurvedAnimationになります。
image.png

結果

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

AndroidStudioでHello Worldを表示させる

はじめに

新規アプリケーションで空のアクティビティを選択して準備が終わっていることが前提です。

Shift + F10を押すとコンパイルが開始されて仮想Androidが起動してアプリの実行が行われます。
正常に起動するとHello Worldと表示されます。

Hello World!と表示されたのはなぜ?

空のアクティビティを実行すると画面中央に「Hello World!」と定番の表示が行われました。
これはエディタ画面の上側にあるactivity_main.xmlタブを開いて表示される中身に秘密があります。

ホームページを作るときのHTMLのようにタグが並んでいて TextViewの表示の何行か下に「android:text="Hello World!"」という行があります。

つまりこれが表示されているわけです。

この部分を変更して実行すると画面に反映されるのがわかります。

基礎演算の理解と練習

エディタの上にあるタグ「activity_main.xml」をクリックします。
この部分はこれまで開発環境で開いたファイルが表示されていますが、間違って閉じた場合は画面左側のプロジェクト構成を表示しているツリーから
app/java/[プロジェクト名]にあるMainActivity.ktを開きましょう。

レイアウトファイルのactivity_main.xmlのタブを閉じてしまった場合はapp/res/layout/にあるactivity_main.xmlを開きます。

activity_main.xmlを開くと表示されるXMLに1行「android:id="@+id/tvMain"」を追加して下記のようにしあます。
入力するのが大変に感じますが、実際は空行で「id」と入力されると補完されるのでEnterで確定、その後自動的に「@+id/」が候補に出るのでEnterを押した後 tvMain と入力するだけです。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvMain"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

次はMainActivity.ktの方を開きます。

MainActivity.ktを開くとすでに

MainActivity.kt
class MainActivity : AppCompatActivity() {

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

このようなプログラムが記述されています。
折角なのでこれを使ってAndroidやKotlinの動きを確認してみましょう。

MainActivity.kt
class MainActivity : AppCompatActivity() {

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

        val tvMain = findViewById<TextView>(R.id.tvMain)
        tvMain.setText("Hello Kotlin World!")
    }
}

2行追加しました。これで実行すると Hello Kotlin World に変わったはずです。

表示が変わった理由

表示が変わったのはアプリが実行されると共に追加した2行が処理されたのが原因です。

Windowsアプリなら Formの Create やShowイベント。
マイコンのプログラムなら setupやmainに該当するのが
override fun onCreate(savedInstanceState: Bundle?) {
になります。

ちょっと難しいけど説明

class MainActivity : AppCompatActivity() {
AppCompatActivity とクラスが他で定義されていてそれをMainActivityという名前で使います。

override fun onCreate(savedInstanceState: Bundle?) {
AppCompatActivityには抽象クラスと呼ばれる onCreateメソッド(イベントのほうがわかりやすい)が定義されているので、AppCompatActivityを使った場合は onCreateを実装します。

super.onCreate(savedInstanceState)
onCreate はクラスが生成されるときに発生するイベントですが、その他の処理は定義元のクラスにあるので、この1行を書いてそっちで初期化処理を済ませます。
他言語だとinherited とかですね。

setContentView(R.layout.activity_main)
表示レイアウト R.layout.activity_main に従って画面を表示します。
R.layout.activity_main ってのはエディタ左側の app/res の resが Rになったと思えばわかりやすいです。

追加した2行

追加した2行
val tvMain = findViewById(R.id.tvMain)
定数 tvMain を定義します。
定義後に初期化し、その初期値は
findViewById で該当するレイアウト上のパーツを探します。
そのパーツは「TextView」型なのであらかじめこの型が返ってくることを期待します。
R.id.tvMainにてtvMainという IDが付いたパーツ※先ほどXMLに追加したものを参照します。

tvMain.setText("Hello Kotlin World!")
代入したtvMainはTextViewクラスなのでTextというプロパティを持ちます。
そのプロパティへ代入用のメソッド(関数)setTextを使用して値を代入します。

アプリ起動時に生成されるクラスの生成イベントに割り込んで、元々の処理は上位クラスに任せた後、レイアウト上にある指定したID tvMainを持つパーツを検索して、そのパーツのテキストに指定したものを代入するといった処理が行われているのです。

この初期化処理に便乗して Kotlinの変数や基礎演算を覚えてしまいましょう。

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

マテリアルデザイン導入直後にやること

概要

Androidプロジェクトにマテリアルデザインを導入後にやることを書きます。
Androidプロジェクト作成した後のHello worldに対して行います。

ライブラリ導入

マテリアルデザインを導入するために、build.gradleを以下のように記載します。

build.gradle
    // material design
    api 'com.google.android.material:material:1.2.0-alpha06'

styles.xmlの変更

res/values/styles.xmlを以下のように記載します。

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

activity_main.xmlの変更

res/layout/activity_main.xmlを変更して表示を確認します。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.button.MaterialButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="確認"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

結果

以下の表示になることを確認

余談

res/values/styles.xmlを初期値の状態のままだと以下のエラーが表示されます。

Error inflating class com.google.android.material.button.MaterialButton

参考

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

LiveDataとObservableFieldの違い

LiveDataとObservableField

どちらも何かの値を監視するために使用されるものである。
基本的な使い方に関しては下記の通りである。

Class A {
  val liveData = MutableLiveData<String>()

  val observableField = ObservableField<String>()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    liveData.observe(this, Observer {
      Log.d("livedata", "LiveData Changed ${it}")
    })

    observableField.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
      override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
        Log.d("observableField", "ObservableField Changed ${(sender as? ObservableField<String>)?.get()}")
      }
    })
  }

  override fun onResume() {
    super.onResume()
    liveData.value = "one"
    liveData.value = "two"
    liveData.value = "two"
    observableField.set("one")
    observableField.set("two")
    observableField.set("two")
  }
}

onResume()で値を更新する事によって、LiveDataobserve内の処理が実行され、
ObservableFieldonPropertyChangedの処理が実行される。

LiveDataとObservableFieldの動作の違い

両者とも値を監視するものではあるが、何が違ってくるのか。
上記の処理のLogを表示してみる。

D/livedata: LiveData Changed one
D/livedata: LiveData Changed two
D/livedata: LiveData Changed two
D/observableField: ObservableField Changed one
D/observableField: ObservableField Changed two

onResumeでLiveData/ObservableField両者に3回ずつ値を代入したのだが、
LiveData : 3回通知
ObservableField : 2回通知
と差がある。

簡単に説明すると、

LiveData : 値がセットされた時に通知が送られる
ObservableField : 値が変更された時に通知が送られる

という大きな違いがある。

今回の実行例だと、2/3回目に値として代入したものは"two"という値を連続で代入しているため、値としては同値として処理されるため、ObservableField に通知が行かず、LiveDataに通知が行った。

まとめ

LiveDataObservableFieldの両者とも扱いやすく、値を監視する手段としてよく使用されていると思われる。
最近はLiveDataがかなり普及してきているので、元々ObservableFieldを使用していたプロジェクトもLiveDataを併用する場合もあるかもしれない。
片方のみ使用するのであれば特に問題は無いとは思うが、両者が混在しているプロジェクトに関しては、上記のような違いがあるということを念頭に置いて使用していきたい。

参考資料

Android Developer LiveData
Android Developer ObservableField

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