EDIT MODE

モバイルアプリ開発に関することを書いています

Design Support Library v22.2.0について Part 2

前回の記事では、TextInputLayoutとFloatingActionButtonについて書きました。 androhi.hatenablog.com

今回は、主にSnackbarとCoordinatorLayoutについて調べたことを、書いていきます。

SnackBar

Android 4.4まではアプリ内で簡易的な通知を行う際に、Toastを使った実装が多かったと思いますが、Android 5.0以降はSnackbarと呼ばれる実装を使うよう推奨されてます。

UIとしてはToastととてもよく似ていますが、Snackbarにはアクションを含めることが出来る点や、スワイプ操作で表示を消すことが出来る点などが異なっています。

詳細は、公式サイトのSnackbars&toastsが詳しいです。

Snackbarの表示

使い方はほぼToastと同じなので、以下のようなコードで表示させてみました。

final LinearLayout layout = (LinearLayout) findViewById(R.id.root_layout);
Snackbar.make(layout, "Snackbar test", Snackbar.LENGTH_LONG)
        .setAction("UNDO", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // something
            }
        })
        .show();

f:id:androhi:20150603021218p:plain

注意しなければいけないのは、make()メソッドの第一引数にSnackbarをホールドするための親となるViewを渡す必要があることです。 アクションを含めたいときは、setAction()メソッドにラベルとリスナーを渡すだけでした。

なお一つのSnackbarにアクションは一つしか含めることが出来ません。 メッセージは文字数が多い場合は、適時改行されます。 試しに以下のコードを実行すると、下図のようになりました。

final LinearLayout layout = (LinearLayout) findViewById(R.id.root_layout);
String message = "long test message. long test message. long test message. long test message.";
Snackbar.make(layout, message, Snackbar.LENGTH_LONG)
        .setAction("UNDO", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // something
            }
        })
        .setAction("REDO", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // something
            }
        })
        .show();

f:id:androhi:20150603021241p:plain

CoordinatorLayout

このクラスはMaterialDesignならではだなぁという感じのViewGroupです。あるViewがスクロールした際に、連動して他のViewもスクロールするようなUIを作るために使用するクラスのようです。GoogleのInboxアプリでよく見ますね。

Support Libraryのリリースノートによると、Design Libraryのコンポーネントの多くは、このCoordinatorLayoutの子Viewになることを当てにするとあります。

Class Overviewでは、主なユースケースとして次の2点を挙げています。

  1. As a top-level application decor or chrome layout
  2. As a container for a specific interaction with one or more child views

要約すると最初に書いたように、特別な依存関係を構築したいViewの親ViewGroupとして使えということのようです。

CoordinatorLayout + FloatingActionBar + Snackbar

分かり易い例として、Snackbarが表示されるとそれに合わせてFABもアニメーションする(Inboxと同じ動き)、というサンプルを動かそうと思います。

まずはCoordinatorLayoutクラスを、以下のように普通にViewGroupとして使ってみました。 実行してみると、SnackbarとFABが重なってしまいました。意図した動きになりません。

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:design="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/coordinator_layout"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin">

        <Button
            android:id="@+id/show_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Show Snackbar"
            />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:src="@drawable/ic_add_white_24dp"
            design:fabSize="normal"
            />

    </RelativeLayout>
    
</android.support.design.widget.CoordinatorLayout>
findViewById(R.id.show_button).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        final CoordinatorLayout layout = (CoordinatorLayout) findViewById(R.id.coordinator_layout);
        String message = "Snackbar test.";
        Snackbar.make(layout, message, Snackbar.LENGTH_LONG)
                .setAction("UNDO", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // something
                    }
                })
                .show();
    }
});

f:id:androhi:20150603021308p:plain

FABにアンカーを設定する

片方のViewの動きに合わせて、もう片方のViewもアニメーションさせるには、anchorを設定しなければいけないとのことです。アンカーに指定出来るのは、CoordinatorLayoutの派生クラスになります。アンカーが設定されてるViewは指定出来ません。

