20190502のAndroidに関する記事は9件です。

Android Studioをインストールして、アプリを起動してみた

最初の記事ということで、まずは基礎を。
何番煎じとかは気にせずに。起動するところまでをここでやってみます。
環境はWIN7です。
インストールするversionはAndroid Studio 3.4になります。

Android Studioのダウンロード

https://developer.android.com/studio/index.html?hl=ja
ここからダウンロードします。

「DOWNKOAD ANDROID STUDIO」をクリックすると下記の画像が表示されますが、
チェックを入れて、青いボタンをクリックするとAndroid Studioのダウンロードが始まります。
Screenshot_2019-05-02 Download Android Studio and SDK tools2.png

Android Studioのインストール

ダウンロードしたexeファイルをダブルクリックして、Android Studioのインストール。
基本的にはnextボタンを押してくだけでインストールできます。

Android Studioの起動

初めて起動すると下記の画像が表示されます。
無題11 (1).png
これは、他のところで使用した設定を使うかどうかを聞かれています。
特に設定がなければ初期のままで進めます。
無題11 (2).png
次に表示されるのは、改善のためのデータを送信するかを聞かれています。
特に問題なければSend usage statistics to Googleをクリック。
無題3.png
その後はNextをクリックして先へ進みましょう。

UI テーマの選択

Nextを押し、進んでいくと下記画面が表示されます。
これは、ざっくり説明すると背景色を白にするか黒にするかです。
あとから設定できるのでどちらえを選んでも良いです。
ちなみに今回はDarculaを選択しています。
無題4.png

プロジェクト作成

プロジェクトの選択

さて、一通りAndroid Studioの設定が終わると、次は作りたいプロジェクトの選択をします。
下記画面が表示されるので一番上のStart a new Android Studio projectを選びます。
無題5.png
次の画面はどんなプロジェクトを作るかです。
これも初期のEmpty Activityを選択しましょう。
この画面ではどのようなアプリを作りたいかによって、選択するものを変えましょう。
それぞれ必要なものを作ってくれるのでとても便利です。
無題6.png

(追記)
ここで言語を選択します。
どの言語を設定するかは好みで決めてください
image.png

プロジェクト完成

無題a.png
このような画面が表示されればプロジェクトが完成です。

アプリ起動

アプリ起動

メニューバーのRunのRun'app' をクリックしてください。
下記のような画面が表示されます。
この画面はどのデバイスでアプリを動かすかを選択するところです。
スマフォを接続していなければ、下記のように none と表示されているはずです。
無題z.png

では、ここで起動するエミュレータを作成してみましょう。

エミュレータ作成

「Create New Virtual Device」を選択します。
すると下記の画面が表示されます。
この画面はどのようなエミュレータを作りたいかを指定する画面です。
ここでは、すでにPixel 2選択されているので、そのままnextをクリックします。
無題aq.png
ここでもすでにQが選択されているのですが、クリックせずに先にQのとなりにあるDwonload
をクリックしましょう。私はすでにダウンロードしてしまったので表示されません。
するとダウンロードが始まるので、ダウンロードして、nextとくりっくしていきfinishします。
image.png
さて、Qのダウンロードが終わったらnextをクリック。
そうしたら下記の画面が表示されます。
無題w.png
ここはエミュレータの名前や画面の向きを決めるところですが、ここも特に変更せずにfinshボタンをクリックしてエミュレータを作りましょう。
※ 初めて作成する場合には何かダウンロード、インストール処理が走るかもしれません。

アプリ起動

デバイス選択画面に戻ってくると、先程作成したPixel 2 API Qが表示、選択されています。
このデバイスを使ってアプリを起動します。
image.png
OKをクリックし、しばらくするとエミュレータが起動します!
エミュレータの起動と、アプリの起動までは時間差があるのでしばらく待ちましょう。
image.png
この画面が表示されたら、アプリが起動したことになります。

なんと1行もコードを書かずにアプリが起動できるのです

ということで、Android Studioのインストールからアプリ起動までやってみました。

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

Android Architecture Blueprints の Clean Architecture 実装サンプルを読む (その1)

