Création d'un SearchView qui ressemble aux directives de conception des matériaux

134

Je suis actuellement en train d'apprendre à convertir mon application en Material Design et je suis un peu bloqué en ce moment. J'ai ajouté la barre d'outils et j'ai superposé tout le contenu de mon tiroir de navigation.

J'essaie maintenant de créer une recherche extensible qui ressemble à celle des directives matérielles : entrez la description de l'image ici

c'est ce que j'ai en ce moment et je ne peux pas comprendre comment faire comme ci-dessus:
Ma recherche

Ceci est mon menu 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="@android:drawable/ic_menu_search"
        android:title="Search"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

Cela fonctionne, j'obtiens un élément de menu qui se développe en SearchView et je peux filtrer ma liste très bien. Cela ne ressemble en rien à la 1ère photo.

J'ai essayé d'utiliser MenuItemCompat.setOnActionExpandListener()pour R.id.action_searchque je puisse changer l'icône d'accueil en flèche arrière, mais cela ne semble pas fonctionner. Rien n'est renvoyé dans l'auditeur. Même si cela fonctionnait, cela ne serait toujours pas très proche de la 1ère image.

Comment créer un SearchView dans la nouvelle barre d'outils appcompat qui ressemble aux directives relatives aux matériaux?

Mike
la source
6
app: showAsAction = "always | collapseActionView"
Pavlos
Vous voudrez peut-être jeter un oeil à ma réponse ici: stackoverflow.com/a/41013994/5326551
shnizlon

Réponses:

152

C'est en fait assez facile à faire si vous utilisez une android.support.v7bibliothèque.

É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 AppCompatActivityet dans la onCreateOptionsMenuconfiguration le 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;
    }

    ... 

}

Résultat

entrez la description de l'image ici

entrez la description de l'image ici

