web-dev-qa-db-ja.com

材料設計ガイドラインに従ってSearchViewを実装する

材料設計ガイドライン に従って、アクティビティツールバー(アクションバー)で検索ビューを実装する方法を探していました。

検索アイコンをクリックすると、ツールバー全体がアニメーション化され、ドロップダウンではなくメインビューに候補が表示される白い背景の検索EditTextのみが表示されます。

ガイドラインのスクリーンショットは次のとおりです。 enter image description here

以下は、Gmail Inbox実装からのgifです。 enter image description here

私はコード例とチュートリアルを探していましたが、これまでのところ失敗しました。これを行うにはどうすればよいですか?

36
GunnerFan

いくつかのマテリアルSearchViewライブラリを試しましたが、それらのどれもサポートライブラリのライブラリとして適切に機能しなかったため、多くの作業を経て再設計することにしました。結果に満足しています。

enter image description here

方法は次のとおりです。

1)SearchViewアイテムをメニューに追加します

<item
    Android:id="@+id/m_search"
    Android:icon="@drawable/ic_action_search"
    Android:title="@string/search_title"
    app:actionLayout="@layout/search_view_layout"
    app:showAsAction="ifRoom|collapseActionView" />

actionViewClassの代わりにactionLayoutを宣言していることに注意してください。これは、ツールバーテーマとは別にSearchViewテーマを設定する唯一の方法です。

search_view_layout.xml:

<Android.support.v7.widget.SearchView
    Android:id="@+id/search_view"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:theme="@style/SearchViewTheme" />

2)カスタムSearchViewテーマをスタイルに追加し、ツールバーテーマでもSearchViewテーマを宣言します。

<style name="SearchViewTheme" parent="Widget.AppCompat.SearchView.ActionBar">
    <item name="layout">@layout/toolbar_search_view</item>
    <item name="commitIcon">@drawable/ic_search_commit</item>
    <item name="colorControlNormal">@color/material_light_active_icon</item>
    <item name="colorControlHighlight">@color/material_ripple_light</item>
    <item name="autoCompleteTextViewStyle">@style/AutoCompleteTextViewStyle</item>
    <item name="suggestionRowLayout">@layout/search_view_suggestion_row</item>
    <item name="Android:maxWidth">9999dp</item>
</style>

<style name="AutoCompleteTextViewStyle" parent="Widget.AppCompat.Light.AutoCompleteTextView">
    <item name="Android:popupBackground">@drawable/search_suggestions_bg</item>
    <item name="Android:popupElevation">0dp</item>
</style>

<style name="ToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="searchViewStyle">@style/SearchViewTheme</item>
</style>

toolbar_search_view.xml:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/search_bar"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="horizontal"
    Android:paddingEnd="8dp">

<!-- This is actually used for the badge icon *or* the badge label (or neither) -->
<TextView
    Android:id="@+id/search_badge"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:layout_marginBottom="2dp"
    Android:drawablePadding="0dp"
    Android:gravity="center_vertical"
    Android:textAppearance="?android:attr/textAppearanceMedium"
    Android:textColor="?android:attr/textColorPrimary"
    Android:visibility="gone" />

<ImageView
    Android:id="@+id/search_button"
    style="?attr/actionButtonStyle"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:layout_gravity="center_vertical"
    Android:contentDescription="@string/abc_searchview_description_search"
    Android:focusable="true" />

