Tworzenie widoku wyszukiwania, który wygląda jak wytyczne dotyczące projektowania materiałów

134

Obecnie uczę się, jak przekonwertować moją aplikację na Material Design i trochę utknąłem. Dodałem pasek narzędzi, a moja szuflada nawigacyjna nakłada całą zawartość.

Próbuję teraz utworzyć rozwijane wyszukiwanie, które wygląda tak, jak w wytycznych dotyczących materiałów : wprowadź opis obrazu tutaj

Oto, co mam teraz i nie mogę wymyślić, jak to zrobić, jak powyżej:
Moje wyszukiwanie

To jest moje 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>

To działa, otrzymuję element menu, który rozwija się do SearchView i mogę dobrze filtrować moją listę. Nie wygląda to jednak w żaden sposób jak na pierwszym zdjęciu.

Próbowałem użyć MenuItemCompat.setOnActionExpandListener()na R.id.action_searchtak mogę zmienić ikonę domowego do tyłu strzałkę, ale to nie wydają się działać. W słuchaczu nic nie odpala. Nawet gdyby to zadziałało, nadal nie byłoby bardzo zbliżone do pierwszego obrazu.

Jak utworzyć SearchView na nowym pasku narzędziowym appcompat, który wygląda jak wytyczne dotyczące materiałów?

Mikrofon
źródło
6
app: showAsAction = "always | collapseActionView"
Pavlos,
Możesz
rzucić

Odpowiedzi:

152

W rzeczywistości jest to całkiem łatwe, jeśli używasz android.support.v7biblioteki.

Krok 1

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

Krok 2

Rozszerz AppCompatActivityiw onCreateOptionsMenukonfiguracji 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;
    }

    ... 

}

Wynik

wprowadź opis obrazu tutaj

wprowadź opis obrazu tutaj

Subin Sebastian
źródło
2
Głosowałem za tym, ale którego emulatora używasz? Próbowałem, ale nie dostaję navigate-backprzycisku, a raczej ikonę wyszukiwania, a jego odległość od lewej krawędzi ekranu nie jest taka sama jak między Xikoną a prawą krawędzią ekranu (nie mam przepełnienie akcji). Opublikowałem pytanie tutaj , czy możesz się temu przyjrzeć?
Solace
13
to nie jest poszukiwanie materiału. to tylko zwykłe stare wyszukiwanie w pasku akcji
Gopal Singh Sirvi
2
Odpowiedziałem na własne pytanie podrzędne, aby było ono zawsze widoczne bez konieczności klikania przycisku wyszukiwania, dodaj linię searchView.setIconifiedByDefault(false);do onCreateOptionsMenufunkcji.
adelriosantiago
3
kolejna przydatna ciekawostka - jeśli chcesz początkowo rozszerzyć widok wyszukiwania, upewnij się, że masz app:showAsAction="always"i NIEapp:showAsAction="ifRoom|collapseActionView"
Vinay W
1
Również przy użyciu tej metody, nawet gdy searchBar jest rozwinięta, OverflowIcon jest nadal widoczny (tj. 3 kropki). Ale niektóre aplikacje obsługują wyszukiwanie, rozszerzając je całkowicie i zmieniając tło na białe. Podobnie jak GMail
Zen
83

Po tygodniu zastanawiania się nad tym. Myślę, że to rozgryzłem.
Teraz używam tylko EditText na pasku narzędzi. Zasugerował mi to oj88 na reddicie.

Mam teraz to:
Nowy widok wyszukiwania

Najpierw w onCreate () mojej aktywności dodałem EditText z widokiem obrazu po prawej stronie do paska narzędzi w następujący sposób:

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

To zadziałało, ale potem natknąłem się na problem polegający na tym, że onOptionsItemSelected () nie był wywoływany po dotknięciu przycisku strony głównej. Nie mogłem więc anulować wyszukiwania, naciskając przycisk strony głównej. Wypróbowałem kilka różnych sposobów rejestrowania odbiornika kliknięć na przycisku strony głównej, ale nie zadziałały.

W końcu dowiedziałem się, że ActionBarDrawerToggle, który miałem, przeszkadza, więc go usunąłem. Ten słuchacz zaczął wtedy pracować:

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

Mogę więc teraz anulować wyszukiwanie za pomocą przycisku strony głównej, ale nie mogę jeszcze nacisnąć przycisku Wstecz, aby je anulować. Więc dodałem to do 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;
        }
    }

Utworzyłem tę metodę, aby przełączać widoczność EditText i pozycji 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);
    }
}

Potrzebowałem sposobu, aby przełączyć przycisk strony głównej na pasku narzędzi między ikoną szuflady a przyciskiem Wstecz. W końcu znalazłem metodę poniżej w tej odpowiedzi TAK . Chociaż nieco to zmodyfikowałem, aby miało dla mnie więcej sensu:

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