Subin Sebastian
la source
2
Je l'avais voté, mais quel émulateur utilisez-vous? Je l'ai essayé mais je n'obtiens pas le navigate-backbouton, mais plutôt une icône de recherche, et sa distance par rapport au bord gauche de l'écran n'est pas la même que celle entre l' Xicône et le bord droit de l'écran (je n'ai pas débordement d'action). Posté la question ici , pouvez-vous l'examiner?
Solace
13
ce n'est pas une recherche matérielle. ce n'est que l'ancienne recherche habituelle dans la barre d'action
Gopal Singh Sirvi
2
J'ai répondu à ma propre sous-question, pour la rendre toujours visible sans avoir besoin de cliquer sur le bouton de recherche ajouter la ligne searchView.setIconifiedByDefault(false);à la onCreateOptionsMenufonction.
adelriosantiago
3
une autre information utile - si vous voulez que la vue de recherche soit étendue au départ, assurez-vous d'avoir app:showAsAction="always"et NONapp:showAsAction="ifRoom|collapseActionView"
Vinay W
1
De plus, en utilisant cette méthode, même lorsque le searchBar est développé, OverflowIcon est toujours visible (c'est-à-dire les 3 points). Mais certaines applications gèrent la recherche en l'agrandissant complètement et en changeant l'arrière-plan en blanc. Comme GMail
Zen
83

Après une semaine de perplexité à ce sujet. Je pense que j'ai compris.
J'utilise maintenant juste un EditText à l'intérieur de la barre d'outils. Cela m'a été suggéré par oj88 sur reddit.

J'ai maintenant ceci:
Nouvelle SearchView

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
        // https://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) {
            // https://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 je suis ensuite tombé sur un problème où onOptionsItemSelected () n'était pas appelé lorsque j'ai tapé sur le bouton d'accueil. Je n'ai donc pas pu annuler la recherche en appuyant sur le bouton d'accueil. J'ai essayé plusieurs façons différentes d'enregistrer l'écouteur de clic sur le bouton d'accueil, mais elles n'ont pas fonctionné.

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

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

Je peux donc maintenant annuler la recherche avec le bouton d'accueil, mais je ne peux pas encore appuyer sur le bouton retour pour l'annuler. 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 basculer 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 de retour. J'ai finalement trouvé la méthode ci-dessous dans cette réponse SO . Bien que je l'ai légèrement modifié pour avoir plus de sens pour moi:

private enum ActionDrawableState {
    BURGER, ARROW
}

/**
 * Modified version of this, https://stackoverflow.com/a/26836272/1692770<br>
 * I flipped the start offset around for the animations because it seemed like it was the wrong way around to me.<br>
 * I also added a listener to the animation so I can find out when the home button has finished rotating.
 */
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 cours de route. 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>
</android.support.v7.widget.Toolbar>

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
        // https://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);
Mike
la source
Fonctionne très bien, a l'air super, merci! Cependant, au lieu de créer les mises en page dans le code, j'ai créé le LinearLayout avec le EditText et le ImageView en xml et je l'ai simplement gonflé dans onCreate.
aluxian
Oui, j'ai essayé de le faire en XML, mais je pensais que je faisais quelque chose de mal car Android Studio ne me donnerait pas de saisie semi-automatique dans le format XML.
Mike
Pouvez-vous mettre à jour cette réponse avec la conception de mise en page XML correspondante requise pour cela? cela peut très bien aider les autres.
Shreyash Mahajan
1
@Mike Pouvez-vous mettre à jour votre réponse et mettre votre code source github complet?
Hamed Ghadirian
1
s'il vous plaît poster le projet complet dans github
Nilabja
22

Je sais que c'est un vieux fil, mais je poste toujours la bibliothèque que je viens de créer. J'espère que cela pourrait aider quelqu'un.

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

Vue de recherche de compteur

ShahrozKhan91
la source
1
Ce n'est pas difficile, mais j'aime votre travail. Cela me fait gagner du temps pour créer ma propre vue de recherche. Merci mec!
Slim_user71169
19

La première capture d'écran de votre question n'est pas un widget public. Le support SearchView ( android.support.v7.widget.SearchView) imite SearchView ( ) d'Android 5.0 Lollipop android.widget.SearchView. Votre deuxième capture d'écran est utilisée par d'autres applications conçues par des matériaux comme Google Play.

Le SearchView de votre première capture d'écran est utilisé dans Drive, YouTube et d'autres applications Google Apps à code source fermé. Heureusement, il est également utilisé dans le numéroteur Android 5.0 . Vous pouvez essayer de rétroporter la vue, mais il utilise des API 5.0.

Les classes que vous voudrez regarder sont:

SearchEditTextLayout , AnimUtils et DialtactsActivity pour comprendre comment utiliser View. Vous aurez également besoin de ressources de ContactsCommon .

Bonne chance.

Jared Rummler
la source
Merci d'avoir examiné cela, j'espérais qu'il y avait déjà quelque chose qui pourrait le faire. Pour l'instant, je viens d'utiliser un EditText avec un arrière-plan transparent et cela semble correct pour ce dont j'ai besoin.
Mike
111
Cette réponse me dérange beaucoup. Pourquoi Google utilise-t-il un widget privé qui correspond à sa propre directive de conception matérielle et publie-t-il ensuite un widget merdique pour nous qui ne le fait pas? Et chaque développeur est maintenant aux prises avec cela par lui-même? Quel raisonnement possible pour cela?
Greg Ennis
18

Voici ma tentative de faire ceci:

Étape 1: créer un style nommé SearchViewStyle

<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
    <!-- Gets rid of the search icon -->
    <item name="searchIcon">@drawable/search</item>
    <!-- Gets rid of the "underline" in the text -->
    <item name="queryBackground">@null</item>
    <!-- Gets rid of the search icon when the SearchView is expanded -->
    <item name="searchHintIcon">@null</item>
    <!-- The hint text that appears when the user has not typed anything -->
    <item name="queryHint">@string/search_hint</item>
</style>

Étape 2: Créez une mise en page nommée simple_search_view_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.SearchView
    android:layout_gravity="end"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    style="@style/SearchViewStyle"
    xmlns:android="http://schemas.android.com/apk/res/android" />  

Étape 3: créer un élément de menu pour cette vue de recherche

<?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
        app:actionLayout="@layout/simple_search_view_item"
        android:title="@string/search"
        android:icon="@drawable/search"
        app:showAsAction="always" />
</menu>  

Étape 4: gonflez le menu

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_searchable_activity, menu);
    return true;
}  

Résultat:

entrez la description de l'image ici

La seule chose que je n'ai pas pu faire était de le faire remplir toute la largeur du Toolbar. Si quelqu'un pouvait m'aider à faire ça, ce serait en or.

