phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

【Android】MaterialShowcaseViewライブラリでチュートリアルを実装する

MyCurationの1.2.1でチュートリアルを追加しました。というのもインストールされてもすぐアンインストールされているようで、説明が足りなかったかな・・・と思い始めたためです。 実装を自分でやってもよかったのですが、デザイン的なセンスがないのと、ある程度テンプレート化されたものがあるのではということでライブラリを探しました。 今回はMaterialShowcaseViewというライブラリを使ってチュートリアルを実装してみました。

f:id:phicdy:20170625104753g:plain

設定

GitHubのページ通りにbuild.gradleを編集

プロジェクトのbuild.gradle

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

アプリのbuild.gradle

dependencies {
  compile 'com.github.deano2390:MaterialShowcaseView:1.1.0@aar'
}

使い方

MaterialShowcaseViewでは特定のViewにハイライトを当ててチュートリアルを行います。 実装できるパターンとしては、(1)単純に追加ボタンなど1つだけを説明するパターンと、(2)ボタン1を押して次にボタン2を押して・・・といったように連続して説明をするパターンがあります。

MyCurationでは最初のRSS購読のチュートリアルを入れました。 RSS購読の流れとしては

  1. メイン画面からToolbarの「+」ボタンを押し、検索画面に行く(メイン画面)
  2. RSSを購読するサイト検索する(検索画面)
  3. サイトを開いたら追加ボタンを押す(検索画面)

です。

まずメイン画面で実装した単純に追加ボタンなど1つだけを説明するパターンです。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Menu settings...

    // Start tutorial at first time
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            View view = findViewById(R.id.add);
            new MaterialShowcaseView.Builder(TopActivity.this)
                    .setTarget(view)
                    .setContentText(R.string.tutorial_go_to_search_rss_description)
                    .setDismissText(R.string.tutorial_next)
                    .singleUse(SHOWCASE_ID)
                    .setListener(new IShowcaseListener() {
                        @Override
                        public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) {

                        }

                        @Override
                        public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) {
                            goToFeedSearch();
                        }
                    })
                    .show();
        }
    });
    return true;
}

Builderパターンを使ってMaterialShowcaseView.Builderを作成していきます。今回はToolbar上の「+」ボタン(R.id.add)にハイライトを当てたかったのでonCreateOptionsMenu()の中でチュートリアルを作成します。 まずsetTarget()でハイライトするViewを指定します。次にチュートリアルの説明文と、チュートリアルを消す部分のテキストを設定します。singleUse()でIDを指定することで初回のみチュートリアルを表示し、同じIDのチュートリアルは今後表示しないように設定できます。今回はチュートリアルが閉じたときに次の画面(検索画面)に移りたかったので、setListener()でIShowcaseListenerをセットし、チュートリアルが閉じられたときに呼ばれるonShowcaseDismissed()で次の画面に飛んでいます。設定が終わったら最後にshow()でチュートリアルを表示します。

使ったメソッドのまとめです。

メソッド 説明
setTarget(View view) ハイライトするViewを指定
setContentText(int resource) 説明文を指定
setDismissText(int resource) タップして閉じる部分の文を指定
singleUse(String showCaseId) 1度だけの表示を管理するためのID。これを設定するとアンインストールしない限りは同じIDのチュートリアルは表示されない
setListener(IShowcaseListener listener) リスナの設定。表示時、消えた時のハンドリング
show() 表示する

次に検索画面で実装した連続して説明をするパターンです。

@Override
public boolean onCreateOptionsMenu(Menu menu) { 
    // Menu settings...

    // Start tutorial at first time
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            View view = findViewById(R.id.search_rss);
            ShowcaseConfig config = new ShowcaseConfig();
            config.setDelay(500); // half second between each showcase view

            MaterialShowcaseSequence sequence = new MaterialShowcaseSequence(FeedSearchActivity.this, SHOWCASE_ID);
            sequence.setConfig(config);

            // Search tutorial
            sequence.addSequenceItem(
                    new MaterialShowcaseView.Builder(FeedSearchActivity.this)
                            .setTarget(view)
                            .setContentText(R.string.tutorial_search_rss_description)
                            .setDismissText(R.string.tutorial_next)
                            .build()
            );

            // Add button tutorial
            sequence.addSequenceItem(
                    new MaterialShowcaseView.Builder(FeedSearchActivity.this)
                            .setTarget(fab)
                            .setContentText(R.string.tutorial_add_rss_description)
                            .setDismissText(R.string.tutorial_close)
                            .setDismissOnTouch(true)
                            .build()
            );

            // Open software keyboard if tutorial already finished
            if (sequence.hasFired()) {
                searchView.setIconified(false);
            }

            sequence.start();
        }
    });
    return true;
}

今度はMaterialShowcaseSequenceというクラスのインスタンスを作り、MaterialShowcaseViewのインスタンスを追加していってチュートリアルの流れを作ります。

さきほどと同様にBuilderパターンでMaterialShowcaseView.Builderを作っていき、今回は最後にbuild()を呼ぶことでMaterialShowcaseViewを作り、MaterialShowcaseSequenceに追加します。これを繰り返すことでチュートリアルを表示→閉じる→チュートリアルを表示→閉じる→・・・と流れを作れます。作り終わったらstart()でチュートリアルを始めます。

注意した点

Toolbar上のViewがNullになる

onCreateOptionsMenu()の中でViewをfindViewById()で取るとNullが返ってきて落ちるという現象がありました。Handler#post()を使うことで遅延を発生させてこれを回避しました。

参考

How To Get Action View Of Menu Item?

チュートリアル中にキーボードが開かないようにする

検索画面では開いたときにすぐキーボードが開くようにsearchView.setIconified(false)を呼んでいたのですが、チュートリアル中は邪魔です。MaterialShowcaseSequence#hasFired()でチュートリアルが既に終わったかを判定できるので、チュートリアルでないときのみキーボードを開くようにしました。

// Open software keyboard if tutorial already finished
if (sequence.hasFired()) {
    searchView.setIconified(false);
}

終わりに

MaterialShowcaseViewを使うことでかなり簡単にチュートリアルを作成しました。さくっと作れるので、凝ったチュートリアルが必要でなければこれで十分かなと思います。以上です。