<LinearLayout
    Android:id="@+id/search_edit_frame"
    Android:layout_width="0dp"
    Android:layout_height="match_parent"
    Android:layout_weight="1"
    Android:layoutDirection="locale"
    Android:orientation="horizontal">

    <ImageView
        Android:id="@+id/search_mag_icon"
        style="@style/RtlOverlay.Widget.AppCompat.SearchView.MagIcon"
        Android:layout_width="@dimen/abc_dropdownitem_icon_width"
        Android:layout_height="wrap_content"
        Android:layout_gravity="center_vertical"
        Android:scaleType="centerInside"
        Android:visibility="gone" />

    <!-- Inner layout contains the app icon, button(s) and EditText -->
    <LinearLayout
        Android:id="@+id/search_plate"
        Android:layout_width="0dp"
        Android:layout_height="match_parent"
        Android:layout_gravity="center_vertical"
        Android:layout_weight="1"
        Android:orientation="horizontal">

        <view
            Android:id="@+id/search_src_text"
            class="Android.support.v7.widget.SearchView$SearchAutoComplete"
            Android:layout_width="0dp"
            Android:layout_height="match_parent"
            Android:layout_gravity="center_vertical"
            Android:layout_marginEnd="@dimen/item_list_horizontal_margin"
            Android:layout_marginStart="@dimen/item_list_horizontal_margin"
            Android:layout_weight="1"
            Android:background="@null"
            Android:dropDownAnchor="@id/anchor_dropdown"
            Android:dropDownHeight="wrap_content"
            Android:dropDownHorizontalOffset="0dp"
            Android:dropDownVerticalOffset="0dp"
            Android:ellipsize="end"
            Android:imeOptions="actionSearch"
            Android:inputType="text|textAutoComplete|textNoSuggestions"
            Android:maxLines="1"
            Android:paddingEnd="8dp"
            Android:textColor="@Android:color/black"
            Android:textColorHint="@color/material_light_hint_text"
            Android:textSize="20sp" />

        <ImageView
            Android:id="@+id/search_close_btn"
            Android:layout_width="wrap_content"
            Android:layout_height="match_parent"
            Android:layout_gravity="center_vertical"
            Android:background="?attr/selectableItemBackgroundBorderless"
            Android:contentDescription="@string/abc_searchview_description_clear"
            Android:focusable="true"
            Android:paddingEnd="8dp"
            Android:paddingStart="8dp" />
    </LinearLayout>

    <LinearLayout
        Android:id="@+id/submit_area"
        Android:layout_width="wrap_content"
        Android:layout_height="match_parent"
        Android:orientation="horizontal">

        <ImageView
            Android:id="@+id/search_go_btn"
            Android:layout_width="wrap_content"
            Android:layout_height="match_parent"
            Android:layout_gravity="center_vertical"
            Android:background="?attr/selectableItemBackgroundBorderless"
            Android:contentDescription="@string/abc_searchview_description_submit"
            Android:focusable="true"
            Android:paddingEnd="8dp"
            Android:paddingStart="8dp"
            Android:visibility="gone" />

        <ImageView
            Android:id="@+id/search_voice_btn"
            Android:layout_width="wrap_content"
            Android:layout_height="match_parent"
            Android:layout_gravity="center_vertical"
            Android:background="?attr/selectableItemBackgroundBorderless"
            Android:contentDescription="@string/abc_searchview_description_voice"
            Android:focusable="true"
            Android:paddingEnd="8dp"
            Android:paddingStart="8dp"
            Android:visibility="gone" />
    </LinearLayout>
</LinearLayout>

ツールバービューの下にアンカードロップダウンビューを追加したことに注意してください。これにより、候補が画面全体に表示されます。

<Android.support.design.widget.AppBarLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/appBar"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content">

<Android.support.v7.widget.Toolbar
    Android:id="@+id/toolbar"
    Android:layout_width="match_parent"
    Android:layout_height="?attr/actionBarSize"
    Android:background="?attr/colorPrimary"
    app:collapseIcon="@drawable/ic_search_collapse"
    app:popupTheme="@style/AppTheme.PopupOverlay"
    app:theme="@style/ToolbarTheme" />

<View
    Android:id="@+id/anchor_dropdown"
    Android:layout_width="match_parent"
    Android:layout_height="0dp" />

</Android.support.design.widget.AppBarLayout>

search_view_suggestion_row.xml:

(提案間を分割したい場合は、suggestion_dividerの可視性を変更してください):

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="58dp"
    Android:theme="@style/Theme.AppCompat.DayNight">

<!-- Icons come first in the layout, since their placement doesn't depend on
     the placement of the text views. -->
<ImageView
    Android:id="@Android:id/icon1"
    style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1"
    Android:layout_width="56dp"
    Android:layout_height="56dp"
    Android:layout_alignParentBottom="true"
    Android:layout_alignParentTop="true"
    Android:scaleType="centerInside"
    Android:visibility="invisible" />