Un utilisateur SO
la source
1
I wasn't able to do was to make it fill the entire width, quelle version de bibliothèque de support utilisez-vous? Essayez de configurer app:contentInsetStartWithNavigation="0dp"votre barre d'outils.
Mangesh
@LittleChild, essayez la solution donnée par Magnesh. Si le problème n'est toujours pas résolu, essayez d'ajouter les lignes ci-dessous dans la barre d'outils. app: contentInsetStartWithNavigation = "0dp" app: contentInsetLeft = "0dp" app: contentInsetStart = "0dp" app: paddingStart = "0dp" android: layout_marginLeft = "0dp" android: layout_marginStart = "0dp"
Shrey Mahajan
Merci d'avoir mis une explication pour chaque ligne dans SearchViewStyle!
Shinta S
Little Child Pour toute la largeur, vous pouvez faire qc comme ceci: (" stackoverflow.com/questions/27946569/… )
Ali_dev
10

Pour obtenir l'aspect souhaité de SearchView, vous pouvez utiliser des styles.

Tout d'abord, vous devez créer stylepour votre SearchView, qui devrait ressembler à ceci:

<style name="CustomSearchView" parent="Widget.AppCompat.SearchView">
    <item name="searchIcon">@null</item>
    <item name="queryBackground">@null</item>
</style>

Liste complète des attributs que vous pouvez trouver dans cet article, dans la section "SearchView".

Deuxièmement, vous devez créer un stylefor your Toolbar, qui est utilisé comme ActionBar:

<style name="ToolbarSearchView" parent="Base.ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="searchViewStyle">@style/CustomSearchView</item>
</style>

Et enfin, vous devez mettre à jour votre attribut de thème de barre d'outils de cette façon:

<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"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:theme="@style/ToolbarSearchView" />

Résultat:

entrez la description de l'image ici

REMARQUE: vous devez modifier Toolbardirectement l'attribut de votre thème. Si vous mettez simplement à jour l' searchViewStyleattribut de votre thème principal, cela n'affectera pas votre Toolbar.

Artem
la source
Hé, avez-vous ajouté ces icônes navigate-back(flèche arrière) et cancel(les x) vous-même ou elles ont été automatiquement ajoutées?
Solace
1
@Solace ils sont ajoutés automatiquement
Artem
Apparaissent-ils uniquement lorsque vous commencez à écrire la requête de recherche dans SearchView ou sont-ils là même lorsque vous n'avez rien écrit et que le conseil de recherche est visible? Je demande parce que le mien n'apparaît pas tant que je n'ai pas commencé à écrire la requête. Donc cette information me sera très utile
Solace
1
@Solace navigate-backest toujours affiché, n'apparaît clearqu'après avoir écrit une requête de recherche.
Artem
6

Une autre façon d'obtenir l'effet souhaité consiste à utiliser cette bibliothèque de vues de recherche de matériaux . Il gère automatiquement l'historique de recherche et il est également possible de fournir des suggestions de recherche à la vue.

Exemple: (il est affiché en portugais, mais il fonctionne également en anglais et en italien).

Échantillon

Installer

Avant de pouvoir utiliser cette bibliothèque, vous devez implémenter une classe nommée MsvAuthorityà l'intérieur du br.com.maukerpackage sur votre module d'application, et elle doit avoir une variable String statique publique appelée CONTENT_AUTHORITY. Donnez-lui la valeur que vous souhaitez et n'oubliez pas d'ajouter le même nom sur votre fichier manifeste. La bibliothèque utilisera ce fichier pour définir l'autorité du fournisseur de contenu.

Exemple:

MsvAuthority.java

package br.com.mauker;

public class MsvAuthority {
    public static final String CONTENT_AUTHORITY = "br.com.mauker.materialsearchview.searchhistorydatabase";
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>

    <application ... >
        <provider
        android:name="br.com.mauker.materialsearchview.db.HistoryProvider"
        android:authorities="br.com.mauker.materialsearchview.searchhistorydatabase"
        android:exported="false"
        android:protectionLevel="signature"
        android:syncable="true"/>
    </application>

</manifest>

Usage

Pour l'utiliser, ajoutez la dépendance:

compile 'br.com.mauker.materialsearchview:materialsearchview:1.2.0'

Et puis, sur votre Activityfichier de mise en page, ajoutez ce qui suit:

<br.com.mauker.materialsearchview.MaterialSearchView
    android:id="@+id/search_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Après cela, il vous suffira d'obtenir la MaterialSearchViewréférence en utilisant getViewById(), et de l'ouvrir ou de la fermer en utilisant MaterialSearchView#openSearch()et MaterialSearchView#closeSearch().

PS: Il est possible d'ouvrir et de fermer la vue non seulement depuis le Toolbar. Vous pouvez utiliser la openSearch()méthode à partir de n'importe quelle méthode Button, comme un bouton d'action flottant.

// Inside onCreate()
MaterialSearchView searchView = (MaterialSearchView) findViewById(R.id.search_view);
Button bt = (Button) findViewById(R.id.button);

bt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            searchView.openSearch();
        }
    });

