Criando um SearchView que se parece com as diretrizes de design do material


134

Atualmente, estou aprendendo a converter meu aplicativo em design de materiais e estou um pouco preso no momento. Adicionei a Barra de ferramentas e fiz com que minha gaveta de navegação sobreponha todo o conteúdo.

Agora estou tentando criar uma pesquisa expansível que se pareça com a das diretrizes materiais : insira a descrição da imagem aqui

é isso que eu tenho agora e não consigo descobrir como fazê-lo da maneira acima:
Minha pesquisa

Este é o meu 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>

Isso funciona, recebo um item de menu que se expande para o SearchView e posso filtrar minha lista com precisão. Mas não parece nada com a primeira foto.

Eu tentei usar MenuItemCompat.setOnActionExpandListener()em R.id.action_searchque eu pudesse alterar o ícone lar de uma seta para trás, mas que não parecem funcionar. Nada é disparado no ouvinte. Mesmo que isso funcionasse, ainda não estaria muito próximo da 1ª imagem.

Como crio um SearchView na nova barra de ferramentas appcompat semelhante às diretrizes de material?


6
app: showAsAction = "always | collapseActionView"
Pavlos

Você pode querer dar uma olhada na minha resposta aqui: stackoverflow.com/a/41013994/5326551
shnizlon:

Respostas:


152

Na verdade, é muito fácil fazer isso, se você estiver usando a android.support.v7biblioteca.

Passo 1

Declarar um item 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" />

Passo 2

Estenda AppCompatActivitye na onCreateOptionsMenuconfiguração o 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;
    }

    ... 

}

Resultado

insira a descrição da imagem aqui

insira a descrição da imagem aqui


2
Eu já tinha votado, mas qual emulador você está usando? Eu tentei, mas não estou conseguindo o navigate-backbotão, mas sim um ícone de pesquisa, e sua distância da borda esquerda da tela não é a mesma que aquela entre o Xícone e a borda direita da tela (não tenho estouro de ação). Poste a pergunta aqui , você pode investigar?
Solace

13
não é uma pesquisa material. é apenas a busca de idade usual na barra de ação
Gopal Singh Sirvi

2
Respondi minha própria sub-pergunta, para torná-la sempre visível sem a necessidade de clicar no botão de pesquisa e adicionar a linha searchView.setIconifiedByDefault(false);à onCreateOptionsMenufunção.
Adelriosantiago 17/11/2015

3
outro detalhe útil - se você deseja que a exibição da pesquisa seja expandida inicialmente, verifique se você tem app:showAsAction="always"e NÃOapp:showAsAction="ifRoom|collapseActionView"
Vinay W

1
Além disso, usando esse método, mesmo quando a barra de pesquisa é expandida, o OverflowIcon ainda está visível (ou seja, os 3 pontos). Mas alguns aplicativos lidam com a pesquisa, expandindo-a completamente e alterando o plano de fundo para branco. Como GMail
Zen

83

Depois de uma semana de intrigas sobre isso. Eu acho que descobri.
Agora estou usando apenas um EditText dentro da barra de ferramentas. Isso me foi sugerido pelo oj88 no reddit.

Agora tenho o seguinte:
Nova Pesquisa

Primeiro, dentro do onCreate () da minha atividade, adicionei o EditText com uma visualização de imagem no lado direito da barra de ferramentas, como segue:

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

Isso funcionou, mas então me deparei com um problema em que onOptionsItemSelected () não estava sendo chamado quando toquei no botão home. Portanto, não pude cancelar a pesquisa pressionando o botão home. Tentei algumas maneiras diferentes de registrar o ouvinte de cliques no botão home, mas elas não funcionaram.

Eventualmente, descobri que o ActionBarDrawerToggle estava interferindo nas coisas, então o removi. Este ouvinte começou a trabalhar:

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

Portanto, agora posso cancelar a pesquisa com o botão home, mas não posso pressionar o botão voltar para cancelar ainda. Então eu adicionei isso ao 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;
        }
    }

