Androidの最近のブログ記事

Android L Developer Preview、Material Design で追加された新ウィジェット(※1)である RecyclerView を使用してみました。

 

RecyclerView を使用すると、アイテムのサイズが固定長の場合に、従来よりも良いパフォーマンスが得られる(※2)ほか、

アイテムの追加、削除時などのアニメーション(※3)についても、デフォルトで利用することができます。

 

ちなみに RecyclerView のコードは、現時点(2014/7/11)では見れなかったのですが、前身のコード?っぽいのは、

sdk / sources / android-20 / android / support / v7 / widget / RecyclerView.java

にありました(約5,700行)。

(ソースコード読んで、notifyItemInserted() や notifyItemRemoved() の存在に気づくなど。。。)

 

以下、

従来の ListView & BaseAdapter で実装した場合のソースコードと、

RecyvlerView & RecyvlerView.Adapter で実装した場合のソースコードを貼っておきました。

文章で書くよりもコードを見た方が分かり易いと思いますので、コード内の番号をヒントに比較してみてください。

 

BaseAdapter(従来)のコード

public class SampleAdapter1 extends BaseAdapter {
    private LayoutInflater mLayoutInflater;
    private ArrayList<String> mDataList;

    // コンストラクタは、RecyclerView.Adapter でも変更なし
    public SampleAdapter1(Context context, ArrayList<String> dataList) {
        super();
        mLayoutInflater = LayoutInflater.from(context);
        mDataList = dataList;
    }

    // 4.RecyclerView.Adapter の場合、getItemCount() に書き換える
    @Override
    public int getCount() {
        return mDataList.size();
    }

    // RecyclerView.Adapter では不要
    @Override
    public Object getItem(int position) {
        return mDataList.get(position);
    }

    // RecyclerView.Adapter では不要
    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {

            // 1.RecyclerView.Adapter の場合、この部分を onCreateViewHolder() で実装する
            // ViewHolder の引数には、インフレートしたビューを渡すように変更する
            convertView = mLayoutInflater.inflate(R.layout.list_item, parent, false);
            viewHolder = new ViewHolder();

            // 2.RecyclerView.Adapter の場合、この部分を ViewHolder のコンストラクタ内で実装する
            viewHolder.text = (TextView) convertView.findViewById(R.id.text);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // 3.RecyclerView.Adapter の場合、この部分を onBindViewHolder() で実装する
        String data = (String) getItem(position);
        viewHolder.text.setText(data);

        return convertView;
    }

    static class ViewHolder {
        TextView text;
    }
}

 

RecyvlerView.Adapter に書き換えた場合のコード

public class SampleAdapter2 extends RecyclerView.Adapter<SampleAdapter2.ViewHolder> {
    private LayoutInflater mLayoutInflater;
    private ArrayList<String> mDataList;

    public SampleAdapter2(Context context, ArrayList<String> dataList) {
        super();
        mLayoutInflater = LayoutInflater.from(context);
        mDataList = dataList;
    }

    @Override
    public SampleAdapter2.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 1
        View v = mLayoutInflater.inflate(R.layout.list_item, parent, false);
        ViewHolder viewHolder = new ViewHolder(v);
        return viewHolder;
    }

    // 4
    @Override
    public int getItemCount() {
        return mDataList.size();
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // 3
        String data = (String) mDataList.get(position);
        holder.text.setText(data);
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView text;

        public ViewHolder(View v) {
            super(v);
            // 2
            text = (TextView) v.findViewById(R.id.text);
        }
    }
}

 

ListView(従来)のコード

ListView listView = (ListView) view.findViewById(R.id.listview);

// アダプターの設定(mDataList は、ここでは ArrayList<String>)
listView.setAdapter(new SampleAdapter1(getActivity(), mDataList));

 

RecyvlerView に書き換えた場合のコード

RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);

// コンテキスト:Activity内ではthis、Fragment内ではgetActivity()など
recyclerView.setLayoutManager(new LinearLayoutManager(コンテキスト));
recyclerView.setHasFixedSize(true); // アイテムは固定サイズ

// アダプターの設定(mDataList は、ここでは ArrayList<String>)
recyclerView.setAdapter(new SampleAdapter2(getActivity(), mDataList));

 

ListView(従来)のリソース

<ListView
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

 

RecyvlerView に書き換えた場合のリソース

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />

 

RecyvlerView.Adapter でデフォルトアニメーションを使用する例