Android Architecture Blueprints には、GoogleによってMVVMやMVPなどの様々なアーキテクチャ実装や、ライブラリ利用のサンプルが公開されています。
本記事は、その中でも Clean Architecture の実装サンプルである todo-mvp-clean を読むことにより、書籍『Clean Architecture 達人に学ぶソフトウェアの構造と設計』の内容をより実践的に理解することを目的としています。

todo-mvp-cleanの位置付け

MVP実装のサンプルである todo-mvp からの変更点として、Presentation LayerData Layerの間にDomain Layerが追加されています。Use caseがクラスとして切り出されている点が、Clean Architectureのわかりやすい特徴と言えそうです。
alt

SOLID原則の目的のひとつは「変更に強くすること」

Clean Architectureの観点では、「データベースは詳細1であり、ビジネスルールに影響を与えません。
このTODOアプリは、@969581f にて DBライブラリをSQLiteOpenHelperからRoomに変更しています。
永続化されたTODO情報へのアクセス方法は、 TasksDataSource インターフェースに定義されています。そして、DBの具象実装は TasksLocalDataSource となります。
SOLID原則 に乗っ取ってモジュール2が分離されているので、DBが変わってもインターフェースの変更なしで具象実装を変更していることが確認できます。

SOLID原則とは

「第三部 設計の原則」にて、5章にわたって解説されています。
SOLID原則の目的は以下の3つであるとされています。

  • 変更に強いこと
  • 理解しやすいこと
  • コンポーネントの基盤として、多くのソフトウェアシステムで利用できること

以下の5つの原則の頭文字をとって、SOLID原則と呼ばれます。

  1. クラスはたったひとつのアクターに対して責務を負うべき(Simple Responsibility Principle)
  2. 振る舞いの変更は、コードの修正より追加で実現 (Open-Closed Principle)
  3. 個々のパーツが交換可能となるような契約に従う (Liscov Substitution Principle)
  4. 使ってないものへの依存はインターフェース分離で回避すべき (Interface Segregation Principle)
  5. 上位レベルの方針実装コードが下位レベルの詳細に依存せず、逆方向に依存すべき(Dependency Inversation Principle)

Clean Architectureで実装するとはどういうことか

SOLID原則はClean Architecture固有の概念ではありませんし、TasksDataSourceはRepositoryパターンで実装されているとも言えそうです。次の記事ではUsecaseの周辺を読み解いていき、さらにClean Architectureについての理解を深めていこうと思います。

備考:公式以外のClean Architecture実装サンプル

  1. android10/Android-CleanArchitecture ★1万超の有名リポジトリ。
  2. android10/Android-CleanArchitecture-Kotlin 1のKotlinリニューアル版。
  3. bufferapp/clean-architecture-components-boilerplate AACを導入したClean Architectureサンプル。

  1. 「Clean Architecture 達人に学ぶソフトウェアの構造と設計」 第30章 

  2. Android開発の「module」ではなく、Clean Architectureにおける「モジュール」のこと。 

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

【Android Studio】Android Studio古いバージョンが見つからない場合の対処法

以下のサイトから、Android Studioの古いバージョンをダウンロードできる

Android Studio 古いバージョンをダウンロードする
https://developer.android.com/studio/archive.html

日本語にすると、表示が崩れて、Android Studioの古いバージョンが見つからない。
なので、ご利用規約の時に、言語を「英語」にすると、表示が崩れないので
Android Studioの古いバージョンが表示されるようになる

スクリーンショット 2019-05-02 17.42.26.png

スクリーンショット 2019-05-02 17.43.33.png

スクリーンショット 2019-05-02 17.44.08.png




↓↓Google Play 無料Free
CherryCocktailGlassチェリーカクテルグラス〜無料簡単ミニゲームFree games
googleStoreLink.png

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

【GooglePlay】AdMob広告を入れた場合の設定「コンテンツの不適切なレーティング」

AdMob側の設定で、「デリケートなカテゴリ」で広告の種類が設定できる。
Google Playの「コンテンツのレーディング」とAdMobの「デリケートなカテゴリ」を、矛盾なく設定する必要がある。

コンテンツのレーディングを「3歳以上」の場合は、AdMobの「デリケートなカテゴリ」を
許可→ブロック
に設定する。

↓AdMob側
スクリーンショット 2019-05-02 17.55.37.png

スクリーンショット 2019-05-02 17.56.13.png

↓Google Play側
スクリーンショット 2019-05-02 18.04.24.png