さっきの失敗したxmlを、以下のように直してみました。

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:design="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/coordinator_layout"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/show_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Show Snackbar"
            />

    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_add_white_24dp"
        design:fabSize="normal"
        design:layout_anchor="@id/coordinator_layout"
        design:layout_anchorGravity="bottom|right"
        />

</android.support.design.widget.CoordinatorLayout>

やったことは、FABをCoordinatorLayout直下に移動して、anchorを設定しました。 layout_anchorに対象のViewIDを指定し、layout_anchorGravityで特定の位置に寄せています。

これを実行すると、きちんとSnackbarとFABが重ならない動きになりました。

f:id:androhi:20150603021328p:plain

振る舞いの実装について

ところでこの場合、実際にFABがアニメーションする仕組みを提供しているのは、FloatingActionButton.Behaviorクラスです。

これはCoordinatorLayout.Behaviorを拡張したクラスで、他にもAppBarLayout.Behavior/AppBarLayout.ScrollingViewBehavior/SwipeDismissBehaviorなどが用意されていて、それぞれどんなアニメーションをするかなどの振る舞いを実装しているようです。

CoordinatorLayoutの子Viewになるクラスには、DefaultBehaviorアノテーションを使うことで、カスタムしたBehaviorも設定可能なようです。試してませんが、以下のように使えば良さそうです。

@DefaultBehavior(CustomView.Behavior.class)
public class CustomView extends View {
    // something
    ...
    public static class Behavior extends android.support.design.widget.CoordinatorLayout.Behavior<CustomeView> {
        ...
    
        public boolean layoutDependsOn(CoordinatorLayout parent, CustomView child, View dependency) {
            ...
        }
    
        public boolean onDependentViewChanged(CoordinatorLayout parent, CustomeView child, View dependency) {
        ...
        }
    }
}

まとめ

  1. SnackbarはToastにアクションを追加したようなUIなので、うまく使えばアプリ内通知がスッキリしそうだと感じます
  2. CoordinatorLayoutは一見地味だけど、ユーザー操作に合わせてUIをアニメーションさせるのに強力な仕組みだと思います
  3. CoordinatorLayout.Behaviorは、あまり凝ったことしなければFABなどのデフォルトのBehaviorで十分だろうけど、カスタムも出来るので使い勝手が良さそう

Design Support Library v22.2.0について Part 1

先日リリースされたDesignSupportLibraryについて調べたことを書いていきます。 なおこの記事で動作確認しているのは、SupportLibrary v22.2.0を使っています。

動作確認したサンプルプロジェクトでは、build.gradleに以下を追記しました。

dependencies {
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.android.support:design:22.2.0'
}

TextInputLayout

ドキュメントを読むと、このクラスはLinearLayoutのサブクラスとなっていて、EditTextのヒントテキストをフローティングラベルとして見せることが出来るようになるとのことです。あとはエラー表示にも対応しているみたいですね。

FloatingLabel付きEditTextの表示

以下のコードを動かしてみました。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="hint text"/>

    </android.support.design.widget.TextInputLayout>

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout);
        textInputLayout.setErrorEnabled(true);
        textInputLayout.setError("Error!");
    }

f:id:androhi:20150602013825p:plain f:id:androhi:20150602013843p:plain

Note: エラー表示を消したいときは、setErrorEnabled(false)にすればいいようです。

ChildViewの追加

TextInputLayoutクラスにはaddView()メソッドが用意されているので、動的にViewを追加出来ます。 ただし、TextInputLayoutとEditTextは1対1でないといけないようです。試しにさっきのコードを以下のようにすると、例外が発生しました。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout);
        textInputLayout.setErrorEnabled(true);
        textInputLayout.setError("Error!");

        EditText editText = new EditText(this);
        textInputLayout.addView(editText, 0, 
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    }
Caused by: java.lang.IllegalArgumentException: We already have an EditText, can only have one