// アイテム追加後、notifyItemInserted(index)を呼び出す(ここでは最後に追加)
recyclerView.getAdapter().notifyItemInserted(mDataList.size() - 1);

// アイテム削除後、notifyItemRemoved(index)を呼び出す(ここでは先頭を削除)
recyclerView.getAdapter().notifyItemRemoved(0);

 

備考

※1:N5だと、従来のListView と動作比較してみたところ、目に見えてわかるような差は体感できませんでした

※2:Material Design の追加ウィジェットは2つだけで、もう一方は以前紹介した CardView

※3:アニメーションは RecyclerView.ItemAnimator で自作したものへ置き換え可能

Android L(API Level 21)のViewAnimationUtils.createCircularRevealメソッドを使用すると、

ビューに対して広がる(/またはその逆の)円状のクリッピングを適用したアニメーション効果を得る事ができます(表現困難...)。

 

サンプル動画

※画面右端中央やや下のMapアイコンをタップしてビューを切り替えています

 

切り替え前後のビュー(参考)

before.png after.png

 

サンプルソースコード

// Revealアニメーションを適用したいビュー
final View animationTarget = findViewById(R.id.information_container);

int cx = (view.getLeft() + view.getRight()) / 2;
int cy = (view.getTop() + view.getBottom()) / 2;
float radius = Math.max(animationTarget.getWidth(), animationTarget.getHeight()) * 2.0f;

if (animationTarget.getVisibility() == View.INVISIBLE) {
    // 切り替えたいビューが非表示の場合(最初は、こっちを通る)

    // これから表示するビューを表示する(アニメーション開始時には円の半径が0なので実質見えない)
    animationTarget.setVisibility(View.VISIBLE);

    // 円状のクリッピングを適用したアニメーションを開始する
    // 円は(数百ミリ秒で)あっという間に大きくなります
    ViewAnimationUtils.createCircularReveal(
            animationTarget, // アニメーション対象のビュー(これから表示したいビュー)
            cx, cy, // アニメーションの原点(=円の中心)
            0,      // アニメーション開始時の円の半径
            radius  // アニメーション終了時の円の半径
    ).start(); // アニメーション開始
} else {
    // 切り替えたいビューが表示済の場合

    // 円状のクリッピングを適用したアニメーションを開始する
    // 円は(数百ミリ秒で)あっという間に小さくなります
    ValueAnimator reveal = ViewAnimationUtils.createCircularReveal(
            animationTarget, // アニメーション対象のビュー(これから表示したいビュー)
            cx, cy, // アニメーションの原点(=円の中心)
            radius, // アニメーション開始時の円の半径
            0       // アニメーション終了時の円の半径
    );
    // アニメーション終了時に呼び出されるリスナを設定
    reveal.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            // アニメーション終了時に対象のビューを非表示にする
            animationTarget.setVisibility(View.INVISIBLE);
        }
    });
    reveal.start(); // アニメーション開始
}

※デモアプリのソースコードは、https://github.com/romainguy/google-io-2014

 

Android L(API Level 21)のandroid.support.v7.graphics.Palette クラスを使用すると、指定した画像から、画像に使われている色を解析し、いい感じのパレット(6色分の色値)を計算してくれるようです。

取得した色をテキストやグレーアイコンに適用することで、画像にマッチした配色ができそうです(例えば、下図のフラミンゴだと、フラミンゴの色から、ピンク、赤、暗めの紺色の色などが Palette クラスから返される)。

 

Palette 呼び出し方

Palette palette = Palette.generate(photo); // photo は Bitmap

// get○○○Color()で任意のパレット色が取得できる

// VibrantColor
palette.getLightVibrantColor().getRgb();    // 明るい
palette.getVibrantColor().getRgb();
palette.getDarkVibrantColor().getRgb();     // 暗い

// MutedColor
palette.getLightMutedColor().getRgb();      // 明るい
palette.getMutedColor().getRgb();
palette.getDarkMutedColor().getRgb();       // 暗い

 

Google I/O 2014 Material Witness で紹介されていたデモアプリ

1_PaciflcaPier.PNG 2_PinkFlamingo.PNG

3_AntelopeCanyon.PNG 4_LonePine.PNG

※デモアプリのソースコードは、https://github.com/romainguy/google-io-2014

※キャプチャは、取得できるパレット色の名前と値を表示するように手を加えています

 

どんな風に色を選択しているか興味深く、Android L のソースコード公開が待ち遠しいです。

