Materialデザインに対応したYouTubeのアプリは、右上の検索アイコンをタップするとToolBarの背景色が変わってSearchViewっぽいものが表示されます。
実際にどう実装しているかわかりませんが、同じ動きをするものを作ってみたのでメモしておきます。
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:windowEnterTransition
とandroid:windowExitTransition
に@android:transition/fade
を指定しておけば、同じような動きをします。
ただ、ActivityTransitionsはAPI Level 21から有効なので、Android5.0未満では使えません。将来的にはこのやり方がよさそうですが、Android4以下の対応を考えて別の方法を取りました。
ActivityOptionsCompatを使う
ということで、ActivityTransitionsと同じような動きをAndroid4以下でも実現するようにしました。support-v4:21.0
ライブラリのActivityOptionsCompat
クラスを使います。
以下、実装手順を簡単にまとめます。
build.gradleのdependenciesを追加
以下のライブラリを使うので追加します。
dependencies {
compile 'com.android.support:support-v4:21.0.0'
compile 'com.android.support:appcompat-v7:21.0.0'
}
メインのActivityのツールバーに検索アイコンを追加
メインのActivityに検索アイコンを追加します。普通にmenuを追加すればよいです。
<?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を配置しています。
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はこんな感じです。
<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を呼び出す
最後に、検索アイコンをタップした時の実装をこんな感じで加えるだけです。
@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に実装していくだけです。
こんな感じの見た目の動きを実現することができます。
もっといい方法があるかも
一応この方法で見た目はほぼ同じものを作ることができましたが、もっとスマートな方法があるかもしれません。もし知っていたらぜひ教えてください。