Eu criei este método para alternar a visibilidade do EditText e do item de 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);
    }
}

Eu precisava de uma maneira de alternar o botão home na barra de ferramentas entre o ícone da gaveta e o botão voltar. Acabei encontrando o método abaixo nesta resposta SO . Embora eu tenha modificado um pouco para fazer mais sentido para mim:

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

Isso funciona, eu consegui resolver alguns bugs que encontrei ao longo do caminho. Eu não acho que é 100%, mas funciona bem o suficiente para mim.

EDIT: Se você deseja adicionar a exibição de pesquisa em XML em vez de Java, faça o seguinte:

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 () da sua atividade:

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

Funciona muito bem, parece ótimo, obrigado! No entanto, em vez de criar os layouts no código, criei o LinearLayout com o EditText e o ImageView em xml e apenas o insuflei no onCreate.
aluxian

Sim, tentei fazer isso em XML, mas pensei que estava fazendo algo errado, pois o Android Studio não me daria o preenchimento automático no XML do layout.
Mike

Você pode atualizar esta resposta com o respectivo layout de layout XML necessário para isso? isso pode ajudar outros muito bem.
Shreyash Mahajan /

1
@ Mike Você pode atualizar sua resposta e colocar seu código fonte completo do github?
Hamed Ghadirian

1
por favor poste o projeto completo no github
Nilabja


19

A primeira captura de tela da sua pergunta não é um widget público. O suporte SearchView ( android.support.v7.widget.SearchView) imita o SearchView ( ) do Android 5.0 Lollipop android.widget.SearchView. Sua segunda captura de tela é usada por outros aplicativos projetados por material, como o Google Play.

O SearchView na sua primeira captura de tela é usado no Drive, YouTube e outro Google Apps de código fechado. Felizmente, também é usado no Android 5.0 Dialer . Você pode tentar fazer o backport da exibição, mas ele usa algumas APIs 5.0.

As classes que você deseja consultar são:

SearchEditTextLayout , AnimUtils e DialtactsActivity para entender como usar a Visualização. Você também precisará de recursos do ContactsCommon .

Boa sorte.


Obrigado por investigar isso, eu esperava que já houvesse algo que pudesse fazer isso. Por enquanto, acabei de usar um EditText com um plano de fundo transparente e parece adequado para o que eu preciso.
Mike

111
Esta resposta é muito perturbadora para mim. Por que o Google usa um widget privado que coincide com suas próprias diretrizes de design de material e depois publica um widget ruim para nós que não usa? E todo desenvolvedor agora está por aí lutando com isso sozinho? Que raciocínio possível para isso?
Greg Ennis

18

Aqui está minha tentativa de fazer isso:

Etapa 1: criar um estilo chamado 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>

Etapa 2: criar um layout chamado 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" />  

Etapa 3: criar um item de menu para esta exibição de pesquisa

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

Etapa 4: Inflar o menu

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

Resultado:

insira a descrição da imagem aqui

A única coisa que eu não era capaz de fazer era preencher toda a largura do arquivo Toolbar. Se alguém pudesse me ajudar a fazer isso, seria dourado.


1
I wasn't able to do was to make it fill the entire width, qual versão da biblioteca de suporte você está usando? Tente configurar app:contentInsetStartWithNavigation="0dp"a sua barra de ferramentas.
Mangesh

@ LittleChild, tente a solução dada por Magnesh. Se ainda assim não for resolvido, tente adicionar as linhas abaixo na barra de ferramentas. app: contentInsetStartWithNavigation = "0dp" app: contentInsetLeft = "0dp" app: contentInsetStart = "0dp" app: paddingStart = "0dp" android: layout_marginLeft = "0dp" android: layout_marginStart = "0dp"
Shreyash Mahajan

Obrigado por colocar uma explicação para cada linha no SearchViewStyle!
21818 Shinta S

