web-dev-qa-db-fra.com

Implémentation de SearchView selon les directives de conception de matériel

J'ai cherché des moyens d'implémenter une searchview dans la barre d'outils d'activité (actionbar) conformément au directives de conception de matériel.

En cliquant sur l'icône de recherche, la barre d'outils entière s'anime pour que seul le texte de recherche EditText avec un arrière-plan blanc avec des suggestions apparaissant dans la vue principale au lieu d'un menu déroulant.

Voici une capture d'écran des lignes directrices: enter image description here

Voici un gif de l'implémentation de la boîte de réception Gmail: enter image description here

Je cherchais des exemples de code et des tutoriels, mais jusqu'à présent, j'ai été infructueux. Comment puis-je faire cela?

36
GunnerFan

J'ai essayé plusieurs bibliothèques SearchView matérielles, mais aucune d'entre elles ne fonctionnait bien, mais j'ai décidé de la redéfinir. Après beaucoup de travail, je suis ravie du résultat:

enter image description here

Voici comment vous pouvez le faire:

1) Ajouter un élément SearchView à votre menu

<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" />

Notez que je déclare actionLayout au lieu de actionViewClass , j'ai pensé que c'est le seul moyen de définir le thème SearchView séparément du thème de la barre d'outils.

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) Ajoutez le thème SearchView personnalisé à vos styles, déclarez également le thème SearchView dans votre thème de barre d’outils:

<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>

Notez que j'ai ajouté une vue déroulante ancre sous la vue Barre d'outils, de sorte que les suggestions obtiennent une largeur d'écran complète.

<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:

(modifiez la visibilité de suggestion_divider si vous souhaitez séparer les suggestions):

<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" />

Le fond des suggestions et l'icône de validation sont personnalisés, le reste des icônes que j'ai utilisées se trouvent à l'adresse suivante: 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>

Ajoutez les valeurs suivantes à votre fichier colors.xml (ajoutez les valeurs nuit uniquement si vous utilisez le thème DayNight):

valeurs/couleurs.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>

valeurs-nuit/couleurs.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) Dernière partie, créez la magie dans le code:

Configurez et initialisez SearchView dans l'activité de votre choix

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;
}

Peu de choses à noter sur le code:

1) L’animation ajustera son point de départ en fonction de votre ensemble d’éléments de menu. Si la barre d’outils contient une icône de débordement, elle détectera automatiquement si la mise en page est LTR ou RTL.

2) J'utilise l'activité du tiroir de navigation. J'ai donc défini la couleur de StatusBar sur mDrawerLayout. Si vous utilisez une activité normale, vous pouvez définir la couleur de StatusBar de la manière suivante:

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

3) L’animation de révélation circulaire ne fonctionnera que sur KitKat et au-dessus.

100
shnizlon

En fait, il est très facile de le faire si vous utilisez la bibliothèque Android.support.v7.

étape - 1

Déclarer un élément de menu

<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" />

étape - 2

Étendez AppCompatActivity et dans le onCreateOptionsMenu, configurez 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
Jigar Brahmbhatt

L'idée est très simple: vous devez écrire votre propre AutoCompleteTextView à l'aide d'EditText, TextWatcher et RecyclerView avec un adaptateur filtrable.

  • EditText vous donne un champ de texte avec la possibilité de saisir des caractères
  • TextWatcher vous permet de surveiller les modifications de texte
  • RecyclerView peut être placé n'importe où pour que vous puissiez afficher les résultats de la recherche, comme sur votre capture d'écran.
  • L'adaptateur filtrable permet de présenter les données filtrées avec le texte saisi

Alors:

  • faites une mise en page avec EditText en haut, avec RecyclerView remplissant l'espace restant. Ajoutez l'icône, l'ombre, etc.
  • ajouter un TextWatcher et mettre à jour l'adaptateur à chaque changement de texte

Si vous souhaitez voir ma solution en action, consultez mon projet sur github: https://github.com/ZieIony/Carbon

La démo de finalisation automatique peut être sonore dans l'exemple d'application dans la section 'Démos'.

Screenshot

8
Zielony

Prenant un indice de la réponse de @ Zielony, j’ai fait ce qui suit:

1) À la place, si vous utilisez une barre d’action ou une barre d’outils, j’ai construit ma propre mise en page (essentiellement un menu RelativeLayout avec hamburger, des boutons de recherche et d’autres menus et un texte EditText pour la recherche)

2) A utilisé un thème sans barre d’action, a placé ma présentation personnalisée en haut de l’activité de sorte qu’elle apparaisse comme une barre d’action.

3) Dans le bouton de recherche OnClickListener, je fais 2 choses:

  • Masquer les boutons de menu et afficher la "recherche" EditText.
  • Ajouter un fragment pour afficher les suggestions de recherche et la recherche
  • Afficher la saisie au clavier

3) OnClickListeners ajouté pour les autres boutons de menu.

4) Ajout d'un TextWatcher sur le champ 'search' EditText pour afficher les astuces de recherche et les résultats du serveur.

Voici comment cela apparaît maintenant: enter image description here

7
GunnerFan

Voici comment j'ai essayé de le mettre en œuvre, veuillez vérifier ceci.

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

Meterial Search View

2
ShahrozKhan91

Je pense que je l'ai compris. J'utilise maintenant seulement un EditText à l'intérieur de la barre d'outils.

J'ai maintenant ceci:

enter image description here

Tout d'abord dans onCreate () de mon activité, j'ai ajouté le EditText avec une vue d'image sur le côté droit de la barre d'outils comme ceci:

// 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);

Cela a fonctionné, mais j'ai rencontré un problème où onOptionsItemSelected () n'était pas appelé lorsque j'ai appuyé sur le bouton d'accueil. Je n'ai donc pas pu annuler la recherche en appuyant sur le bouton d'accueil. J'ai essayé différentes méthodes pour enregistrer l'auditeur de clics sur le bouton d'accueil, mais cela n'a pas fonctionné.

Finalement, j'ai découvert que le ActionBarDrawerToggle que j'avais interférait avec des choses, alors je l'ai supprimé. Cet écouteur a alors commencé à fonctionner:

 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));
    }
});

Donc, je peux maintenant annuler la recherche avec le bouton d'accueil, mais je ne peux pas appuyer sur le bouton de retour pour l'annuler pour le moment. J'ai donc ajouté ceci à 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;
    }
}

J'ai créé cette méthode pour activer la visibilité de l'élément EditText et du menu:

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);
    }
}

J'avais besoin d'un moyen de basculer le bouton d'accueil de la barre d'outils entre l'icône du tiroir et le bouton précédent. J'ai finalement trouvé la méthode ci-dessous dans cette réponse SO. Même si je l'ai légèrement modifiée, cela a plus de sens pour moi:

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);
        }
    }
}

Cela fonctionne, j'ai réussi à résoudre quelques bugs que j'ai trouvés en chemin. Je ne pense pas que ce soit à 100% mais cela fonctionne assez bien pour moi. EDIT: Si vous souhaitez ajouter la vue de recherche en XML au lieu de Java procédez comme suit:

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 () de votre activité:

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
Jigar Brahmbhatt

Vous pouvez utiliser AutoCompleteTextView pour y parvenir, suivez le lien ci-dessous

Comment construire Gmail comme un champ de recherche dans la barre d’actions?

0
Vinay Jayaram