↓↓Google Play 無料Free
CherryCocktailGlassチェリーカクテルグラス〜無料簡単ミニゲームFree games
googleStoreLink.png

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

MotionLayoutでMaterialDesignのTextFieldもどきを実装する

はじめに

昨年のGoogleI/O 2018でConstraintLayout2.0が紹介されましたが、その中でMotionLayoutという新たなAndroidのアニメーションの仕組みが公開されました。
今回は、そのMotionLayoutを使用して、MaterialDesignのTextFieldっぽいものを実装してみたので、それについて実装方法などを書き連ねたいと思います。
※またMotionLayoutはまだalpha版なので、今回は、constraint-layout:2.0.0-alpha4での実装を紹介しますが、新たなバージョンがリリースされた場合、実装が変わる可能性もあるので、ご了承ください。

作ったもの

こちらのような項目がリストのように表示されていて、画面遷移させることなく閲覧モードから入力モードにすることができます。それぞれのモード間の遷移時のアニメーションでMotionLayoutを使って実装しています。

挙動としては、
1. 右のテキスト部分をクリックした場合、入力モードになる
2. フォーカスが外れたら、閲覧モードに戻る
(フォーカスは別のテキストFieldをクリックするか、下のボタンを押下すると外れる)

ソースコードはこちらに上げています。参考にされたい方はこちらをご覧ください。
https://github.com/youmitsu/MotionLayoutMaterialTextField

MotionLayoutの概要

MotionLayoutについては、多くの方が仕組みについての記事を公開しているので、ここでは省略します。

基本的なステップとしては、以下となります。

  1. アニメーションさせる前のレイアウトをMotionLayoutを親として実装
  2. Sceneのxmlを作成
  3. 1のattributeに2のSceneファイルを指定

実装方法

1. ConstraintLayout2.0のインストール

まずは、ConstraintLayout2.0をインストールします。
AndroidXと、SupportLibraryの2つのArtifactsがあるので、自身のプロジェクトに応じて、使い分けましょう。

リリースノートはこちら
https://androidstudio.googleblog.com/2019/04/constraintlayout-200-alpha-4.html

AndroidXの場合

dependencies {
    ...
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
}

SupportLibraryの場合

dependencies {
    ...
    implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha4'
}

2. 初期状態のviewを作成

まずは、こちらのクリックされる前のレイアウトを作っていきます。

xmlは以下になります。MotionLayoutはConstraintLayoutの子クラスなので、基本的にはConstraintLayoutでレイアウトを作るのと同じ要領で実装します。

※サンプルリポジトリでは、Databindingを使って入力データをバインディングしているので、<layout><data>タグが入っていますが、無くても動きます。

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

    <data>
        <variable name="data" type="jp.co.youmitsu.myapplication.CustomMotionEditTextLayout"/>
    </data>

    <androidx.constraintlayout.motion.widget.MotionLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/motion_layout"
    >

        <TextView
                android:id="@+id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="start|center_vertical"
                android:layout_marginStart="10dp"
                android:textColor="#808080"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toStartOf="@id/nickname_value"
                android:text="@{data.title}"
        />

        <TextView
                android:id="@+id/nickname_value"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:gravity="end|center_vertical"
                android:textSize="15sp"
                android:layout_marginEnd="10dp"
                android:ellipsize="end"
                android:singleLine="true"
                android:maxEms="15"
                android:text="@{data.value}"
                android:clickable="true"
                android:focusable="true"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@id/nickname_title"/>

        <androidx.appcompat.widget.AppCompatEditText
                android:id="@+id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="0"
                android:visibility="invisible"
                android:textSize="15sp"
                android:inputType="text"
                android:text="@{data.value}"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

    </androidx.constraintlayout.motion.widget.MotionLayout>
</layout>

3. アニメーション前後のConstraintの状態とTransitionを表すMotionSceneファイルを作成

次に、タップしてアニメーションし始める時と終わった時のレイアウトのConstraintSetとTransitionをMotionSceneという形で定義します。
MotionSceneファイルはxmlで記述するので、res/xml配下に新たなファイルを作成します。

xmlファイルは以下です。
@id/startがアニメーションする前のConstraintSet。@id/endがアニメーションした後のConstraintSetを表しています。
今回の場合、start時のConstraintと上記2で定義したMotionLayout内の要素のConstraintは一致することになります。