Vous pouvez également fermer la vue à l'aide du bouton Retour, en procédant comme suit:

@Override
public void onBackPressed() {
    if (searchView.isOpen()) {
        // Close the search on the back button press.
        searchView.closeSearch();
    } else {
        super.onBackPressed();
    }
}

Pour plus d'informations sur l'utilisation de la lib, consultez la page github .

Mauker
la source
2
Excellente bibliothèque et bonne idée d'abstraire la méthode d'ouverture / fermeture afin qu'un MenuItem ne soit pas nécessaire pour l'ouvrir / le fermer, je prévois de l'utiliser dans mon application avec un FloatingActionButton avec une icône de recherche, donc cela fonctionnera très bien.
AdamMc331
Pourquoi n'y a-t-il pas de paramètres pour des chaînes telles que «Recherche»? Il semble que la bibliothèque limite les gens aux versions anglaise ou portugaise de la chaîne: /
Aspiring Dev
Mais il est possible de changer la chaîne d'indication en utilisant des styles comme indiqué sur le README. Quant à l'indice de saisie vocale, il sera publié plus tard: github.com/Mauker1/MaterialSearchView/issues/23
Mauker
@rpgmaker Vérifiez la dernière mise à jour, il est maintenant possible de modifier ces chaînes.
Mauker
@Mauker une idée comment définir android: imeOptions = "actionSearch" sur le EditText de votre composant? (Je veux afficher un bouton "recherche" sur le clavier)
Greg
2

Ce qui suit va créer un SearchView identique à celui de Gmail et l'ajouter à la barre d'outils donnée. Vous n'aurez qu'à implémenter votre propre méthode "ViewUtil.convertDpToPixel".

private SearchView createMaterialSearchView(Toolbar toolbar, String hintText) {

    setSupportActionBar(toolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowCustomEnabled(true);
    actionBar.setDisplayShowTitleEnabled(false);

    SearchView searchView = new SearchView(this);
    searchView.setIconifiedByDefault(false);
    searchView.setMaxWidth(Integer.MAX_VALUE);
    searchView.setMinimumHeight(Integer.MAX_VALUE);
    searchView.setQueryHint(hintText);

    int rightMarginFrame = 0;
    View frame = searchView.findViewById(getResources().getIdentifier("android:id/search_edit_frame", null, null));
    if (frame != null) {
        LinearLayout.LayoutParams frameParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        rightMarginFrame = ((LinearLayout.LayoutParams) frame.getLayoutParams()).rightMargin;
        frameParams.setMargins(0, 0, 0, 0);
        frame.setLayoutParams(frameParams);
    }

    View plate = searchView.findViewById(getResources().getIdentifier("android:id/search_plate", null, null));
    if (plate != null) {
        plate.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        plate.setPadding(0, 0, rightMarginFrame, 0);
        plate.setBackgroundColor(Color.TRANSPARENT);
    }

    int autoCompleteId = getResources().getIdentifier("android:id/search_src_text", null, null);
    if (searchView.findViewById(autoCompleteId) != null) {
        EditText autoComplete = (EditText) searchView.findViewById(autoCompleteId);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int) ViewUtil.convertDpToPixel(36));
        params.weight = 1;
        params.gravity = Gravity.CENTER_VERTICAL;
        params.leftMargin = rightMarginFrame;
        autoComplete.setLayoutParams(params);
        autoComplete.setTextSize(16f);
    }

    int searchMagId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
    if (searchView.findViewById(searchMagId) != null) {
        ImageView v = (ImageView) searchView.findViewById(searchMagId);
        v.setImageDrawable(null);
        v.setPadding(0, 0, 0, 0);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, 0, 0, 0);
        v.setLayoutParams(params);
    }

    toolbar.setTitle(null);
    toolbar.setContentInsetsAbsolute(0, 0);
    toolbar.addView(searchView);

    return searchView;
}

la source