Android L Developer Preview で追加された UI 部品である CardView を試してみました。

 

動画

カードのふちが角丸(影つき)になっているのが見えますかね。。。

丸みは cardCornerRadius で指定するようです。

 

サンプルリソース

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="8dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="8dp">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="280dp"
            android:scaleType="centerCrop" />

    </android.support.v7.widget.CardView>

</LinearLayout>

 

あれっ???

角が丸いだけの View ???

 

(そうだ、yanzm 先生の Android Pattern Cookbook に載ってたカードビューをみてみよう)

 

Android Pattern Cookbook に載ってたカードビューのリソース

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/card_item_bg2"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="@dimen/thumbnail_height"
            android:contentDescription="@string/thumbnail"
            android:scaleType="centerCrop" />

    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="4dp"
        android:background="@drawable/card_shadow" />

</LinearLayout>

あれっ???

yanzm せんせいのとコード量、ほとんど変わらないw

CardView さん...

きっと、ボクが何か勘違いしているに違いない...

 

あわせて読みたい

Android Support Library, revision 19.1.0SwipeRefreshLayout が追加されました。

SwipeRefreshLayout とは、下方向のスワイプジェスチャーを検出してプログレスを表示するためのもので、

アプリの情報更新手段として使用できます。

類似の機能は、これまでは各アプリ独自に実装していたと思いますが、Support Library を使用することで、簡単に使用できます。

※2014/3/29追記:Effective Android

 「第4章 引っ張って更新するPullToRefresh UIを使ったListViewを作る」の方がおすすめだよ(みんなには内緒だよ!)

 

SwipeRefreshLayout

 

使い方

1. SwipeRefreshLayout#setOnRefreshListener() を呼び出し、スワイプ時のリスナを登録する

2. スワイプ時に呼び出されるリスナ SwipeRefreshLayout.OnRefreshListener#onRefresh() で更新中の処理を行う

3. 更新後、SwipeRefreshLayout#setRefreshing(false) でプログレスを終了させる

 

※a. SwipeRefreshLayout#setRefreshing(true) を呼び出す事で、メニューアイテム押下時など、

 スワイプ以外の任意のトリガでもプログレスを開始できる

※b. SwipeRefreshLayout#setColorScheme() を呼び出す事で、プログレスの色もカスタマイズできます

 

サンプル

サンプルアプリは、sdk / extras / android / support / samples / Support4Demos にありました(上記動画)。

以下、Support4Demos 内のソースコード(Apache License, Version 2.0)の抜粋です。

 

サンプルリソース(swipe_refresh_widget_sample.xml)

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_refresh_widget"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/content"/>
</android.support.v4.widget.SwipeRefreshLayout>

 

サンプルソースコード(SwipeRefreshLayoutActivity.java)

