Implementieren von SearchView gemäß den Material Design Guidelines
Lesezeit: 22 Minuten
GunnerFan
Ich habe nach Möglichkeiten gesucht, eine Suchansicht in der Aktivitätssymbolleiste (Actionbar) gemäß der zu implementieren Richtlinien für Materialdesign.
Wenn Sie auf das Suchsymbol klicken, wird die gesamte Symbolleiste so animiert, dass nur die Suche EditText mit weißem Hintergrund mit Vorschlägen in der Hauptansicht anstelle eines Dropdown-Menüs angezeigt wird.
Hier ist ein Screenshot aus den Richtlinien:
Hier ist ein GIF aus der Gmail-Inbox-Implementierung:
Ich habe nach Codebeispielen und Tutorials gesucht, aber bisher war ich erfolglos. Wie mache ich das?
ist das nicht ein Duplikat von stackoverflow.com/questions/27556623/… ?
– Adam Burley
26. Januar 2021 um 17:11 Uhr
schnizlon
Ich habe mehrere SearchView-Materialbibliotheken ausprobiert, aber keine davon hat so gut funktioniert wie die aus der Support-Bibliothek, also habe ich mich entschieden, sie neu zu gestalten. Nach viel Arbeit bin ich mit dem Ergebnis zufrieden:
So können Sie es tun:
1) Fügen Sie das SearchView-Element zu Ihrem Menü hinzu
Beachten Sie, dass ich erkläre AktionLayout Anstatt von actionViewClassdachte ich, dass dies die einzige Möglichkeit ist, das SearchView-Design separat vom Toolbar-Design festzulegen.
(ändern Sie die Sichtbarkeit von suggestion_divider, wenn Sie eine Trennlinie zwischen den Vorschlägen wünschen):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="58dp"
android:theme="@style/Theme.AppCompat.DayNight">
<!-- Icons come first in the layout, since their placement doesn't depend on
the placement of the text views. -->
<ImageView
android:id="@android:id/icon1"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:scaleType="centerInside"
android:visibility="invisible" />
<ImageView
android:id="@+id/edit_query"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:background="?attr/selectableItemBackground"
android:scaleType="centerInside"
android:visibility="gone" />
<ImageView
android:id="@id/android:icon2"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon2"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:scaleType="centerInside"
android:visibility="gone" />
<!-- The subtitle comes before the title, since the height of the title depends on whether the
subtitle is visible or gone. -->
<TextView
android:id="@android:id/text2"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="29dp"
android:layout_alignParentBottom="true"
android:layout_alignWithParentIfMissing="true"
android:gravity="top"
android:maxLines="1"
android:paddingBottom="4dp"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
android:visibility="gone" />
<!-- The title is placed above the subtitle, if there is one. If there is no
subtitle, it fills the parent. -->
<TextView
android:id="@android:id/text1"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@android:id/text2"
android:layout_centerVertical="true"
android:ellipsize="end"
android:maxLines="1"
android:scrollHorizontally="false"
android:textColor="?android:textColorPrimary"
android:textSize="16sp" />
<View
android:id="@+id/suggestion_divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:layout_alignStart="@android:id/text1"
android:layout_marginStart="8dp"
android:background="@color/divider_color"
android:visibility="gone" />
Der Vorschlagshintergrund und das Commit-Symbol sind maßgefertigt, die restlichen Symbole, die ich verwendet habe, finden Sie unter: https://material.io/icons/
1) Die Animation passt ihren Startpunkt basierend auf Ihrer Anzahl von Menüelementen an und wenn die Symbolleiste ein Überlaufsymbol hat, erkennt sie automatisch, ob das Layout LTR oder RTL ist.
2) Ich verwende die Aktivität der Navigationsleiste, also setze ich die StatusBar-Farbe auf mDrawerLayout. Wenn Sie regelmäßige Aktivitäten verwenden, können Sie die StatusBar-Farbe auf diese Weise festlegen:
3) Die kreisförmige Enthüllungsanimation funktioniert nur auf KitKat und höher.
Das sieht toll aus, könntest du es vielleicht auf Github stellen? Wo Sie die Datei toolbar_search_view.xml erstellen, befindet sich diese appbarlayout-XML in derselben Datei?
– zen_1991
19. Januar 2017 um 7:10 Uhr
Ich habe hinzufügen circleReveal-Animation mit Bibliothek von Drittanbietern unter Lollipop Setzen Sie einfach die Symbolleiste in das Rahmenlayout io.codetail.widget.RevealFrameLayout und importieren Sie io.codetail.animation.ViewAnimationUtils anstelle der Android-Klasse und sehen Sie die Magie
– Zohaib Akram
1. Februar 2017 um 13:06 Uhr
Beachten Sie, dass toolbar_search_view.xml eine geänderte Kopie von abc_search_view.xml aus der Support-Bibliothek ist, die für Apache 2.0 lizenziert ist. Wenn Sie dies verwenden, sollten Sie also sicherstellen, dass Sie diese Lizenz einhalten.
– Simon Warta
21. Mai 2017 um 16:08 Uhr
„android:popupElevation“ funktioniert nur mit Android 5.0+. Aber ich brauche das für Android 4.3.
– Alexej
17. Oktober 2017 um 10:30 Uhr
Sie verwenden ein dunkles actionBar-Design, daher sind der Titel und die Symbole weiß (in Ihrem Beispiel auf einem hellblauen Hintergrund), aber wenn die Suche erweitert wird, sind die Farben jetzt grau. Wie erreichen Sie das? meins ist immer noch weiß, also ist es weiß auf weiß …
– ndori
15. August 2018 um 7:16 Uhr
Jigar Brahmbhatt
Dies ist eigentlich ganz einfach, wenn Sie die Bibliothek android.support.v7 verwenden.
Die Auto-Complete-Demo kann in der Beispiel-App im Abschnitt „Demos“ angehört werden.
Ich glaube du hast meine Frage falsch verstanden oder ich habe sie nicht richtig formuliert. Meine Frage bezog sich auf die Implementierung des UI-Teils und nicht auf die Textüberwachungs- und Filterlogik – ob Android Widgets (wie ActionBar, Menüelemente usw.) hat, die bei der Implementierung dieser Ansicht gemäß den Materialdesignrichtlinien helfen? Es stellt sich heraus, dass es keine solchen Widgets gibt und Sie die Symbolleiste selbst erstellen müssen. Sobald Sie dies herausgefunden haben, können wir Ihre Antwort verwenden, um die Filter- und Textüberwachungslogik zu erstellen. Obwohl ich Ihre Antwort positiv bewertet und für nützlich befunden habe, habe ich sie nicht akzeptiert, da sie nur einen Teil der Frage beantwortet.
– GunnerFan
7. August 2015 um 11:38 Uhr
Ausgehend von einem Hinweis aus der Antwort von @ Zielony habe ich Folgendes getan:
1) Stattdessen habe ich bei Verwendung einer ActionBar oder ToolBar mein eigenes Layout erstellt (im Grunde ein RelativeLayout mit Burger-Menü, Suche und anderen Menüschaltflächen und einem EditText für die Suche)
2) Ich habe ein Design ohne ActionBar verwendet und mein benutzerdefiniertes Layout oben in der Aktivität platziert, sodass es wie eine ActionBar aussah.
3) Im OnClickListener der Suchschaltfläche mache ich zwei Dinge:
Blenden Sie die Menüschaltflächen aus und zeigen Sie den ‘Such’-Bearbeitungstext an.
Fügen Sie ein Fragment hinzu, um Suchvorschläge anzuzeigen und zu suchen
Zeigen Sie die Softkeyboard-Eingabe an
3) OnClickListeners für die anderen Menüschaltflächen hinzugefügt.
4) Einen TextWatcher auf der „Suche“ EditText hinzugefügt, um Suchhinweise und Ergebnisse vom Server anzuzeigen.
So sieht es jetzt aus:
Ich glaube, ich habe es herausgefunden. Ich verwende jetzt nur einen EditText innerhalb der Symbolleiste.
Ich habe jetzt das:
Zuerst habe ich in onCreate() meiner Aktivität den EditText mit einer Bildansicht auf der rechten Seite wie folgt zur Symbolleiste hinzugefügt:
// Setup search container view
searchContainer = new LinearLayout(this);
Toolbar.LayoutParams containerParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
containerParams.gravity = Gravity.CENTER_VERTICAL;
searchContainer.setLayoutParams(containerParams);
// Setup search view
toolbarSearchView = new EditText(this);
// Set width / height / gravity
int[] textSizeAttr = new int[]{android.R.attr.actionBarSize};
int indexOfAttrTextSize = 0;
TypedArray a = obtainStyledAttributes(new TypedValue().data, textSizeAttr);
int actionBarHeight = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
a.recycle();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, actionBarHeight);
params.gravity = Gravity.CENTER_VERTICAL;
params.weight = 1;
toolbarSearchView.setLayoutParams(params);
// Setup display
toolbarSearchView.setBackgroundColor(Color.TRANSPARENT);
toolbarSearchView.setPadding(2, 0, 0, 0);
toolbarSearchView.setTextColor(Color.WHITE);
toolbarSearchView.setGravity(Gravity.CENTER_VERTICAL);
toolbarSearchView.setSingleLine(true);
toolbarSearchView.setImeActionLabel("Search", EditorInfo.IME_ACTION_UNSPECIFIED);
toolbarSearchView.setHint("Search");
toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
try {
// Set cursor colour to white
// http://stackoverflow.com/a/26544231/1692770
// https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
} catch (Exception ignored) {
}
// Search text changed listener
toolbarSearchView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
if (mainFragment != null && mainFragment instanceof MainListFragment) {
((MainListFragment) mainFragment).search(s.toString());
}
}
@Override
public void afterTextChanged(Editable s) {
// http://stackoverflow.com/a/6438918/1692770
if (s.toString().length() <= 0) {
toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
}
}
});
((LinearLayout) searchContainer).addView(toolbarSearchView);
// Setup the clear button
searchClearButton = new ImageView(this);
Resources r = getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, r.getDisplayMetrics());
LinearLayout.LayoutParams clearParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
clearParams.gravity = Gravity.CENTER;
searchClearButton.setLayoutParams(clearParams);
searchClearButton.setImageResource(R.drawable.ic_close_white_24dp); // TODO: Get this image from here: https://github.com/google/material-design-icons
searchClearButton.setPadding(px, 0, px, 0);
searchClearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toolbarSearchView.setText("");
}
});
((LinearLayout) searchContainer).addView(searchClearButton);
// Add search view to toolbar and hide it
searchContainer.setVisibility(View.GONE);
toolbar.addView(searchContainer);
Das hat funktioniert, aber dann bin ich auf ein Problem gestoßen, bei dem onOptionsItemSelected() nicht aufgerufen wurde, als ich auf die Home-Schaltfläche getippt habe. Daher konnte ich die Suche nicht durch Drücken der Home-Taste abbrechen. Ich habe verschiedene Möglichkeiten ausprobiert, den Klick-Listener auf der Home-Schaltfläche zu registrieren, aber sie haben nicht funktioniert.
Irgendwann fand ich heraus, dass der ActionBarDrawerToggle, den ich hatte, die Dinge störte, also habe ich ihn entfernt. Dieser Listener begann dann zu arbeiten:
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));
}
});
So kann ich jetzt die Suche mit dem Home-Button abbrechen, aber ich kann noch nicht den Zurück-Button drücken, um sie abzubrechen. Also habe ich dies zu onBackPressed() hinzugefügt:
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;
}
}
Ich habe diese Methode erstellt, um die Sichtbarkeit des EditText- und Menüelements umzuschalten:
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);
}
}
Ich brauchte eine Möglichkeit, die Home-Schaltfläche in der Symbolleiste zwischen dem Schubladensymbol und der Zurück-Schaltfläche umzuschalten. Ich habe schließlich die folgende Methode in dieser SO-Antwort gefunden. Obwohl ich es leicht modifiziert habe, um es für mich sinnvoller zu machen:
Das funktioniert, ich habe es geschafft, ein paar Fehler zu beheben, die ich auf dem Weg gefunden habe. Ich glaube nicht, dass es 100% ist, aber es funktioniert gut genug für mich. BEARBEITEN: Wenn Sie die Suchansicht in XML anstelle von Java hinzufügen möchten, tun Sie dies:
Sie können AutoCompleteTextView verwenden, um dies zu erreichen, folgen Sie dem Link unten
Wie erstelle ich ein Gmail-ähnliches Suchfeld in der Aktionsleiste?
Ich habe das schon. Ich möchte es gemäß den Materialdesignrichtlinien implementieren. Beachten Sie, wie Vorschläge in der Hauptansicht statt in der Dropdown-Liste angezeigt werden.
– GunnerFan
21. Mai 2015 um 9:28 Uhr
11761000cookie-checkImplementieren von SearchView gemäß den Material Design Guidelinesyes
ist das nicht ein Duplikat von stackoverflow.com/questions/27556623/… ?
– Adam Burley
26. Januar 2021 um 17:11 Uhr