<ImageView
    Android:id="@+id/edit_query"
    style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query"
    Android:layout_width="56dp"
    Android:layout_height="56dp"
    Android:layout_alignParentBottom="true"
    Android:layout_alignParentTop="true"
    Android:background="?attr/selectableItemBackground"
    Android:scaleType="centerInside"
    Android:visibility="gone" />

<ImageView
    Android:id="@id/Android:icon2"
    style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon2"
    Android:layout_width="56dp"
    Android:layout_height="56dp"
    Android:layout_alignParentBottom="true"
    Android:layout_alignParentTop="true"
    Android:layout_alignWithParentIfMissing="true"
    Android:scaleType="centerInside"
    Android:visibility="gone" />

<!-- The subtitle comes before the title, since the height of the title depends on whether the
     subtitle is visible or gone. -->
<TextView
    Android:id="@Android:id/text2"
    style="?android:attr/dropDownItemStyle"
    Android:layout_width="match_parent"
    Android:layout_height="29dp"
    Android:layout_alignParentBottom="true"
    Android:layout_alignWithParentIfMissing="true"
    Android:gravity="top"
    Android:maxLines="1"
    Android:paddingBottom="4dp"
    Android:textColor="?android:textColorSecondary"
    Android:textSize="12sp"
    Android:visibility="gone" />

<!-- The title is placed above the subtitle, if there is one. If there is no
     subtitle, it fills the parent. -->
<TextView
    Android:id="@Android:id/text1"
    style="?android:attr/dropDownItemStyle"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_above="@Android:id/text2"
    Android:layout_centerVertical="true"
    Android:ellipsize="end"
    Android:maxLines="1"
    Android:scrollHorizontally="false"
    Android:textColor="?android:textColorPrimary"
    Android:textSize="16sp" />

<View
    Android:id="@+id/suggestion_divider"
    Android:layout_width="match_parent"
    Android:layout_height="0.5dp"
    Android:layout_alignParentBottom="true"
    Android:layout_alignStart="@Android:id/text1"
    Android:layout_marginStart="8dp"
    Android:background="@color/divider_color"
    Android:visibility="gone" />

提案の背景とコミットアイコンはカスタムメイドで、使用したその他のアイコンは次の場所にあります。 https://material.io/icons/

ic_search_commit.xml:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:width="24dp"
    Android:height="24dp"
    Android:autoMirrored="true"
    Android:viewportHeight="24.0"
    Android:viewportWidth="24.0">
    <path
        Android:fillColor="@color/active_icon_color"
        Android:pathData="m18.364,16.95l-8.605,-8.605l7.905,-0l-0.007,-2.001l-11.314,0l0,11.314l1.994,-0l0.007,-7.898l8.605,8.605l1.414,-1.414z" />

search_suggestions_bg.xml:

<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item>
    <shape Android:shape="rectangle">
        <padding Android:top="0.5dp" />
        <stroke
            Android:width="0.5dp"
            Android:color="@color/divider_color" />
    </shape>
</item>
<item>
    <shape Android:shape="rectangle">
        <solid Android:color="@color/cards_and_dialogs_color" />
    </shape>
</item>
</layer-list>

Colors.xmlに次の値を追加します(DayNightテーマを使用している場合のみ、values-nightを追加します)。

values/colors.xml

<color name="material_light_primary_text">#DE000000</color>
<color name="material_light_hint_text">#61000000</color>
<color name="material_light_active_icon">#8A000000</color>
<color name="material_ripple_light">#1F000000</color>
<color name="divider_color">#1F000000</color>
<color name="active_icon_color">#8A000000</color>
<color name="cards_and_dialogs_color">@Android:color/white</color>
<color name="quantum_grey_600">#757575</color>

values-night/colors.xml:

<color name="divider_color">#1FFFFFFF</color>
<color name="active_icon_color">@Android:color/white</color>
<color name="cards_and_dialogs_color">#424242</color>

3)最後に、コードで魔法を起こさせます:

目的のアクティビティでSearchViewをセットアップおよび初期化します