public class SwipeRefreshLayoutActivity extends Activity implements OnRefreshListener {
    public static final String[] TITLES =
    {
            "Henry IV (1)",
            "Henry V",
・・・省略・・・
             "Othello",
            "King Lear"
    };
    private SwipeRefreshLayout mSwipeRefreshWidget;
    private ListView mList;
    private Handler mHandler = new Handler();
    private final Runnable mRefreshDone = new Runnable() {

        @Override
        public void run() {
            // 3. プログレスを終了させる
            mSwipeRefreshWidget.setRefreshing(false);
        }

    };
    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.swipe_refresh_widget_sample);
        mSwipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);
        mSwipeRefreshWidget.setColorScheme(R.color.color1, R.color.color2, R.color.color3,
                R.color.color4);
        mList = (ListView) findViewById(R.id.content);
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1, TITLES);
        mList.setAdapter(arrayAdapter);
        // 1. スワイプ時のリスナを登録する(implements OnRefreshListener)
        mSwipeRefreshWidget.setOnRefreshListener(this);
    }

    @Override
    public void onRefresh() {
        // 2. スワイプ時に呼び出される、ここで更新中の処理を行う
        refresh();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.swipe_refresh_menu, menu);
        return true;
    }

    /**
     * Click handler for the menu item to force a refresh.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        final int id = item.getItemId();
        switch(id) {
            case R.id.force_refresh:
                // a. メニューアイテム押下時など、スワイプ以外の任意のトリガでもプログレスを開始できる
                mSwipeRefreshWidget.setRefreshing(true);
                refresh();
                return true;
        }
        return false;
    }

    private void refresh() {
        // このアプリでは更新処理のダミーとして1秒後に更新終了処理を呼び出している
        mHandler.removeCallbacks(mRefreshDone);
        mHandler.postDelayed(mRefreshDone, 1000); // 3000にすると3秒間プログレスが表示されるよ
    }
}

 

あわせて読みたい

cookbooks.JPG

インプレスジャパン様から『Android Pattern Cookbook』をちょうだいいたしましたので紹介させていただきます。

 

Android Cookbook シリーズ第三弾となる今回は、待望のフルカラー、288ページで、本日 2014年3月20日(木)発売!

Navigation Drawer から カスタムビュー まで、いま流行の UI を実装する方法が解説されています。

1.2-2s.PNG 1.5-2s.PNG 2.6s.PNG 7.1s.PNG

特に第7章は、

  • カードUI
  • ショーケース
  • スワイプオフできるリスト
  • ヘッダーが残るリスト
  • スクロール位置に応じて透明度が変わるActionBar
  • FastScroll + インデックスラベル
  • ログイン画面
  • オリジナルのプログレス
  • パターンロック
  • ドラッグ&ドロップコンテキストメニュー
  • 下にスワイプして更新

など、他では読む事ができない貴重な情報が詰まっており、非常にお買い得な内容になっていると思います。

この本を読めば、長らく Android 開発とはご無沙汰状態なワタクシでも、

最近の Google+、Facebook、Feedly、Gmail のような UI を持つアプリを実装できそうです\^^/

 

サンプルアプリ

AndroidPatternCookbook.PNG

本書のデモアプリは、以下のリンク先 (Google Play)で公開されています。

https://play.google.com/store/apps/details?id=yanzm.products.patterncookbook

以下にデモアプリ「第4章 ViewPager」の一部を録画しましたので、参考にしてみてください^^

 

サンプルソースコード

本書で解説されているソースコードは、(近いうちに?)インプレスさんサイトからダウンロードできます。

以下は、ActionBar の背景を(コードで)グラデーションするリソースの抜粋。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="270"
        android:endColor="@color/main_color_dark"
        android:startColor="@color/main_color_dark"
        android:type="linear" />
</shape>
action_grad.png

 

おわりに

やんざむさん曰く、Android Pattern Cookbook は、書籍制作にあたり、Re:VIEW を使用されているそうです。

Re:VIEW による美しい仕上がり、、、凄い!凄いよ、ほむらちゃん!

また、2014年3月21日(金)には、Android Bazaar and Conference 2014 Spring が開催されます。

当日は、『Android Pattern Cookbook』だけでなく、てくぶの『Effective Android』、

のぶさとさん監修の『Smashing Android UI』など、Android関連書籍の販売会もあるようですので、

当日参加される方は、バザールのインプレスさんブース(え3)で書籍を手に取って確認してみてください!

(うわさでは、サイン会もある!?かも。。。裏山。。。)

 

あわせて読みたい

 

※本エントリの内容は、2014年3月20日時点のものです

cover.png

Android 界の(元)Flappy Bird 王の adakoda です。

Android 界の シゲちゃんこと「しげむら こうじ」さんから、

Android SDK ポケットリファレンス』本をちょうだいいたしましたので紹介させていただきます。

 

書籍の情報(技術評論社)

  • 書籍案内・・・概要/目次
  • サポートページ・・・サンプルコードダウンロード(Gitがわからない初心者の方でもzipで一括DL可)
  • サンプルソース・・・GitHubソースコード
  • 対象読者=初級者〜中級者(中級向けの内容は ActionBar 、support.v○ 系、Google Map v2など)
  • ページ数・・・約500ページくらい

 

書籍の内容

技術評論社のポケットリファレンス本ということで、

やりたいこと(目的)から APIの使い方を見つけられる「逆引き系」の書籍となっています。

各目的毎の解説については、1〜数ページで構成されているため、必要なページ/興味あるページから読み進めることができます。

ソースコードの説明については、紙面の都合上、必要な部分の抜粋となっていますが、

すべてのソースコードは、インポート可能なプロジェクト形式で公開されているため、自分で実行して試すことができます。

 

本書を読むべき方

書籍の内容を読んでみた印象としては、「これから Android アプリの開発を初めてみたい!」

という方が一番フィットするのではないか思いました(※個人の感想です)。

使い方としては、以下の流れが良いと思います。

1. 気になる機能の解説に該当するページを斜め読みする

2. 該当のソースコードをダウンロード、実行し、動作を確認する

3. もういちど解説ページの詳細を読んで、値を変更するなど、ソースコードを変更し、変化を確認する

 

サンプルソース紹介

例えば、オーバースクロール時に何かをしたい時(ひっぱって情報の更新とか)のソースコードは、

shige0501 / android-sdk-pokeri / Chapter03 / ui_OverScroll

にあります。

※以下のソースコードは、公開されているソースコードの引用です

package net.buildbox.pokeri.ui_overscroll;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ListView;

public class OverScrollView extends ListView {
	private static final String TAG = "OverScrollView";
	
	public OverScrollView(Context context) {
		super(context);
		
		// オーバースクロールモードの設定
		setOverScrollMode(OVER_SCROLL_ALWAYS);
	}
	
	public OverScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);

		// オーバースクロールモードの設定
		setOverScrollMode(OVER_SCROLL_ALWAYS);
	}
	
	// オーバースクロールとしてonOverScrolledを呼び出す条件を指定
	@Override
	protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
			int scrollY, int scrollRangeX, int scrollRangeY,
			int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
		return super.overScrollBy(0, deltaY, 0, scrollY, 0,
				scrollRangeY, 0, 100, isTouchEvent);
	}
	
	// オーバースクロール時の処理
	@Override
	protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
			boolean clampedY) {
		// オーバースクロールの情報のデバッグ出力
		Log.d(TAG, "call onOverScrolled(): "
			+ "scrollX=" + scrollX
			+ ", scrollY=" + scrollY
			+ ", clampedX=" + clampedX
			+ ", clampedY=" + clampedY);
		super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
	}
}

 

おわりに

単著って大変ですよね。。。500ページとかレビューアも死ぬと思います。。。

Fragment のあたりは、さすがに少ないページ量だとちょっと説明が少なかったかも^^;。。。

ということで、次回は上級者向けお願いします^^;

ブログが「かけなび化」してるにも関わらず本を送っていただきありがとうございましたm_ _m

 

あわせて読みたい

PCからのキーボード操作に対応した Android Screen Monitor Ver.3.00 を公開しました。

 

asm3_large.PNG

競合する?別のツールでは昔から対応されていた機能なので、今さら・・・と言われるとショボーンなんですけど、それはそれで^^;

 

ちなみに、この機能は、@thorikawaさんが実装され、GitHub 上のリポジトリへPull Request(PR)していただいたものです。m_ _m

これまでの Google Code の方は、2014年1月以降ダウンロード機能がなくなる?らしいので、ソースコードは、GitHub へお引っ越しました。

branch は多数切っていますが、PR は development まで頂けると有り難いです(Mac版で初期表示のサイズがおかしいの絶賛放置してるし)。

 

 

もともと、このツールを作った時は、画面サイズが320x480(16bpp)の時代で、1フレームの転送サイズが300KBだったのですが、Nexus 5だと1920x1080(32bpp)なので7.9MB、さすがに使えないなー、というのが正直なところ。Galaxy Nexusの720x1280(32bpp)より大きい画面サイズでは使わないでね!

バッテリー残量の画像の確認って大変ですよね(約100枚あるし)。。。

放置したり、充電したり。。。

そんなあなたに朗報です。

以下のコマンドを実行すれば、電池残量0〜100%の画像をアニメーションで確認できます!

adb shell am broadcast -a com.android.systemui.BATTERY_LEVEL_TEST

※ただし、どのバージョンから対応しているかは未確認です^^

※ウィジェットの方は、タップしてあげないと反応してくれない場合もありました

 

詳しくは以下の動画(約40秒)を参照してください。

※ステータスバー左上と右上、そして、ホーム上の2つのウィジェットに注目!

 

このコマンドを使用すれば、開発者だけでなく、ユーザーも、購入したバッテリー残量アプリの表示確認が簡単にできますね!

screenrecordex.PNG

長時間録画できる screenrecord (名付けてscreenrecordex)を作りました。

といっても、ソースコードを1行変更して、最大録画時間を3分から60分に変更しただけですが^^;

 

試しに Shooting Star の画面を 1 時間録画してみたところ、約118MBのmp4ファイルが無事出力されました。

 

以下のサイトからビルド済バイナリをダウンロードできます。

※Nexus5(Androd 4.4)でのみ動作確認済です

 

ソースコード

※ライセンスは Apache License Version 2.0 です

 

FAQ

Q:「需要はあるの?」

A:「知りません。自分が使いたかっただけです。」

 

あわせて読みたい

1234567891011

2014年7月

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31