JavaからEditTextを操作する場合は、以下のように書くとうまくいきました。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </android.support.design.widget.TextInputLayout>

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout);
        textInputLayout.setHint("hint text from setHint method");
        textInputLayout.setError("Error!");
        textInputLayout.setErrorEnabled(false);

        EditText editText = new EditText(this);
        textInputLayout.addView(editText, 0,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

        EditText editText2 = textInputLayout.getEditText();
        editText2.setText("text from setText method");

セットしたEditTextはgetEditTextで取り出すことが出来ます。 注意しなければいけないのは、テキストはEditTextにセットしますが、エラーとヒントはTextInputLayoutにセットする必要があります。

f:id:androhi:20150602015625p:plain

FloatingActionButton

待望のFloatingActionButtonクラスですね。 MaterialDesignのUIコンポーネントの中で最もメジャーであるにも関わらず、長い間3rd Party Libraryや独自実装に頼らざるを得なかったので、個人的にはDesignSupportLibraryで一番うれしいです。

FloatingActionButtonについてはClass Overviewでも、特定のアクションを促すためのボタンだと定義しています。 パッケージツリーを見ると、ImageViewを継承しているようです。 デフォルトの背景色は、アプリのテーマのcolorAccentが割り当てられます。

ちなみにこのクラスは、FloatingActionButton.Behaviorクラスを持っていますが、主にSnackBarと連携する際に用いるので、次回書くことにします。

FABの表示

表示するだけであれば、layoutファイルに以下のように書くだけで大丈夫でした。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:design="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/mini_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_add_white_24dp"
        design:fabSize="mini"
        />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/normal_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_add_white_24dp"
        design:fabSize="normal"
        />

</LinearLayout>

f:id:androhi:20150602014006p:plain

ちゃんと影も付いてます。タップ時には影も濃くなって、浮き上がるアニメーションになります。

FloatingActionButtonクラスは専用のAttributesを持っていて、FABのサイズを2パターン指定出来るようです。

背景色の変更

背景色を変えるには、setBackgroundTintList()メソッドが推奨されています。引数にはColorStateListを渡すので、ボタンの状態ごとに色を指定出来ます。

FloatingActionButton miniFab = (FloatingActionButton) findViewById(R.id.mini_fab);
FloatingActionButton normalFab = (FloatingActionButton) findViewById(R.id.normal_fab);
miniFab.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW));
normalFab.setBackgroundTintList(ColorStateList.valueOf(Color.GREEN));

f:id:androhi:20150602014027p:plain

あとsetRippleColor()というメソッドも用意されていて、KitKat以降のデバイスなら波紋のような描画をするとあるので、以下のコードを手元のKitKat端末で試しましたが確認出来ませんでした。 使い方が間違っているのかもしれません。

FloatingActionButton normalFab = (FloatingActionButton) findViewById(R.id.normal_fab);
normalFab.setRippleColor(Color.CYAN);

まとめ

  1. TextInputLayoutは、FloatingLabelを実現するためにEditTextをラップするLayoutクラスでした
  2. FloatingActionButtonは、色をカスタムするための便利メソッド複数用意されていました

AndroidNDKを含むプロジェクトをCircleCIでビルドする

標準的なAndroidプロジェクトのcircle.yml

2015/5/12現在では、公式サイトによると主要なAndroidSDKは、VMにプリインストールされているとのことです。 そのため、以下のような非常にすっきりしたYAMLファイルで、Androidプロジェクトをビルドすることが出来るようになっています。(テストは省略しています。)

machine:
  java:
    version: openjdk7
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assemble

もしプリインストールされたSDKに、使用したいものが無い場合だけアップデート処理を追記してあげればいいみたいです。

dependencies:
  pre:
    - echo y | android update sdk --no-ui --all --filter "package-name"

AndroidNDKを使用する場合のcircle.yml

公式によると、

We also preinstall the Android NDK; it can be found at $ANDROID_NDK.

とあるので、AndroidNDKもプリインストールされてるようです。 ところが、そのままAndroidNDKを使ったプロジェクトをビルドさせると、以下のようなエラーが出てNDKのタスクで失敗してしまいました。