private MenuItem mSearchItem;
private Toolbar mToolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);

    mSearchItem = menu.findItem(R.id.m_search);

    MenuItemCompat.setOnActionExpandListener(mSearchItem, new MenuItemCompat.OnActionExpandListener() {
        @Override
        public boolean onMenuItemActionCollapse(MenuItem item) {
            // Called when SearchView is collapsing
            if (mSearchItem.isActionViewExpanded()) {
                animateSearchToolbar(1, false, false);
            }
            return true;
        }

        @Override
        public boolean onMenuItemActionExpand(MenuItem item) {
            // Called when SearchView is expanding
            animateSearchToolbar(1, true, true);
            return true;
        }
    });

    return true;
}

public void animateSearchToolbar(int numberOfMenuIcon, boolean containsOverflow, boolean show) {

    mToolbar.setBackgroundColor(ContextCompat.getColor(this, Android.R.color.white));
    mDrawerLayout.setStatusBarBackgroundColor(ContextCompat.getColor(this, R.color.quantum_grey_600));

    if (show) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
            int width = mToolbar.getWidth() -
                    (containsOverflow ? getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_overflow_material) : 0) -
                    ((getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_material) * numberOfMenuIcon) / 2);
            Animator createCircularReveal = ViewAnimationUtils.createCircularReveal(mToolbar,
                    isRtl(getResources()) ? mToolbar.getWidth() - width : width, mToolbar.getHeight() / 2, 0.0f, (float) width);
            createCircularReveal.setDuration(250);
            createCircularReveal.start();
        } else {
            TranslateAnimation translateAnimation = new TranslateAnimation(0.0f, 0.0f, (float) (-mToolbar.getHeight()), 0.0f);
            translateAnimation.setDuration(220);
            mToolbar.clearAnimation();
            mToolbar.startAnimation(translateAnimation);
        }
    } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
            int width = mToolbar.getWidth() -
                    (containsOverflow ? getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_overflow_material) : 0) -
                    ((getResources().getDimensionPixelSize(R.dimen.abc_action_button_min_width_material) * numberOfMenuIcon) / 2);
            Animator createCircularReveal = ViewAnimationUtils.createCircularReveal(mToolbar,
                    isRtl(getResources()) ? mToolbar.getWidth() - width : width, mToolbar.getHeight() / 2, (float) width, 0.0f);
            createCircularReveal.setDuration(250);
            createCircularReveal.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    mToolbar.setBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimary));
                    mDrawerLayout.setStatusBarBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimaryDark));
                }
            });
            createCircularReveal.start();
        } else {
            AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
            Animation translateAnimation = new TranslateAnimation(0.0f, 0.0f, 0.0f, (float) (-mToolbar.getHeight()));
            AnimationSet animationSet = new AnimationSet(true);
            animationSet.addAnimation(alphaAnimation);
            animationSet.addAnimation(translateAnimation);
            animationSet.setDuration(220);
            animationSet.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mToolbar.setBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimary));
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
            mToolbar.startAnimation(animationSet);
        }
        mDrawerLayout.setStatusBarBackgroundColor(getThemeColor(MainActivity.this, R.attr.colorPrimaryDark));
    }
}

private boolean isRtl(Resources resources) {
    return resources.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}

private static int getThemeColor(Context context, int id) {
    Resources.Theme theme = context.getTheme();
    TypedArray a = theme.obtainStyledAttributes(new int[]{id});
    int result = a.getColor(0, 0);
    a.recycle();
    return result;
}

コードについて注意すべき点はほとんどありません:

1)アニメーションは、メニュー項目のセットに基づいて開始点を調整し、ツールバーにオーバーフローアイコンがある場合、レイアウトがLTRかRTLかを自動的に検出します。

2)ナビゲーションドロワーアクティビティを使用しているので、StatusBarの色をmDrawerLayoutに設定します。通常のアクティビティを使用している場合は、StatusBarの色を次のように設定できます。

getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.quantum_grey_600));

3)循環表示アニメーションは、キットカット以上でのみ機能します。

100
shnizlon

Android.support.v7ライブラリを使用している場合、実際にこれを行うのは非常に簡単です。