@id/startのConstraintSetでのレイアウト:

@id/endのConstraintSetでのレイアウト:

layout_custom_motion_edittext_scene.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
        xmlns:motion="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android">

    <Transition
            motion:constraintSetStart="@id/start"
            motion:constraintSetEnd="@id/end"
            motion:duration="200">

        <OnClick motion:targetId="@id/nickname_value"
                 motion:clickAction="transitionToStart|transitionToEnd"/>

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
                android:id="@+id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textSize="@dimen/text_size_normal"
                android:layout_marginStart="5dp"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toStartOf="@id/nickname_value">
            <CustomAttribute
                    motion:attributeName="textSize"
                    motion:customFloatValue="15"
            />
            <CustomAttribute
                    motion:attributeName="textColor"
                    motion:customColorValue="#808080"
            />
        </Constraint>

        <Constraint
                android:id="@+id/nickname_value"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:textSize="15sp"
                android:layout_marginEnd="10dp"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toEndOf="@id/nickname_title"/>

        <Constraint
                android:id="@+id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="0"
                android:visibility="invisible"
                android:textSize="15sp"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">

        <Constraint
                android:id="@id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="5dp"
                motion:layout_constraintBottom_toTopOf="@id/edit_text"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent">
            <CustomAttribute
                    motion:attributeName="textSize"
                    motion:customFloatValue="12"
            />
            <CustomAttribute
                    motion:attributeName="textColor"
                    motion:customColorValue="@color/colorAccent"
            />
        </Constraint>

        <Constraint
                android:id="@+id/nickname_value"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:textSize="15sp"
                android:alpha="0"
                android:visibility="invisible"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"/>

        <Constraint
                android:id="@id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="1"
                android:visibility="visible"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

</MotionScene>

4. MotionLayoutのattributeにlayoutDescriptionとして3のSceneファイルを設定

アニメーションする対象のview(MotionLayout)とMotionSceneファイルを作成できたら、それぞれを結びつけるために、MotionLayoutのlayoutDescription属性を設定します。こうすることで、画像のようなアニメーションが実現できます。

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

    <data>
        <variable name="data" type="jp.co.youmitsu.myapplication.CustomMotionEditTextLayout"/>
    </data>

    <androidx.constraintlayout.motion.widget.MotionLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/motion_layout"
            app:layoutDescription="@xml/layout_custom_motion_edittext_scene"  // これを追加
    >
    ...
    </androidx.constraintlayout.motion.widget.MotionLayout>
</layout>

まとめ

今回は、MotionLayoutを使って、MaterialDesignのTextFieldの拡張っぽいものを実装してみました。アニメーションに関するコードをほとんどxmlだけで完結させることができるので、とても使いやすそうだなという印象です。
これからも色々機能追加があるみたいなので、楽しみです。
最後まで読んでいただきありがとうございました。

参考にさせていただいたもの

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

【Android】MotionLayoutでMaterialDesignのTextFieldもどきを実装する

はじめに

昨年のGoogleI/O 2018でConstraintLayout2.0が紹介されましたが、その中でMotionLayoutという新たなAndroidのアニメーションの仕組みが公開されました。
今回は、そのMotionLayoutを使用して、MaterialDesignのTextFieldっぽいものを実装してみたので、それについて実装方法などを書き連ねたいと思います。
※またMotionLayoutはまだalpha版なので、今回は、constraint-layout:2.0.0-alpha4での実装を紹介しますが、新たなバージョンがリリースされた場合、実装が変わる可能性もあるので、ご了承ください。

作ったもの

こちらのような項目がリストのように表示されていて、画面遷移させることなく閲覧モードから入力モードにすることができます。それぞれのモード間の遷移時のアニメーションでMotionLayoutを使って実装しています。

挙動としては、
1. 右のテキスト部分をクリックした場合、入力モードになる
2. フォーカスが外れたら、閲覧モードに戻る
(フォーカスは別のテキストFieldをクリックするか、下のボタンを押下すると外れる)

ソースコードはこちらに上げています。参考にされたい方はこちらをご覧ください。
https://github.com/youmitsu/MotionLayoutMaterialTextField

MotionLayoutの概要