> Building 2%NDK not configured.
> Building 2%  Download the NDK from http://developer.android.com/tools/sdk/ndk/.Then add ndk.dir=path/to/ndk in local.properties.
> Building 2%  (On Windows, make sure you escape backslashes, e.g. C:\\ndk rather than C:\ndk)

失敗する原因は、$ANDROID_NDKではAndroidNDKのホームディレクトリとして認識出来ないことでした。 そのため以下のように、$ANDROID_NDK_HOMEにプリインストールされているAndroidNDKを指定するとうまくいきました。($ANDROID_NDK_HOMEに言及した元ソースは、思い出せませんでした…)

machine:
  java:
    version: openjdk7
  environment:
    ANDROID_NDK_HOME: /usr/local/android-ndk
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assemble

ビルド中の突然死を予防するcircle.yml

特に具体的なエラーを吐くことなく、ビルドが失敗するケースがありました。 主な対策としては、下記2点が有効なようです。

  1. JVMのHeapSizeを制限する
  2. PreDexingを無効化する
machine:
  java:
    version: openjdk7
  environment:
    ANDROID_NDK_HOME: /usr/local/android-ndk
    JAVA_OPTS: "-Xmx2048m -XX:MaxPermSize=1024m"
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assembleDogfood -PdisablePreDex

JVMのHeapSizeを制限する

JAVA_OPTS: "-Xmx2048m -XX:MaxPermSize=1024m"

ある程度の規模のプロジェクトになると、仮想マシンのメモリを食い尽くしてしまうことが多々あるので、Gradleが使えるリソースに制限をかけてあげると安定します。

PreDexingを無効化する

これは公式サイトのDisable Pre-Dexing to Improve Build Performanceの部分に、詳細が書かれています。 その部分を一部引用すると、以下のように書かれています。

Because CircleCI always runs clean builds this pre-dexing has no benefit; in fact it makes compilation slower and can also use large quantities of memory. We recommend disabling pre-dexing for Android builds on CircleCI.

CircleCIでビルドするときは、PreDexingを無効化してねということらしいです。 やり方は、GradleAndroidPluginのサイトに載ってます。(上記CircleCIのサイトからもリンクが貼られてました。)

まずプロジェクトの直下にあるbuild.gradleに、以下のGradleタスクを追加します。

project.ext.preDexLibs = !project.hasProperty('disablePreDex')

subprojects {
  project.plugins.whenPluginAdded { plugin ->
    if ("com.android.build.gradle.AppPlugin".equals(plugin.class.name)) {
      project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
    } else if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
      project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
    }
  }
}

次にcircle.ymlでビルドコマンドを叩く箇所に、dsablePreDexプロパティを付与してあげます。 これでpreDexタスクは実行されなくなります。

./gradlew clean assemble -PdisablePreDex

参考にさせて頂いたサイト

まとめ

AndroidNDKを使う場合は、$ANDROID_NDK_HOMEの設定が必要でした。 JVMのHeapSize制限は必要に応じて使えばいいけど、PreDexingの無効化はやっておいたほうがよさそうです。

またcircle.ymlの書き方は、まだまだ変わっていきそうなので、定期的に公式サイトをチェックした方がよさそうだなと思いました。 この記事では触れませんでしたが、エミュレーターの起動やテストまわりも書きやすくなってました。

自分史上最高に英語学習に取り組んでみようとしてる

今年に入ってから英語でコニュニケーション出来ないために、「ぐぬぬ…」となる出来事が立て続けに起こりました。仕事で1回、コミュニティ活動で1回、あと勉強会でも1回ありました。

分からない単語は調べながら、そこそこ英語のドキュメントが読めれば十分だと思ってた時期が僕にもありました。

きっと多くの人が同じような感じだとも思ってました。 ところがそうでは無いことも、今年になって急激に知ることとなってしまったんです。

知り合いのエンジニアの多くは海外のエンジニアと英語でコニュニケーションを取ってるし、海外のmeetupでLTもするし、同僚のディレクターは僕の隣で某外資系企業の人と英語でコニュニケーション取ってるんです。