ステップ-1

メニュー項目を宣言する

<item Android:id="@+id/action_search"
Android:title="Search"
Android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="Android.support.v7.widget.SearchView" />

ステップ-2

AppCompatActivityを拡張し、onCreateOptionsMenuでSearchViewをセットアップします。

import Android.support.v7.widget.SearchView;

public class YourActivity extends AppCompatActivity {

    ...

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_home, menu);
        // Retrieve the SearchView and plug it into SearchManager
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    ... 
}
9

アイデアは非常にシンプルです-EditText、TextWatcher、RecyclerViewとFilterableアダプターを使用して、独自のAutoCompleteTextViewを記述する必要があります。

  • EditTextは、文字を入力できるテキストフィールドを提供します
  • TextWatcherを使用すると、テキストの変更を監視できます。
  • RecyclerViewはどこにでも配置できるため、スクリーンショットのように検索結果を表示できます
  • フィルター可能なアダプターは、入力されたテキストでフィルターされたデータを表示するのに役立ちます

そう:

  • editTextを上部に配置して、RecyclerViewが残りのスペースを埋めるレイアウトを作成します。アイコン、影などを追加します.
  • textWatcherを追加し、テキストが変更されるたびにアダプターを更新します

私のソリューションの実際の動作をご覧になりたい場合は、githubで私のプロジェクトをご覧ください: https://github.com/ZieIony/Carbon

オートコンプリートデモは、「デモ」セクションのサンプルアプリで確認できます。

Screenshot

8
Zielony

@Zielonyの回答からヒントを得て、次のことを行いました。

1)代わりに、ActionBarまたはToolBarを使用する場合、独自のレイアウトを作成しました(基本的には、ハンバーガーメニュー、検索、その他のメニューボタン、および検索用のEditTextを備えたRelativeLayout)

2)ActionBarのないテーマを使用し、アクティビティの上部にカスタムレイアウトを配置して、ActionBarのように表示されるようにしました。

3)検索ボタンのOnClickListenerで、2つのことを行います。

  • メニューボタンを非表示にし、「検索」EditTextを表示します。
  • フラグメントを追加して、検索候補と検索を表示します
  • ソフトキーボード入力を表示する

3)他のメニューボタンにOnClickListenersを追加しました。

4)「検索」EditTextにTextWatcherを追加して、サーバーからの検索ヒントと結果を表示します。

これは、現在の表示方法です。 enter image description here

7
GunnerFan

ここに私がそれを実装しようとした方法があります、これをチェックしてください。

https://github.com/Shahroz16/material-searchview

Meterial Search View

2
ShahrozKhan91

私はそれを理解したと思う。現在、ツールバー内でEditTextのみを使用しています。

私は今これを持っています:

enter image description here

最初に私のアクティビティのonCreate()内で、右側に画像ビューのあるEditTextを次のようにツールバーに追加しました。

// Setup search container view
searchContainer = new LinearLayout(this);
Toolbar.LayoutParams containerParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
containerParams.gravity = Gravity.CENTER_VERTICAL;
searchContainer.setLayoutParams(containerParams);

// Setup search view
toolbarSearchView = new EditText(this);
// Set width / height / gravity
int[] textSizeAttr = new int[]{Android.R.attr.actionBarSize};
int indexOfAttrTextSize = 0;
TypedArray a = obtainStyledAttributes(new TypedValue().data, textSizeAttr);
int actionBarHeight = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
a.recycle();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, actionBarHeight);
params.gravity = Gravity.CENTER_VERTICAL;
params.weight = 1;
toolbarSearchView.setLayoutParams(params);

// Setup display
toolbarSearchView.setBackgroundColor(Color.TRANSPARENT);
toolbarSearchView.setPadding(2, 0, 0, 0);
toolbarSearchView.setTextColor(Color.WHITE);
toolbarSearchView.setGravity(Gravity.CENTER_VERTICAL);
toolbarSearchView.setSingleLine(true);
toolbarSearchView.setImeActionLabel("Search", EditorInfo.IME_ACTION_UNSPECIFIED);
toolbarSearchView.setHint("Search");
toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
try {
    // Set cursor colour to white
    // http://stackoverflow.com/a/26544231/1692770
    // https://github.com/Android/platform_frameworks_base/blob/KitKat-release/core/Java/Android/widget/TextView.Java#L562-564
    Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
    f.setAccessible(true);
    f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
} catch (Exception ignored) {
}

