LoginSignup
76
66

More than 5 years have passed since last update.

YouTubeのAndroidアプリと同じ検索ビューを作ってみる

Posted at

Materialデザインに対応したYouTubeのアプリは、右上の検索アイコンをタップするとToolBarの背景色が変わってSearchViewっぽいものが表示されます。

activity_transition.gif

実際にどう実装しているかわかりませんが、同じ動きをするものを作ってみたのでメモしておきます。

SearchView & Fragment切り替え?

ぱっと見、menuのitemにSearchViewつけて実装してるのかなと思ったんですが、以下のような問題があって面倒くさそうでした。

SearchViewを使うと、普通のEditTextと同じテーマが適用される

普通にSearchViewを使うと、下線のついたMaterialデザインのEditTextが表示されます。YouTubeアプリではToolBar上にそのまま書けるような感じなので、これを実現するためにはSearchViewのStyleを作って、android:background="@android:color/transparent"を指定しなければなりません。

ToolBarの背景色を動的に変更しなければいけない

SearchViewが表示された時に、ToolBarの色を変更しなければなりません。変更するのは簡単なのですが、ちょっとFadeアニメーションがかかっていてこれを実現するのは面倒です。

ということで、この方法は却下しました。

ActivityTransitionを使う?

SdkVersion21から追加されたActivityTransitionsを使って、別Activityを表示する方法がよさそうでした。ActivityTransitionsについては、Y.A.M の 雑記帳にわかりやすく説明されています。

背景色を変えて検索EditViewを入れ子にしたToolBarを配置した別Activityを作り、android:windowEnterTransitionandroid:windowExitTransition@android:transition/fadeを指定しておけば、同じような動きをします。

ただ、ActivityTransitionsはAPI Level 21から有効なので、Android5.0未満では使えません。将来的にはこのやり方がよさそうですが、Android4以下の対応を考えて別の方法を取りました。

ActivityOptionsCompatを使う

ということで、ActivityTransitionsと同じような動きをAndroid4以下でも実現するようにしました。support-v4:21.0ライブラリのActivityOptionsCompatクラスを使います。
以下、実装手順を簡単にまとめます。

build.gradleのdependenciesを追加

以下のライブラリを使うので追加します。

build.gradle
dependencies {
    compile 'com.android.support:support-v4:21.0.0'
    compile 'com.android.support:appcompat-v7:21.0.0'
}

メインのActivityのツールバーに検索アイコンを追加

メインのActivityに検索アイコンを追加します。普通にmenuを追加すればよいです。

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

    <item
        android:id="@+id/action_search"
        android:icon="@drawable/ic_search_white_24dp"
        android:title="@string/search"
        app:showAsAction="always" />

</menu>

検索用のActivityを作る

検索用のActivityを作ります。toolbarの中に、検索EditTextを配置しています。

SearchActivity.java
public class SearchActivity extends ActionBarActivity {

    // ButterKnifeを使ってます。
    @InjectView(R.id.toolbar)
    Toolbar mToolbar;
    @InjectView(R.id.edit_search)
    EditText mEditSearch;

    // Activityの呼び出しメソッド
    public static void start(Activity activity) {
        Intent intent = new Intent(activity, SearchActivity.class);
        // ActivityOptionsCompatを使うと、ActivityTransitionsと同じようなアニメーションを実現できます。
        // ここではapp-compat-v7:21.0に入っているR.anim.abc_fade_inとR.anim.abc_fade_outを使っています。
        ActivityOptionsCompat options = ActivityOptionsCompat.makeCustomAnimation(
                activity, R.anim.abc_fade_in, R.anim.abc_fade_out);
        ActivityCompat.startActivity(activity, intent, options.toBundle());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_search);
        ButterKnife.inject(this);

        setSupportActionBar(mToolbar);
        initActionBar();

        KeyboardUtils.show(this, mEditSearch);
    }

    private void initActionBar() {
        // ToolBarの場合はもっとスマートなやり方があるかもしれません。
        ActionBar bar = getSupportActionBar();
        bar.setDisplayHomeAsUpEnabled(true);
        bar.setDisplayShowHomeEnabled(true);
        bar.setDisplayShowTitleEnabled(true);
        bar.setHomeButtonEnabled(true);

        // 矢印アイコンの色を変更しています。xmlで指定する方法があるかもしれません。
        final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
        upArrow.setColorFilter(getResources().getColor(R.color.grey600), PorterDuff.Mode.SRC_ATOP);
        bar.setHomeAsUpIndicator(upArrow);
    }

    // 略

    @Override
    public void finish() {
        super.finish();
        // ActivityOptionsCompatだけの指定だと、Activityを閉じる時にアニメーションが反映されなかったので、finish時に明示的に指定してあげます。
        overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out);
    }

}

xmlはこんな感じです。

activity_search.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/grey200"
        android:minHeight="?attr/actionBarSize"
        app:elevation="4dp"
        app:popupTheme="@style/Theme.AppCompat.Light">

        <EditText
            android:id="@+id/edit_search"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:hint="@string/search_hint"
            android:textColorHint="@color/grey600">

            <requestFocus />

        </EditText>

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

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/toolbar" />

</RelativeLayout>

検索アイコンをタップした時にSearchActivityを呼び出す

最後に、検索アイコンをタップした時の実装をこんな感じで加えるだけです。

MainActivity.java
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        switch (id) {
            case R.id.action_search:
                SearchActivity.start(this);
                break;
        }

        return super.onOptionsItemSelected(item);
    }

あとは、サジェストや検索結果の表示なんかをSearchActivityに実装していくだけです。
こんな感じの見た目の動きを実現することができます。

activity_transition.gif

もっといい方法があるかも

一応この方法で見た目はほぼ同じものを作ることができましたが、もっとスマートな方法があるかもしれません。もし知っていたらぜひ教えてください。

76
66
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
66