MotionLayoutについては、多くの方が仕組みについての記事を公開しているので、ここでは省略します。

基本的なステップとしては、以下となります。

  1. アニメーションさせる前のレイアウトをMotionLayoutを親として実装
  2. Sceneのxmlを作成
  3. 1のattributeに2のSceneファイルを指定

実装方法

1. ConstraintLayout2.0のインストール

まずは、ConstraintLayout2.0をインストールします。
AndroidXと、SupportLibraryの2つのArtifactsがあるので、自身のプロジェクトに応じて、使い分けましょう。

リリースノートはこちら
https://androidstudio.googleblog.com/2019/04/constraintlayout-200-alpha-4.html

AndroidXの場合

dependencies {
    ...
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
}

SupportLibraryの場合

dependencies {
    ...
    implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha4'
}

2. 初期状態のviewを作成

まずは、こちらのクリックされる前のレイアウトを作っていきます。

xmlは以下になります。MotionLayoutはConstraintLayoutの子クラスなので、基本的にはConstraintLayoutでレイアウトを作るのと同じ要領で実装します。

※サンプルリポジトリでは、Databindingを使って入力データをバインディングしているので、<layout><data>タグが入っていますが、無くても動きます。

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

    <data>
        <variable name="data" type="jp.co.youmitsu.myapplication.CustomMotionEditTextLayout"/>
    </data>

    <androidx.constraintlayout.motion.widget.MotionLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/motion_layout"
    >

        <TextView
                android:id="@+id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="start|center_vertical"
                android:layout_marginStart="10dp"
                android:textColor="#808080"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toStartOf="@id/nickname_value"
                android:text="@{data.title}"
        />

        <TextView
                android:id="@+id/nickname_value"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:gravity="end|center_vertical"
                android:textSize="15sp"
                android:layout_marginEnd="10dp"
                android:ellipsize="end"
                android:singleLine="true"
                android:maxEms="15"
                android:text="@{data.value}"
                android:clickable="true"
                android:focusable="true"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@id/nickname_title"/>

        <androidx.appcompat.widget.AppCompatEditText
                android:id="@+id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="0"
                android:visibility="invisible"
                android:textSize="15sp"
                android:inputType="text"
                android:text="@{data.value}"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

    </androidx.constraintlayout.motion.widget.MotionLayout>
</layout>

3. アニメーション前後のConstraintの状態とTransitionを表すMotionSceneファイルを作成

次に、タップしてアニメーションし始める時と終わった時のレイアウトのConstraintSetとTransitionをMotionSceneという形で定義します。
MotionSceneファイルはxmlで記述するので、res/xml配下に新たなファイルを作成します。

xmlファイルは以下です。
@id/startがアニメーションする前のConstraintSet。@id/endがアニメーションした後のConstraintSetを表しています。
今回の場合、start時のConstraintと上記2で定義したMotionLayout内の要素のConstraintは一致することになります。

@id/startのConstraintSetでのレイアウト:

@id/endのConstraintSetでのレイアウト:

layout_custom_motion_edittext_scene.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
        xmlns:motion="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android">

    <Transition
            motion:constraintSetStart="@id/start"
            motion:constraintSetEnd="@id/end"
            motion:duration="200">

        <OnClick motion:targetId="@id/nickname_value"
                 motion:clickAction="transitionToStart|transitionToEnd"/>

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
                android:id="@+id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textSize="@dimen/text_size_normal"
                android:layout_marginStart="5dp"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toStartOf="@id/nickname_value">
            <CustomAttribute
                    motion:attributeName="textSize"
                    motion:customFloatValue="15"
            />
            <CustomAttribute
                    motion:attributeName="textColor"
                    motion:customColorValue="#808080"
            />
        </Constraint>

        <Constraint
                android:id="@+id/nickname_value"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:textSize="15sp"
                android:layout_marginEnd="10dp"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toEndOf="@id/nickname_title"/>

        <Constraint
                android:id="@+id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="0"
                android:visibility="invisible"
                android:textSize="15sp"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">

        <Constraint
                android:id="@id/nickname_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="5dp"
                motion:layout_constraintBottom_toTopOf="@id/edit_text"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent">
            <CustomAttribute
                    motion:attributeName="textSize"
                    motion:customFloatValue="12"
            />
            <CustomAttribute
                    motion:attributeName="textColor"
                    motion:customColorValue="@color/colorAccent"
            />
        </Constraint>

        <Constraint
                android:id="@+id/nickname_value"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:textSize="15sp"
                android:alpha="0"
                android:visibility="invisible"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"/>

        <Constraint
                android:id="@id/edit_text"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:alpha="1"
                android:visibility="visible"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