Criança pequena Para toda a largura, você pode fazer sth assim: (" stackoverflow.com/questions/27946569/… )
Ali_dev

10

Para obter a aparência desejada do SearchView, você pode usar estilos.

Primeiro, você precisa criar stylepara o seu SearchView, que deve ser algo como isto:

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

Lista inteira de atributos que você pode encontrar neste artigo, na seção "SearchView".

Em segundo lugar, você precisa criar um stylepara o seu Toolbar, que é usado como ActionBar:

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

E, finalmente, você precisa atualizar o atributo do tema da barra de ferramentas da seguinte maneira:

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

Resultado:

insira a descrição da imagem aqui

NOTA: Você precisa alterar Toolbardiretamente o atributo do tema. Se você apenas atualizar seu searchViewStyleatributo de tema principal , isso não afetará o seu Toolbar.


Ei, você adicionou esses ícones navigate-back(seta para trás) e cancel(x) ou eles foram adicionados automaticamente?
Solace

1
@Solace eles são adicionados automaticamente
Artem

Eles aparecem apenas quando você começa a escrever a consulta de pesquisa no SearchView ou estão lá mesmo quando você não escreveu nada e a dica de pesquisa está visível? Estou perguntando porque o meu não aparece até eu começar a escrever a consulta. Portanto, esta informação será muito útil para mim
Solace

1
O @Solace navigate-backé sempre mostrado, clearé mostrado somente depois que você escreve alguma consulta de pesquisa.
Artem

6

Outra maneira de obter o efeito desejado é usar esta biblioteca de exibição de pesquisa de material . Ele lida com o histórico de pesquisa automaticamente e também é possível fornecer sugestões de pesquisa para a visualização.

Amostra: (É exibido em português, mas também funciona em inglês e italiano).

Amostra

Configuração

Antes de poder usar essa lib, você deve implementar uma classe nomeada MsvAuthoritydentro do br.com.maukerpacote no seu módulo de aplicativo e ela deve ter uma variável String estática pública chamada CONTENT_AUTHORITY. Dê o valor que você deseja e não se esqueça de adicionar o mesmo nome ao seu arquivo de manifesto. A lib usará esse arquivo para definir a autoridade do provedor de conteúdo.

Exemplo:

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>

Uso

Para usá-lo, adicione a dependência:

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

E então, no seu Activityarquivo de layout, adicione o seguinte:

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

Depois disso, você só precisará obter a MaterialSearchViewreferência usando getViewById()e abrir ou fechá-la usando MaterialSearchView#openSearch()e MaterialSearchView#closeSearch().

PS: É possível abrir e fechar a visualização, não apenas a partir do Toolbar. Você pode usar o openSearch()método de basicamente qualquer Button, como um botão de ação flutuante.

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

Você também pode fechar a exibição usando o botão Voltar, fazendo o seguinte:

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

Para mais informações sobre como usar a lib, consulte a página do github .


2
Excelente biblioteca e ótima idéia de abstrair o método de abrir / fechar para que um MenuItem não seja necessário para abri-lo / fechado, planejo usá-lo no meu aplicativo com um FloatingActionButton com um ícone de pesquisa, para que ele funcione perfeitamente.
precisa saber é o seguinte

Por que não existem parâmetros para cadeias de caracteres como "Pesquisar"? Parece que a biblioteca limita as pessoas a versões em inglês ou em português da string: /
Aspiring Dev

Mas é possível alterar a dica String usando estilos, conforme indicado no README. Quanto à dica de entrada de voz, ela será lançada mais tarde: github.com/Mauker1/MaterialSearchView/issues/23
Mauker

@rpgmaker Verifique a atualização mais recente, agora é possível alterar essas strings.
Mauker 31/10/16

@ Maraker alguma idéia de como definir android: imeOptions = "actionSearch" para o EditText do seu componente? (Eu quero exibir um botão de "pesquisa" no teclado)
Greg

2

A seguir, será criado um SearchView idêntico ao do Gmail e será adicionado à barra de ferramentas fornecida. Você apenas precisará implementar seu próprio método "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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.