// Search text changed listener
toolbarSearchView.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
        if (mainFragment != null && mainFragment instanceof MainListFragment) {
            ((MainListFragment) mainFragment).search(s.toString());
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
        // http://stackoverflow.com/a/6438918/1692770
        if (s.toString().length() <= 0) {
            toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
        }
    }
});
((LinearLayout) searchContainer).addView(toolbarSearchView);

// Setup the clear button
searchClearButton = new ImageView(this);
Resources r = getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, r.getDisplayMetrics());
LinearLayout.LayoutParams clearParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
clearParams.gravity = Gravity.CENTER;
searchClearButton.setLayoutParams(clearParams);
searchClearButton.setImageResource(R.drawable.ic_close_white_24dp); // TODO: Get this image from here: https://github.com/google/material-design-icons
searchClearButton.setPadding(px, 0, px, 0);
searchClearButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        toolbarSearchView.setText("");
    }
});
((LinearLayout) searchContainer).addView(searchClearButton);

// Add search view to toolbar and hide it
searchContainer.setVisibility(View.GONE);
toolbar.addView(searchContainer);

これは機能しましたが、ホームボタンをタップしたときにonOptionsItemSelected()が呼び出されないという問題に遭遇しました。そのため、ホームボタンを押しても検索をキャンセルできませんでした。ホームボタンにクリックリスナーを登録する方法をいくつか試しましたが、うまくいきませんでした。

結局、私が持っていたActionBarDrawerToggleが物事に干渉していることがわかったので、それを削除しました。その後、このリスナーは動作を開始しました。

 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // toolbarHomeButtonAnimating is a boolean that is initialized as false. It's used to stop the user pressing the home button while it is animating and breaking things.
        if (!toolbarHomeButtonAnimating) {
            // Here you'll want to check if you have a search query set, if you don't then hide the search box.
            // My main fragment handles this stuff, so I call its methods.
            FragmentManager fragmentManager = getFragmentManager();
            final Fragment fragment = fragmentManager.findFragmentById(R.id.container);
            if (fragment != null && fragment instanceof MainListFragment) {
                if (((MainListFragment) fragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
                    displaySearchView(false);
                    return;
                }
            }
        }

        if (mDrawerLayout.isDrawerOpen(findViewById(R.id.navigation_drawer)))
            mDrawerLayout.closeDrawer(findViewById(R.id.navigation_drawer));
        else
            mDrawerLayout.openDrawer(findViewById(R.id.navigation_drawer));
    }
});

ホームボタンで検索をキャンセルできるようになりましたが、[戻る]ボタンを押してキャンセルすることはできません。そこで、これをonBackPressed()に追加しました。

FragmentManager fragmentManager = getFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.container);
if (mainFragment != null && mainFragment instanceof MainListFragment) {
    if (((MainListFragment) mainFragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
        displaySearchView(false);
        return;
    }
}

EditTextとメニュー項目の表示を切り替えるためにこのメソッドを作成しました:

public void displaySearchView(boolean visible) {
    if (visible) {
        // Stops user from being able to open drawer while searching
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);

        // Hide search button, display EditText
        menu.findItem(R.id.action_search).setVisible(false);
        searchContainer.setVisibility(View.VISIBLE);

        // Animate the home icon to the back arrow
        toggleActionBarIcon(ActionDrawableState.ARROW, mDrawerToggle, true);

        // Shift focus to the search EditText
        toolbarSearchView.requestFocus();

        // Pop up the soft keyboard
        new Handler().postDelayed(new Runnable() {
            public void run() {
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0));
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0));
            }
        }, 200);
    } else {
        // Allows user to open drawer again
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

        // Hide the EditText and put the search button back on the Toolbar.
        // This sometimes fails when it isn't postDelayed(), don't know why.
        toolbarSearchView.postDelayed(new Runnable() {
            @Override
            public void run() {
                toolbarSearchView.setText("");
                searchContainer.setVisibility(View.GONE);
                menu.findItem(R.id.action_search).setVisible(true);
            }
        }, 200);

        // Turn the home button back into a drawer icon
        toggleActionBarIcon(ActionDrawableState.BURGER, mDrawerToggle, true);

        // Hide the keyboard because the search box has been hidden
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(toolbarSearchView.getWindowToken(), 0);
    }
}