</MotionScene>

4. MotionLayoutのattributeにlayoutDescriptionとして3のSceneファイルを設定

アニメーションする対象のview(MotionLayout)とMotionSceneファイルを作成できたら、それぞれを結びつけるために、MotionLayoutのlayoutDescription属性を設定します。こうすることで、画像のようなアニメーションが実現できます。

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

    <data>
        <variable name="data" type="jp.co.youmitsu.myapplication.CustomMotionEditTextLayout"/>
    </data>

    <androidx.constraintlayout.motion.widget.MotionLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/motion_layout"
            app:layoutDescription="@xml/layout_custom_motion_edittext_scene"  // これを追加
    >
    ...
    </androidx.constraintlayout.motion.widget.MotionLayout>
</layout>

まとめ

今回は、MotionLayoutを使って、MaterialDesignのTextFieldの拡張っぽいものを実装してみました。アニメーションに関するコードをほとんどxmlだけで完結させることができるので、とても使いやすそうだなという印象です。
これからも色々機能追加があるみたいなので、楽しみです。
最後まで読んでいただきありがとうございました。

参考にさせていただいたもの

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

NotoSansCJKJPを使ってみてのメモ(Android)

仕事でNotoSansCJKJPを使ったので

仕事でデザイナーさんに指定されて、NotoSansCJKJPを使うことが続いたので、メモを残します。
ソースはこちらに。
https://github.com/shinya-takano/NotoSansCjkJpSample

NotoSansCJKJPのダウンロードからAndroidStudioへの格納まで

  • https://www.google.com/get/noto/ からフォントをDLして、zipを解凍します。
  • 解凍したotfファイルをresフォルダのfontフォルダに格納します。
  • そのままだと大文字と「-」がフォーマット違反なので、キャプチャのようにリネームして格納します。

スクリーンショット 2019-05-02 16.26.33.png

これで、xmlから使うときは、android:fontFamily="@font/noto_sans_cjk_jp_regular"
のように使えます。
ソースから使う場合は、

val font = context.resources.getFont(R.font.noto_sans_cjk_jp_regular)
textView.setTypeface(font, Typeface.NORMAL)

のようにして使えます。

いくつかハマったところがあったので、解決策をメモ

そのまま使うと、キャプチャ(サンプルアプリ)の3つめのように元々のフォントの空白が大きく出てしまい、
デザインで指定・イメージしているマージンとだいぶ違う結果になってしまうので、
android:includeFontPadding="false" を設定します。
(フォントがNotoSansCJKJPでプロパティをfalseに設定しているのが、4つめ)
Screenshot_1556781750.png

ちょっとサンプルアプリがわかりにくいのですが、以下の形でまとめています。

上から1つめ 上から2つめ 上から3つめ 一番下
DefaultFont DefaultFontで includeFontPadding="false" NotoFont NotoFontで includeFontPadding="false"

なお、ViewPagerのタブ文字の場合は、フォント自体がうまく適用できなかったので、
stackoverflow を参考に直接フォントを設定します。

    private fun changeTabsFont(tabs: TabLayout) {

        val font = this.resources.getFont(R.font.noto_sans_cjk_jp_regular)

        val vg = tabs.getChildAt(0) as ViewGroup
        val tabsCount = vg.childCount
        for (j in 0 until tabsCount) {
            val vgTab = vg.getChildAt(j) as ViewGroup
            val tabChildsCount = vgTab.childCount
            for (i in 0 until tabChildsCount) {
                val tabViewChild = vgTab.getChildAt(i)
                if (tabViewChild is TextView) {
                    tabViewChild.setTypeface(font, Typeface.NORMAL)
                    tabViewChild.includeFontPadding = false
                }
            }
        }
    }

まとめ

NotoSansCJKJPを使う機会がちょくちょく出るので、解決策をメモしておきたかったので、
自分用のメモを作りました。

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

