android: поиск в actionbar

Есть большая проблема: compatibility library не включает ActionBar. К счастью, есть хорошая библиотека, которая реализует экшнбары для младших версиий андроида, а для старших - проксирует вызовы к системным компонентам. Но и тут не всё гладко: сейчас нет полноценной реализации компонента SearchView(UI для строки поиска).

Есть несколько костылей способов как решить эту проблему. На просторах сети я нашёл библиотеку MenuItemSearchAction которая реализует функциональность SearchView для старых андроидов. По сути - эта "библиотека" - всего лищь несколько классов которые оборачивают создают MenuItem и оборачивают EditText, вешая на них обработчики событий. Я несколько переделал этот компонент: теперь он использует встроенный SearchView на современных платформах и создаёт свой, если в системе не нашлось.

Подготавливаемся

  • в манифесте указываем targetSdk=14
  • подключаем [ActionBarSheldok](http://ActionBarSheldok.com), как написано в инструкции
  • устанавливаем тему приложения, как рекомендуют в библиотеке

Создаём пункт меню

В /res/menu/main.xml, обращаем внимание на android:actionViewClass

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/menuSearch"
android:title="@string/search"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom|withText|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
. . . .
</menu>

Регистрируемся в Activity

Извлекаем и регистрируем меню в наследнике SheldokActivity

@Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
final MenuInflater menuInflater = getSupportMenuInflater();
menuInflater.inflate(vc.rux.englishpoems.free.R.menu.authors, menu);
MenuItemSearchAction.bind(this, menu, R.id.menuSearch, mSearchTextListener);
return true;
}

И создаём обработчик

private OnQueryTextListenerCompat mSearchTextListener = new OnQueryTextListenerCompat() {
@Override
public boolean onQueryTextChange(String s) {
mAuthorsAdapter.getFilter().filter(s);
return true;
}

@Override
public boolean onQueryTextSubmit(String s) {
return false;
}
};

MenuItemSearchAction

Класс имеет статический метод bind, который сначала пытается загрузить строку поиска с помощью компонент системы, а если не удаётся, то вешает на заданный пункт меню альтернативную строку поиска. Копирайты оставил оригинальные


package de.appetites.android.menuItemSearchAction;

/*
* Copyright (C) 2012 Benjamin Mock
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* <p>
* This class creates a MenuItem with an expandable and collapsable ActionView
* for search purposes
* </p>
*
* <p>
* It is based on the great ActionBar Sherlock of Jake Wharton. The problem with
* the original SearchView is, that the style for the dark ActionBar is wrong;
* i.e. black text on a dark gray background.
* </p>
*
* @author Benjamin Mock <mail@benjaminmock.de>
*/
public class MenuItemSearchAction extends EditText implements TextWatcher {

private MenuItem searchItem;
private OnQueryTextListenerCompat searchListener;

public MenuItemSearchAction(Context context, MenuItem menuItem,
OnQueryTextListenerCompat listener) {
super(context);
searchListener = listener;
searchItem = menuItem;

createMenuItem();
// show search button on keyboard; this needs the setting of
// TYPE_TEXT... to be shown
setImeOptions(EditorInfo.IME_ACTION_SEARCH);
setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
setMaxLines(1);

setTextColor(Color.WHITE);
setBackgroundColor(Color.BLACK);
}

private MenuItemSearchAction(Context context) {
super(context);
}

public static void bind(Context context, Menu menu, int menuItemId, OnQueryTextListenerCompat listener) {
final MenuItem itemSearch = menu.findItem(R.id.menuSearch);
final View searchView = (View) itemSearch.getActionView();
if (searchView != null) {
SearchViewCompat.setOnQueryTextListener(searchView, listener);
} else {
new MenuItemSearchAction(context, itemSearch, listener);
}
}

/**
* Listen for back button clicks, in order to close the keyboard and
* collapse the ActionView
*/
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_UP) {
searchItem.collapseActionView();
}
return super.dispatchKeyEvent(event);
}

/**
* Returns the the created MenuItem for customizations etc.
*
* @return the MenuItem, which holds search ActionView
*/
public MenuItem getMenuItem() {
return searchItem;
}

private void createMenuItem() {
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
setLayoutParams(layoutParams);

setHint(R.string.menuItemSearchHint);

searchItem.setActionView(this);
searchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS
| MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);

searchItem.setOnActionExpandListener(new OnActionExpandListener() {

@Override
public boolean onMenuItemActionExpand(MenuItem item) {
// open keyboard
MenuItemSearchAction.this.setText("");
MenuItemSearchAction.this.requestFocus();

MenuItemSearchAction.this.postDelayed(new Runnable() {
@Override
public void run() {
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

}
}, 200);
return true;
}

@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// close keyboard
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(
MenuItemSearchAction.this.getWindowToken(), 0);

return true;
}
});

setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH || event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
searchItem.collapseActionView();
}
return true;
}
});

addTextChangedListener(this);

}

@Override
public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3) {

}

@Override
public void beforeTextChanged(CharSequence s, int arg1, int arg2, int arg3) {

}

@Override
public void afterTextChanged(Editable arg0) {
searchListener.onQueryTextChange(getText().toString());
}
}

Файл можно забрать отдельно: MenuItemSearchAction.java

Результат

Android 2.3.3 - HTC

Android 4.0.3

UPD: само приложение

Можно посмотреть, потыкать и позитивно проголосовать на google play!