ツールバーのホームボタンを引き出しアイコンと戻るボタンの間で切り替える方法が必要でした。私は最終的にこのSO answer。で以下のメソッドを見つけました。

private enum ActionDrawableState
{
  BURGER, ARROW 
}

private void toggleActionBarIcon(final ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate) {
    if (animate) {
        float start = state == ActionDrawableState.BURGER ? 1.0f : 0f;
        float end = Math.abs(start - 1);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
            offsetAnimator.setDuration(300);
            offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
            offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float offset = (Float) animation.getAnimatedValue();
                    toggle.onDrawerSlide(null, offset);
                }
            });
            offsetAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    toolbarHomeButtonAnimating = false;
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            toolbarHomeButtonAnimating = true;
            offsetAnimator.start();
        }
    } else {
        if (state == ActionDrawableState.BURGER) {
            toggle.onDrawerClosed(null);
        } else {
            toggle.onDrawerOpened(null);
        }
    }
}

これは機能し、途中で見つけたいくつかのバグを解決することができました。私はそれが100%だとは思わないが、それは私にとって十分に機能している。編集:Javaの代わりにXMLで検索ビューを追加する場合は、これを行います:

toolbar.xml:

<Android.support.v7.widget.Toolbar 
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/toolbar"
contentInsetLeft="72dp"
contentInsetStart="72dp"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:elevation="4dp"
Android:minHeight="?attr/actionBarSize"
app:contentInsetLeft="72dp"
app:contentInsetStart="72dp"
app:popupTheme="@style/ActionBarPopupThemeOverlay"
app:theme="@style/ActionBarThemeOverlay">

<LinearLayout
    Android:id="@+id/search_container"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:gravity="center_vertical"
    Android:orientation="horizontal">

    <EditText
        Android:id="@+id/search_view"
        Android:layout_width="0dp"
        Android:layout_height="?attr/actionBarSize"
        Android:layout_weight="1"
        Android:background="@Android:color/transparent"
        Android:gravity="center_vertical"
        Android:hint="Search"
        Android:imeOptions="actionSearch"
        Android:inputType="text"
        Android:maxLines="1"
        Android:paddingLeft="2dp"
        Android:singleLine="true"
        Android:textColor="#ffffff"
        Android:textColorHint="#b3ffffff" />

    <ImageView
        Android:id="@+id/search_clear"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_gravity="center"
        Android:paddingLeft="16dp"
        Android:paddingRight="16dp"
        Android:src="@drawable/ic_close_white_24dp" />
</LinearLayout>

onCreate()のアクティビティ:

searchContainer = findViewById(R.id.search_container);
toolbarSearchView = (EditText) findViewById(R.id.search_view);
searchClearButton = (ImageView) findViewById(R.id.search_clear);

// Setup search container view
try {
    // Set cursor colour to white
    // http://stackoverflow.com/a/26544231/1692770
    // https://github.com/Android/platform_frameworks_base/blob/KitKat-release/core/Java/Android/widget/TextView.Java#L562-564
    Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
    f.setAccessible(true);
    f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
} catch (Exception ignored) {
}

// Search text changed listener
toolbarSearchView.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
        if (mainFragment != null && mainFragment instanceof MainListFragment) {
            ((MainListFragment) mainFragment).search(s.toString());
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
});

// Clear search text when clear button is tapped
searchClearButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        toolbarSearchView.setText("");
    }
});

// Hide the search view
searchContainer.setVisibility(View.GONE);
2

あなたはこれを達成するためにAutoCompleteTextViewを使用することができます、以下のリンクに従ってください

アクションバーの検索ボックスのようなGmailを構築する方法?

0
Vinay Jayaram