React Nativeで複数のstyleを適用する

私があたったユースケース的には
「H3のText用Styleと、リンクを有効化したっぽいStyleを2つ適用したい」
でした。

一言で言うと「 style={} には配列で複数のスタイルを渡すことができる」です。

このようにします。

App.tsx
<Text style={[styles.textH3, styles.textLink]}>ほげほげ</Text>

//...
const styles = StyleSheet.create({
  textH3: {
    paddingTop: 10,
    paddingBottom: 10,
    fontSize: 20,
    fontWeight: 'bold',
  },
  textLink: {
    color: 'blue'
  }
});

思っていたより簡単でした!

ちなみに(ちょっと注意点)

パラメータは後勝ちのようです。
上記の場合、例えばtextLinkに fontSize: 5 を入力すると、文字サイズが小さくなってしまいます。
注意しましょう!

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

Flutterを使ってクソアプリを作ってみた

これは何?

最近、若者の間で「クソアプリ」なるものを作って公開するのが話題になっているようで。いや確かに「ちゃんとしたもの」を作ろうとすると、それはそれで多大なる労力が必要になってハードルも上がるのだけれども、クソアプリでいいやってハードルを下げると「ちょっとかじってみる」程度の経験を積むにはいいし、やったことを公開することで情報の整理にもつながっていい気がするな、ということで最近気になるFlutterで負けじとクソアプリを作ってみた。

ソースコードはコチラ

Flutterとは?

Android/iOSのマルチデバイス対応のアプリが1つのソースコードで開発できるというGoogleが作った技術。Dart言語で実装する。

https://flutter.dev/

やったこと

開発環境の構築

大いにこの記事を参考にしており「開発環境の構築」は全く同じなので端折ります(手抜き)

Flutterに入門してクソアプリを作るまで
https://qiita.com/matsushou/items/f62ca1fb249670d7dbbc

ちなバージョンは

  • Flutter v1.2.1 (for Mac)
  • Android Studio 3.4
    • FlutterとDartのプラグインを入れる

Dartに再入門する

筆者Google好きで、Dartが公開された直後(1.0以前)にかじったことがあったので、おさらい的に言語仕様(結構変わっている...)を見直してみる。

Language Tourをナナメ読む
https://www.dartlang.org/guides/language/language-tour

前述の参考記事のとおり Important concepts まで読んだが、Javaエンジニアとしては以下を踏まえればどうにかなりそう。

  • 型はある、クラス定義も継承もある、ちゃんとオブジェクト指向
  • new は2.x系から省略可能になった(当時のリリースノート
  • アンダースコア _ 始まりの変数/関数/クラスがprivateになる
    • 可視性を示す修飾子 public/private はない

Flutterアプリを作ってみる

  • Android Studioから「Start a new Flutter project」を選択
    Kobito.OHndNY.png

    • Flutter Applicationを選択してNext
    • Project nameを適当に指定(デフォルトの flutter_app のままでもいい)してNext
    • Company domainを適当に指定、Sample Applicationの "generate sample content" にチェックしてFinish
    • サンプルコード付きのプロジェクトが作成される Kobito.W0QeXI.png
      • main.dart にメインロジックが記載されている
      • ちゃんとテストコード widget_test.dart も用意されているのが素敵 :star:
    • Emulatorを用意して起動
      • AVD Managerから端末のVMを用意して起動する
      • +ボタンを押すと画面に表示された数値が増えていくサンプルアプリらしい
    • サンプルアプリの画像は前述の記事にキャプチャがあるので、そっちを見てください(という手抜き)

アプリを実装する

クソアプリの境界線ってどこだろう?うっかりちゃんと作ってしまうとクソではなくなってしまうので、ここは慎重にクソアプリを作る必要がある。

今回は、macOSを始めとして Google Chrome や Evernote でも実装されている流行りの DarkMode を搭載すべく「ダークモードへの切り替え」をこのアプリに実装してみることにする。

漢は黙ってCI

とはいえロジックに手を出し始めるのではなく、眼の前に動くコードとテストコードがあるなら、まずCIを回さないとね。ということでCircleCIでのビルドを設定しておく。

  • 生成されたサンプルプロジェクトをそのままコミット&GitHubへプッシュする。

次に挙げるサイトを参考にすると、すでにFlutter用のビルドコンテナが用意されているのが分かるので、単純に .circleci/config.yml を追加するだけで、CircleCI上でビルドが動くようになる。作業ログ

circleci/config.yml
 version: 2
 jobs:
   build:
     docker:
       - image: cirrusci/flutter
     steps:
       - checkout
       - run: flutter doctor
       - run: flutter test
       - run: flutter build -v apk

これで、branch push 時や、master マージ時にビルドが走るようになる。コケたら教えてくれるので、あんしんあんしん。

モード切り替え用のコントロール(Switch)を配置

よし、本筋に戻ってまずはスイッチを配置するぞ。ということでサンプルをググってみる。

https://kodestat.gitbook.io/flutter/24-flutter-switch

これがシンプルにまとまっていて分かりやすい。他にもサンプルケースが色々あって良さげ。このサイトはGitBookで作られていて、元のリポジトリは ここ のようだ。

main.dart の内容をまるっとこのサンプルに書き換えて実行してみたら、ちゃんとスイッチのサンプルが表示された。

Kobito.zdsg1w.png

そうそう、それよそれ。
今回はタイトル付きのスイッチを使いたいので、この部分+ _onChanged2() 関数をパクればよろし。

main.dart
new SwitchListTile(
    value: _value2,
    onChanged: _onChanged2,
    title: new Text('Hello World', style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.red)),
 )