これでもか!ってくらい、英語が話せないことに劣等感を感じまくりました。もうこれは、本気で英語に取り組むラストチャンスかな、という気持ちになりました。

しばらく英語学習系のアプリを試したり、PCサイトやPodcastなどなど手を出してみたのですが、いまいちこのまま進んでいいのか自信が持てない日が続いてました。

そんな時、先日「英語上達完全マップ」にたどり着きました。コンテンツを読んでいたら、ずっともやもやしてたものがスッキリした気持ちになり、これだと思いました。

具体的には、「音読」と「瞬間英作文」を柱とした基礎力の強化を重視している学習法を詳細に解説してくれている点に、これは実践してみたいと感じることが出来ました。

いろいろと情報収集して、このへんを参考にしつつ第一弾として3冊の参考書を買いました。

買ったのは以下の3冊です。基礎の基礎から勉強し直そうと思います。 秋頃には一度TOEICを受けてみる予定です。

くもんの中学英文法―中学1?3年 基礎から受験まで (スーパーステップ)

くもんの中学英文法―中学1?3年 基礎から受験まで (スーパーステップ)

みるみる英語力がアップする音読パッケージトレーニング(CD BOOK)

みるみる英語力がアップする音読パッケージトレーニング(CD BOOK)

どんどん話すための瞬間英作文トレーニング (CD BOOK)

どんどん話すための瞬間英作文トレーニング (CD BOOK)

DroidKaigiで発表してきたこと+ちょっと追記

4/25(土)にDroidKaigiという、Androidエンジニア向けのカンファレンスに参加しました。 今回は久しぶりに運営側として参加したり、発表もさせて頂きました。

運営側視点では、圧倒的当事者意識の体現者である @hotchemi さんが、素晴らしいまとめを書いてくださっているので、ここでは発表した内容の補足や追記をしたいと思います。

DroidKaigiの運営進め方共有(ギークに憧れて)

発表したこと

DroidKaigi当日は、会場Bの方で「JellyBeanとKitkatで実現するマテリアルデザイン」というタイトルで発表しました。 3日前にアップデートされたSupportLibrary-v22.1の中で、主にAppCompat-v7の変更点に触れながら、SupportLibraryを使ったマテリアルデザインの実現方法を解説しました。

4/22日の時点で既に7割ほど出来ていた資料でしたが、SupporLibraryが22日朝に大きくアップデートされたため、急遽一から資料を作り直すことにしたという貴重な体験が出来ました。

結果、「最新情報をキャッチアップした内容が聞けて良かった」という感想を頂く事が出来たので、書きなおしてみて良かったです。 ただ、何を資料に載せるか悩みながら書いたので、今振り返るといろいろと不足していたなと感じる部分が多々あります。

また、発表中にv22.1.1というマイナーアップデートが観測されるというミラクルも起きたので、その部分についても補足したい欲が出てきました。ということで、ここからは上記資料で書ききれなかったことを追記していきます。

1. 新しいInterporatorについて

資料の中で実際にアニメーションさせた動画を載せたのは良かったものの、新しいInterporatorはどういう良さがあるのかきちんと説明出来てないなと思いました。

公式ではAnimation > Authentic motionにて

To draw attention to an object for a specific purpose, or to add character to an animation, vary its change in speed when starting and stopping.

とあります。

また日本語でもこちらに

ゆっくりと始まり、ゆっくりと終わる典型的な遷移とは異なり、マテリアル デザインにおけるオブジェクトは素早く動き始め、ゆっくりと最終位置につきます。(中略)結果としてユーザーは遷移動作が終わるのを待つ必要がなくなり、モーション化によるマイナス効果は最小限に抑えられます。

とあります。

つまりは、アニメーションを見せつつ、ユーザーがその変化から受けるネガティブな面を、極力小さくするということのようです。微妙な違いではあるけど、Lollipop端末を触ってみるとその違いは大きいのが良く分かります。