To działa, udało mi się rozwiązać kilka błędów, które znalazłem po drodze. Nie wydaje mi się, żeby to było w 100%, ale dla mnie działa wystarczająco dobrze.

EDYCJA: Jeśli chcesz dodać widok wyszukiwania w XML zamiast w Javie, zrób to:

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 () Twojej aktywności:

    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);
Mikrofon
źródło
Działa świetnie, wygląda świetnie, dziękuję! Jednak zamiast tworzyć układy w kodzie, utworzyłem LinearLayout z EditText i ImageView w xml i po prostu nadmuchałem go w onCreate.
aluxian
Tak, próbowałem to zrobić w XML, ale pomyślałem, że robię coś nie tak, ponieważ Android Studio nie daje mi autouzupełniania w układzie XML.
Mike
Czy możesz zaktualizować tę odpowiedź o wymagany do tego projekt układu XML? to może bardzo dobrze pomóc innym.
Shreyash Mahajan
1
@Mike Czy możesz zaktualizować swoją odpowiedź i zamieścić cały kod źródłowy github?
Hamed Ghadirian,
1
proszę opublikować cały projekt na github
Nilabja
22

Wiem, że to stary wątek, ale wciąż publikuję bibliotekę, którą właśnie stworzyłem. Mam nadzieję, że to może komuś pomóc.

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

Widok wyszukiwania materiału

ShahrozKhan91
źródło
1
To nie jest trudne, ale lubię twoją pracę. Tworzenie własnego widoku wyszukiwania oszczędza mój czas. Dzięki stary!
Slim_user71169
19

Pierwszy zrzut ekranu w Twoim pytaniu nie jest publicznym widżetem. Obsługa SearchView ( android.support.v7.widget.SearchView) naśladuje funkcję SearchView ( ) systemu Android 5.0 Lollipop android.widget.SearchView. Twój drugi zrzut ekranu jest używany przez inne aplikacje zaprojektowane dla materiałów, takie jak Google Play.

Widok wyszukiwania na pierwszym zrzucie ekranu jest używany w Dysku, YouTube i innych Google Apps o zamkniętym kodzie źródłowym. Na szczęście jest również używany w programie Android 5.0 Dialer . Możesz spróbować przenieść widok wstecz, ale używa on niektórych interfejsów API 5.0.

Klasy, którym będziesz chciał się przyjrzeć, to:

SearchEditTextLayout , AnimUtils i DialtactsActivity, aby zrozumieć, jak używać widoku. Będziesz także potrzebować zasobów z ContactsCommon .

Powodzenia.

Jared Rummler
źródło
Dzięki za przyjrzenie się temu, miałem nadzieję, że jest już coś, co mogłoby to zrobić. Na razie właśnie użyłem EditText z przezroczystym tłem i wydaje mi się, że jest to w porządku, czego potrzebuję.
Mike
111
Ta odpowiedź jest dla mnie bardzo niepokojąca. Dlaczego Google używa prywatnego widżetu, który przypadkiem pasuje do jej własnych wytycznych dotyczących projektowania materiałów, a następnie publikuje dla nas kiepski widżet, który tego nie robi? A teraz każdy programista zmaga się z tym samodzielnie? Jaki jest tego powód?
Greg Ennis
18

Oto moja próba zrobienia tego:

Krok 1: Utwórz styl o nazwie 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>

Krok 2: Utwórz układ o nazwie 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" />  

Krok 3: Utwórz element menu dla tego widoku wyszukiwania

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

Krok 4: Napompuj menu

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

Wynik:

wprowadź opis obrazu tutaj

Jedyne, czego nie byłem w stanie zrobić, to sprawić, by wypełnił całą szerokość Toolbar. Gdyby ktoś mógł mi w tym pomóc, to byłby złoty.

