Создание SearchView, который выглядит как руководство по разработке материалов

В настоящее время я изучаю, как конвертировать свое приложение в Material Design, и сейчас я немного застрял. У меня есть панель инструментов, и я сделал свой навигационный ящик наложением всего содержимого.

Теперь я пытаюсь создать расширяемый поиск, который похож на тот, который содержится в основных принципах : введите описание изображения здесь

Это то, что у меня есть прямо сейчас, и я не могу понять, как сделать это как выше:
Мой поиск

Это мое меню xml:

    

Это работает, я получаю элемент меню, который расширяется до SearchView, и я могу фильтровать свой список в порядке. Однако это не похоже на 1-ю картинку.

Я попытался использовать MenuItemCompat.setOnActionExpandListener() на R.id.action_search чтобы я мог изменить значок дома на стрелку назад, но это, похоже, не работает. Ничего не увольняют слушателя. Даже если бы это сработало, все равно было бы не очень близко к 1-му изображению.

Как создать SearchView в новой панели инструментов appompat, которая выглядит как материальные рекомендации?

На самом деле это довольно легко сделать, если вы используете библиотеку android.support.v7 .

Шаг 1

Объявление пункта меню

  

Шаг 2

Расширьте AppCompatActivity и в onCreateOptionsMenu настройте 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; } ... } 

результат

введите описание изображения здесь

введите описание изображения здесь

Через неделю это озадачило. Кажется, я понял это.
Теперь я использую только EditText внутри панели инструментов. Это было предложено мне oj88 по reddit.

У меня теперь есть следующее:
Новый SearchView

Сначала внутри onCreate () моей активности я добавил EditText с изображением справа на панели инструментов следующим образом:

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

Это сработало, но потом я столкнулся с проблемой, когда onOptionsItemSelected () не вызывался, когда я постучал по домашней кнопке. Поэтому я не смог отменить поиск, нажав кнопку «Домой». Я попробовал несколько разных способов регистрации прослушивателя кликов на домашней кнопке, но они не работали.

В конце концов, я узнал, что у ActionBarDrawerToggle у меня было вмешательство в дела, поэтому я удалил его. Затем слушатель начал работать:

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

Поэтому теперь я могу отменить поиск с помощью кнопки «домой», но я не могу нажать кнопку «Назад», чтобы отменить ее. Поэтому я добавил это в 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; } } 

Я создал этот метод для переключения видимости EditText и пункта меню:

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

Мне нужен был способ переключить кнопку «Дом» на панели инструментов между значком ящика и кнопкой «Назад». В конце концов я нашел метод ниже в этом SO-ответе . Хотя я немного изменил его, чтобы иметь больше смысла для меня:

 private enum ActionDrawableState { BURGER, ARROW } /** * Modified version of this, https://stackoverflow.com/a/26836272/1692770
* I flipped the start offset around for the animations because it seemed like it was the wrong way around to me.
* 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); } } }

Это работает, мне удалось выработать несколько ошибок, которые я нашел на этом пути. Я не думаю, что это 100%, но он работает достаточно хорошо для меня.

EDIT: если вы хотите добавить представление поиска в XML вместо Java, выполните следующие действия:

toolbar.xml:

       

onCreate () вашей деятельности:

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

Я знаю его старую нить, но все равно публикую только что созданную библиотеку. Надеюсь, это может помочь кому-то.

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

Метрический поиск

Первый скриншот в вашем вопросе не является общедоступным виджетами. Поддержка SearchView ( android.support.v7.widget.SearchView ) имитирует поисковый запрос Android 5.0 Lollipop ( android.widget.SearchView ). Второй скриншот используется другими приложениями, разработанными на основе материалов, такими как Google Play.

SearchView в вашем первом скриншоте используется на Диске, YouTube и других закрытых источниках Google Apps. К счастью, он также используется в Android 5.0 Dialer . Вы можете попытаться выполнить резервное копирование представления, но оно использует некоторые API 5.0.

Классы, которые вы хотите посмотреть:

SearchEditTextLayout , AnimUtils и DialtactsActivity, чтобы понять, как использовать представление. Вам также понадобятся ресурсы из ContactsCommon .

Удачи.

Вот моя попытка сделать это:

Шаг 1. Создайте стиль с именем SearchViewStyle

  

Шаг 2. Создайте макет с именем simple_search_view_item.xml

   

Шаг 3: Создайте пункт меню для этого вида поиска.

     

Шаг 4: Надуть меню

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

Результат:

введите описание изображения здесь

Единственное, что мне не удалось сделать, это заполнить всю ширину Toolbar . Если бы кто-то мог мне помочь, тогда это было бы золотым.

Чтобы добиться желаемого вида SearchView, вы можете использовать стили.

Во-первых, вам нужно создать style для вашего SearchView, который должен выглядеть примерно так:

  

Полный список атрибутов, которые вы можете найти в этой статье, в разделе «SearchView».

Во-вторых, вам нужно создать style для вашей Toolbar , который используется как ActionBar:

  

И, наконец, вам нужно обновить атрибут темы панели инструментов следующим образом:

  

Результат:

введите описание изображения здесь

ПРИМЕЧАНИЕ. Вам необходимо напрямую изменить атрибут темы Toolbar . Если вы просто обновите свой основной атрибут searchViewStyle это не повлияет на вашу Toolbar .

Другой способ добиться желаемого эффекта – использовать эту библиотеку просмотра материалов . Он автоматически обрабатывает историю поиска, а также дает возможность поиска предложений.

Пример: (Он показан на португальском языке, но он также работает на английском и итальянском языках).

Образец

Настроить

Прежде чем вы сможете использовать эту библиотеку, вы должны реализовать class с именем MsvAuthority внутри пакета br.com.mauker в вашем модуле приложения, и он должен иметь общедоступную статическую переменную String, называемую CONTENT_AUTHORITY . Дайте ему нужное значение и не забудьте добавить одно и то же имя в файл манифеста. Библиотека будет использовать этот файл для установки полномочий поставщика содержимого.

Пример:

MsvAuthority.java

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

AndroidManifest.xml

       

Применение

Чтобы использовать его, добавьте зависимость:

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

И затем, в вашем файле макета Activity , добавьте следующее:

  

После этого вам просто нужно получить ссылку MaterialSearchView с помощью getViewById() и открыть ее или закрыть ее с помощью MaterialSearchView#openSearch() и MaterialSearchView#closeSearch() .

PS: Можно открывать и закрывать представление не только с Toolbar . Вы можете использовать метод openSearch() основном из любой Button , такой как кнопка с плавающим действием.

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

Вы также можете закрыть представление с помощью кнопки «Назад», выполнив следующие действия:

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

Для получения дополнительной информации о том, как использовать lib, проверьте страницу github .

Ниже будет создан SearchView, идентичный поисковому файлу в Gmail, и добавьте его в данную панель инструментов. Вам просто нужно реализовать собственный метод 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; } 
  • Как скрыть навигационную панель постоянно в андроид-активности?
  • Как исправить метод getActionBar может вызвать java.lang.NullPointerException
  • Панель c # для рисования графики и прокрутки
  • Android: как заголовок центра в ToolBar
  • self.title устанавливает заголовок navigationController и tabBarItem? Зачем?
  • Как скрыть строку состояния iOS
  • Не удается уловить событие нажатия кнопки кнопки панели инструментов
  • В каком порядке панели наиболее эффективны с точки зрения времени и производительности?
  • Давайте будем гением компьютера.