とても理にかなっているなと思うので、Kitkat以下でも同様の表現が出来るようになったのは嬉しいですね。

2. v22.1.1について

DroidKaigiでの発表が終わる(16:30くらい)頃、数名の方から「v22.1.1が出たみたいだよ!」と声を掛けられました。会場設営のため朝早く脳が活動低下してきていたので、最初意味が分かりませんでした。

しばらくして調べてみたら、主にbug fixesがメインっぽかったのでホッとしました。主にRenderScriptまわりのbug fixesのようでした。

差分について、最初に書いた内容が誤りだったため訂正します。(4/29追記)

指摘くださったのは、DroidconMontrealでJake神にどら焼きを届けるという偉業を成し遂げた zaki50 さんです。ありがとうございました!

ソースのDiffを取ると分かるとのことだったので、取ってみました。

$ diff support-v4-22.1.0-sources.src/android/support/v4 support-v4-22.1.1-sources.src/android/support/v4
diff --git a/support-v4-22.1.0-sources.src/android/support/v4/view/LayoutInflaterCompatHC.java b/support-v4-22.1.1-sources.src/android/support/v4/view/LayoutInflaterCompatHC.java
index ee1a413..06e72f4 100755
--- a/support-v4-22.1.0-sources.src/android/support/v4/view/LayoutInflaterCompatHC.java
+++ b/support-v4-22.1.1-sources.src/android/support/v4/view/LayoutInflaterCompatHC.java
@@ -49,7 +49,16 @@ class LayoutInflaterCompatHC {
         final LayoutInflater.Factory2 factory2 = factory != null
                 ? new FactoryWrapperHC(factory) : null;
         inflater.setFactory2(factory2);
-        forceSetFactory2(inflater, factory2);
+
+        final LayoutInflater.Factory f = inflater.getFactory();
+        if (f instanceof LayoutInflater.Factory2) {
+            // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21).
+            // We will now try and force set the merged factory to mFactory2
+            forceSetFactory2(inflater, (LayoutInflater.Factory2) f);
+        } else {
+            // Else, we will force set the original wrapped Factory2
+            forceSetFactory2(inflater, factory2);
+        }
     }

     /**

発表でもリンクを貼ったGoogle+の投稿のコメント(4/25 IanLake氏)に、

FYI, 22.1.1 is available now with the fix for widget tinting inflated from fragments. Thanks for the reports everyone!

ともありました。(確認不足でした。すみません。)

3. support.design.widgetパッケージ?

すみません、これは完全に脱線した内容ですが、2について調べている過程でSupportLibraryのリポジトリを見ていたら、support.design.widgetという見慣れないパッケージがありました。 中を見るとFloatingActionButton.javaが存在してました。他にも、NavigationDrawerView.javaやTabLayout.javaがあります。

f:id:androhi:20150428012534p:plain

気付かなかっただけかなと思い、ローカルにDLしたSupportLibrary-v22.1.1を見たけど、やっぱりありませんでした。もしかしたら、ついに公式のFloatingActionButtonなどがリリースが近いのかも。

4. AppCompatDelegateについて

Google@yuichi_arakiさんの、SupportLibraryでもPreferenceActivityが使えるようになった、というツイートを見かけたので確認してみました。

AppCompatではv22.1でAppCompatDelegateという抽象クラスが追加されてます。このクラスを使えば、どんなActivityクラスにもAppCompatの機能を継承することが出来るようです。

この仕組みを使って、PreferenceActivityにAppCompat(ActionBar的な機能)を追加できるということでした。詳細はAppCompatPreferenceActivity.javaというサンプルコードがあるので、それを見れば一目瞭然でした。便利ですね、AppCompatDelegate。

SupportLibrayのサンプルコードは、Platformのサンプルと同様に、SDK Manager経由で取得します。Extrasの中にあるAndroid Support RepositoryAndroid Support Libraryを最新にすると、以下の手順でサンプルプロジェクトを見ることが出来ます。

今回見たいAppCompatPreferenceActivityは、Support-v7のサンプルなのでSupport7Demosというプロジェクトに入っています。

  1. SDK ManagerでSupportLibraryのv22.1.1をDLする
  2. AndroidStudioでFile > New > ImportProject...を選択する
  3. [sdk]/extras/android/support/samples/Support7Demosを選択する
  4. ライブラリの依存関係が未設定なのでapp/build.gradleに以下を追加する
dependencies {
    compile 'com.android.support:appcompat-v7:22.1.1'
    compile 'com.android.support:cardview-v7:22.1.1'
    compile 'com.android.support:gridlayout-v7:22.1.1'
    compile 'com.android.support:palette-v7:22.1.1'
    compile 'com.android.support:mediarouter-v7:22.1.1'
    compile 'com.android.support:recyclerview-v7:22.1.1'
}

f:id:androhi:20150428012625p:plain

まとめ

発表のまとめの最後に、今年のGoogle I/OがMaterialDesign発表後の最初のI/Oなので、今後に関する何かしらの発表があったらいいなと言いましたが、今回新たなパッケージを見つけたり、SupportLibraryは今後も進化していきそうなので、楽しみな流れになってきたと思います。

日本の通信キャリアから発売されてるAndroid端末は、いまだにLollipopへのアップデートが全くの未定です。SupportLibraryによってKitKatでも、少ない労力で適切にMaterialDsignのメリットを活かすことが出来るようになればいいなと思いました。

Androidアプリ開発にRxJavaを導入したいと思って参考にしたサイト

まとめが欲しかったのでまとめました。

RxJavaの存在は知っていたけど、学習コストの高さから尻込みしている方も多いと思います。僕もそうでした。正直ドヤ顔するためのライブラリだろうと思ってた時期さえありました。

ところがAndroidアプリ開発にRxJavaを導入することで得られる、さまざまなメリットを知るようになって考えが変わっていきました。とはいえ学習コストが高いのは事実です。 そもそもReactiveXの世界が理解できないと、サンプルコードを見ても全くしっくりきませんでした。そんな中で以下のサイトのおかげでようやく自分でも手を動かせるようになってきました。

他にも素晴らしいサイトがあると思います。ご存知の方は教えていただけると嬉しいです。

概要とかプログラミング・パラダイムとか

サンプルコードから学ぶ

多言語だけど雰囲気をつかめる

本家

DroidKaigiで発表してみませんか!

DroidKaigiというAndroid技術者のためのカンファレンスが、2015年4月25日(土)に開催されます。

先日、実行委員会の中で(微力ながら僕もこのカンファレンスの実行委員をしています)、「もっとたくさんのエンジニアの方に発表の応募をしてもらおう!」 という話しになり、実行委員会でブログを書くことにしました。

この記事はその中の一つです。

DroidKaigiですが、カンファレンスの主旨としては以下の2点に尽きるかと思います。(サイトからの引用です。)

  • エンジニアが主役のAndroidカンファレンスです
  • Android技術情報の共有とコミュニケーションを目的に

普段からアプリ開発に関連する勉強会は多々ありますが、人気のテーマだとすぐ定員になってしまいますし、時間も限られているので割と特定の分野であったり、別のプラットフォームの話しが混ざっていたりもすると思います。

そんな中でDroidKaigiではAndroidというプラットフォームに絞りつつ、いろいろなテーマのセッションを1日の中で聞くことが出来るカンファレンスになる予定です。

2月25日(水) までは、発表してくれる方の応募を受け付けています。

最新技術や人気の技術に関するものは人目を引くのかもしれませんが、エンジニアのみなさんが毎日の中で経験したことや調べたこと、自らの手で書いたコードが何より重要な技術情報だと思っています。

それらをぜひDroidKaigiで他のエンジニアに共有して頂けると、とても有意義なカンファレンスなる気がします。というか、実行委員のメンバーはそれを楽しみに開催に向けて頑張っています。

もし興味を持たれた方は、こちらから詳細を確認できますので応募してみて下さい。 DroidKaigi Call For Papers