Użytkownik SO
źródło
1
I wasn't able to do was to make it fill the entire width, której wersji biblioteki obsługi używasz? Spróbuj ustawić app:contentInsetStartWithNavigation="0dp"pasek narzędzi.
Mangesh
@LittleChild, wypróbuj rozwiązanie podane przez Magnesha. Jeśli nadal nie zostanie rozwiązany, spróbuj dodać poniższe linie na pasku narzędzi. app: contentInsetStartWithNavigation = "0dp" app: contentInsetLeft = "0dp" app: contentInsetStart = "0dp" app: paddingStart = "0dp" android: layout_marginLeft = "0dp" android: layout_marginStart = "0dp"
Shreyash at Mahajan
Dziękujemy za umieszczenie wyjaśnienia dla każdego wiersza w SearchViewStyle!
Shinta S,
Małe dziecko Na całą szerokość możesz zrobić coś w ten sposób: (" stackoverflow.com/questions/27946569/… )
Ali_dev
10

Aby uzyskać pożądany wygląd SearchView, możesz użyć stylów.

Najpierw musisz utworzyć styledla swojego SearchView widok, który powinien wyglądać mniej więcej tak:

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

Pełną listę atrybutów można znaleźć w tym artykule w sekcji „SearchView”.

Po drugie, musisz utworzyć styledla swojego Toolbar, który jest używany jako ActionBar:

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

Na koniec musisz zaktualizować atrybut motywu paska Toolbar w ten sposób:

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

Wynik:

wprowadź opis obrazu tutaj

UWAGA: Musisz bezpośrednio zmienić Toolbaratrybut motywu. Jeśli po prostu zaktualizujesz swój główny searchViewStyleatrybut motywu , nie wpłynie to na twoje Toolbar.

Artem
źródło
Hej, czy sam dodałeś te navigate-back(strzałka wstecz) i cancel(x) ikony, czy zostały dodane automatycznie?
Solace
1
@ Solace są dodawane automatycznie
Artem
Czy pojawiają się one tylko wtedy, gdy zaczynasz pisać zapytanie wyszukiwania w SearchView, czy też są tam, nawet jeśli nic nie napisałeś, a wskazówka dotycząca wyszukiwania jest widoczna? Pytam bo moje nie pojawiają się dopóki nie zacznę pisać zapytania. Więc te informacje będą dla mnie bardzo przydatne
Solace
1
@ Solace navigate-backjest zawsze wyświetlane, clearjest wyświetlane dopiero po wpisaniu zapytania wyszukiwania.
Artem
6

Innym sposobem na osiągnięcie pożądanego efektu jest użycie tej biblioteki Material Search View . Obsługuje automatycznie historię wyszukiwania i możliwe jest również dostarczanie sugestii wyszukiwania do widoku.

Przykład: (jest wyświetlany w języku portugalskim, ale działa również w języku angielskim i włoskim).

Próba

Ustawiać

Zanim będzie można użyć tej biblioteki, należy zaimplementować klasę o nazwie MsvAuthoritywewnątrz br.com.maukerpakietu w module aplikacji i powinna ona mieć publiczną statyczną zmienną String o nazwie CONTENT_AUTHORITY. Nadaj mu żądaną wartość i nie zapomnij dodać tej samej nazwy w pliku manifestu. Biblioteka użyje tego pliku do ustawienia uprawnień dostawcy treści.

Przykład:

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>

Stosowanie

Aby z niego skorzystać, dodaj zależność:

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

Następnie w Activitypliku układu dodaj następujące elementy:

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

Następnie wystarczy pobrać MaterialSearchViewodniesienie za pomocą getViewById()i otworzyć lub zamknąć za pomocą MaterialSearchView#openSearch()i MaterialSearchView#closeSearch().

PS: Otwieranie i zamykanie widoku jest możliwe nie tylko z poziomu Toolbar. Możesz użyć openSearch()metody z praktycznie dowolnego Button, takiego jak pływający przycisk akcji.

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

Możesz również zamknąć widok za pomocą przycisku Wstecz, wykonując następujące czynności:

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

Aby uzyskać więcej informacji na temat korzystania z biblioteki, odwiedź stronę github .

Mauker
źródło
2
Doskonała biblioteka i świetny pomysł na abstrakcję metody otwierania / zamykania, aby MenuItem nie było wymagane do jej otwierania / zamykania, planuję użyć tego w mojej aplikacji z FloatingActionButton z ikoną wyszukiwania, więc będzie działać świetnie.
AdamMc331
Dlaczego nie ma parametrów dla ciągów, takich jak „Wyszukaj”? Wygląda na to, że biblioteka ogranicza ludzi do angielskiej lub portugalskiej wersji ciągu: /
Aspiring Dev
Ale można zmienić ciąg podpowiedzi, używając stylów, jak podano w pliku README. Jeśli chodzi o wskazówkę dotyczącą wprowadzania głosowego, zostanie ona wydana później: github.com/Mauker1/MaterialSearchView/issues/23
Mauker
@rpgmaker Sprawdź najnowszą aktualizację, teraz można zmienić te ciągi.
Mauker
@Mauker masz pomysł, jak ustawić android: imeOptions = "actionSearch" na EditText twojego komponentu? (Chcę wyświetlić przycisk „Szukaj” na klawiaturze)
Greg
2

Poniższe czynności utworzą widok wyszukiwania identyczny z tym w Gmailu i dodają go do danego paska narzędzi. Musisz tylko zaimplementować własną metodę „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;
}

źródło