実際には、こんなソースを child: Column()children: <Widget>[] の先頭に追加しました。
この時点ではまだ _changeDarkMode() 関数はテキトーです。

main.dart
Container(
  padding: EdgeInsets.all(40.0),
  child: SwitchListTile(
    value: _isDarkMode,
    onChanged: _changeDarkMode,
    title: Text('Dark mode', style: new TextStyle(fontWeight: FontWeight.bold)),
  ),
),

見た目はこんな感じに。

Kobito.JqiQUR.png

パーツを配置しただけで「Dark modeに切り替えられる感」が8割増しましたね。

いざ、DarkModeへ切り替え

残るは _changeDarkMode() 関数の実装だ。ということで試しに backgroundColor 指定だけblackで追加したら、文字は黒のままで画面全体が真っ黒になってしまったので、どうやら何か違うらしい。調べてみると Theme を切り替える必要がありそう。

Using Themes to share colors and font styles - Flutter

でもこの実装を真面目にやると面倒くさいなぁ、と調べ続けていたら、DynamicTheme というドンピシャなwidgetが公開されていたので、これを使おう。

pubspec.yaml のdependenciesに1行追加する。

pubspec.yaml
dependencies:
  ...(中略)
  dynamic_theme: ^1.0.0

main.dart の修正箇所はこんな感じ。(抜粋)

main.dart
import 'package:dynamic_theme/dynamic_theme.dart';

...(中略)

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return DynamicTheme(
      defaultBrightness: Brightness.light,
      data: (brightness) => ThemeData(
        primarySwatch: Colors.blue,
        brightness: brightness,
      ),
      themedWidgetBuilder: (context, theme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: theme,
          home: MyHomePage(title: 'Flutter Dark Mode Sample'),
        );
      }
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isDarkMode = false;

  void _changeDarkMode(bool value) {
    setState(() {
      _isDarkMode = value;

      var _brightness = Brightness.light;
      if (_isDarkMode) {
        _brightness = Brightness.dark;
      }
      DynamicTheme.of(context).setBrightness(_brightness);
    });
  }
  ...()
}
  • 結果

    • スイッチのOn/OffでThemeが動的に切り替わり、憧れのDarkModeに!ヒャッホウ!! :night_with_stars: dark-mode-sample2.gif
    • うーん、、、冷静に見ると「だからどうした感」のあるクソアプリですね :star2:
    • 参考:作業ログ

感想

  • 簡単にスマホアプリが作れそう
    • 今回はアプリを最終ビルドするところまでやっていないけど、簡単な動作確認レベルならすぐイケる
  • dart はキャッチアップ楽ちん
    • エディタの補完も効けば何の苦もない
  • ソースコードの保存 → エミュレータへの自動反映、での動作確認が非常に快適
  • クソアプリ作ってみるの楽しい

GW後半に軽くプログラミングしてみたい方は、いかがでしょうか?

お粗末さまでした。

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