[英]SearchView in ActionBar — problems with the *Up* button
I am using the the SearchView
in the ActionBar
of the ListView
. 我在
ListView
的ActionBar
中使用SearchView
。 The magnifying glass can be touched, the SearchView
shows its edit box, and the user can enter the text for filtering the content of the list. 可以触摸放大镜,
SearchView
显示其编辑框,用户可以输入文本以过滤列表内容。 It almost works. 它几乎可以工作。 However, when the user presses the Up button, the
SearchView
collapses back to the icon, the text inside the widget is cleared, and the filtering is reset. 但是,当用户按下向上按钮时,
SearchView
折叠回图标,清除窗口小部件内的文本,并重置过滤。 The effect (in my case) is that the list can be filtered only when the SearchView
is not iconified. 效果(在我的情况下)是只有在
SearchView
没有图标化时才能过滤列表。 The wanted behaviour is to keep the filter text also after the SearchView
was collapsed. 想要的行为是在
SearchView
折叠后保留过滤器文本。
Attention: The behaviour probably changed in Android 4.3. 注意: Android 4.3中的行为可能已更改。 With 4.2.2 it worked as wanted.
4.2.2它按预期工作。 See the observations below.
见下面的观察。
Details: To be more specific, the menu contains the following item: 详细信息:更具体地说,该菜单包含以下项目:
<item android:id="@+id/menu_search_customers"
android:title="@string/menu_search_text"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
Notice the icon and the android:showAsAction
. 注意图标和
android:showAsAction
。 I belive the Up button appears by default when the SearchView
is expanded (by Up I mean the <
plus the icon -- see the right image with the blue book from the official Navigation with Back and Up ). 我相信,当
SearchView
被展开时,默认情况下会出现向上按钮(按向上我的意思是<
加上图标 - 使用官方导航中的蓝图和后退和向上看到右图)。 It seems that the default handler implementation just collapses the expanded SearchView
(returns back to the icon state). 似乎默认处理程序实现只是折叠扩展的
SearchView
(返回图标状态)。
When debugging, I have found that the onQueryTextChange()
is fired with the empty text when the Up is used. 在调试时,我发现当使用Up时,使用空文本触发
onQueryTextChange()
。 (I believe this was not the case with Android 4.2.2, because it worked as wanted before the OS update.) This is the reason why the filtering of the list items is also reset -- see my onQueryTextChange()
below. (我相信这不是Android 4.2.2的情况,因为它在操作系统更新之前按原样运行。)这就是为什么列表项的过滤也被重置的原因 - 请参阅下面的
onQueryTextChange()
。 I want the SearchView
collapsed, and the filter text displayed as subtitle in the action bar. 我希望
SearchView
折叠,过滤器文本显示为操作栏中的副标题。
So far, my code related to the SearchView
looks like this: 到目前为止,我与
SearchView
相关的代码如下所示:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// MenuInflater adds the magnifying glass icon for the SearchView
// to the ActionBar as the always visible menu item.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.customers_menu, menu);
// Get the related SearchView widget.
SearchView sv = (SearchView) menu.findItem(R.id.menu_search_customers)
.getActionView();
// Get the changes immediately.
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
// I am not sure whether the onQueryTextSubmit() is important
// for the purpose.
@Override
public boolean onQueryTextSubmit(String query) {
getActionBar().setSubtitle(mCurFilter);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
// The newText is stored into a member variable that
// is used when the new CursorLoader is created.
mCurFilter = newText;
getActionBar().setSubtitle(mCurFilter);
getLoaderManager().restartLoader(0, null,
CustomersOverviewActivity.this);
return true;
}
});
return true;
}
The restarted loader calls the onCreateLoader
. 重新启动的加载程序调用
onCreateLoader
。 Notice the mCurFilter
is used for building the SQL query: 请注意,
mCurFilter
用于构建SQL查询:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { CustomerTable._ID,
CustomerTable.CODE,
CustomerTable.NAME,
CustomerTable.STREET,
CustomerTable.TOWN };
String selection = null; // init
String[] selectionArgs = null; // init
if ( ! mCurFilter.isEmpty()) {
selection = CustomerTable.NAME + " like ?";
selectionArgs = new String[]{ "%" + mCurFilter +"%" };
}
CursorLoader cursorLoader = new CursorLoader(this,
DemoContentProvider.CUSTOMERS_CONTENT_URI, projection,
selection, selectionArgs,
orderInfo);
return cursorLoader;
}
I would like to detect the situation when the Up is pressed before the onQueryTextChange()
is called. 我想检测在调用
onQueryTextChange()
之前按下Up的情况。 This way (say) I could set a flag and block the mCurFilter
assignment by the emptied SearchView
content. 这样(比方说)我可以设置一个标志并通过清空的
SearchView
内容阻止mCurFilter
分配。 Also, when the search icon is expanded again, I would like to initialize the text in the expanded SearchView
from the mCurFilter
before it is shown (ie the expanded view is preset with the filter text). 此外,当再次展开搜索图标时,我想在
mCurFilter
之前从mCurFilter
初始化扩展的SearchView
的文本(即展开的视图是使用过滤器文本预设的)。 How that can be done? 怎么做?
Update: The earlier implementation of the SearchView
had... 更新:
SearchView
的早期实现有......
@Override
public void onActionViewCollapsed() {
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
Now, it contains... 现在,它包含......
@Override
public void onActionViewCollapsed() {
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
Do you know what could be the reason for setting the query to the empty string? 你知道将查询设置为空字符串的原因是什么? Should I override the new implementation by the old code?
我应该用旧代码覆盖新的实现吗? Or is there a better way?
或者,还有更好的方法?
I have written a StatefulSearchView
which retains the text: 我写了一个
StatefulSearchView
,它保留了文本:
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.SearchView;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;
public class StatefulSearchView extends SearchView implements android.view.View.OnLayoutChangeListener, OnQueryTextListener,android.widget.SearchView.OnCloseListener{
private boolean mSaveText=true;
private OnQueryTextListener mQueryListener;
private String mQuery;
private OnCloseListener mCloseListener;
private boolean fromIconify = true;
public StatefulSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
addOnLayoutChangeListener(this);
super.setOnCloseListener(this);
}
public StatefulSearchView(Context context) {
super(context);
// TODO Auto-generated constructor stub
addOnLayoutChangeListener(this);
super.setOnCloseListener(this);
}
public void setSaveSearchTextState(boolean save){
this.mSaveText = save;
this.setSaveEnabled(mSaveText);
}
public void setOnStatefulQueryTextListener(OnQueryTextListener listener) {
mQueryListener = listener;
super.setOnQueryTextListener(this);
}
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if(super.isIconfiedByDefault() || !super.isIconified() && !TextUtils.isEmpty(mQuery) && mSaveText){
setSavedText(mQuery);
}
Log.i("onLayoutChanged()",""+mQuery);
}
@Override
public void setIconified(boolean iconify) {
mQuery = getQuery().toString();
Log.i("setIconified()",""+mQuery);
super.setOnCloseListener(null);
super.setIconified(iconify);
super.setIconified(iconify);
super.setOnCloseListener(this);
fromIconify = true;
}
@Override
public void setOnCloseListener(OnCloseListener listener) {
mCloseListener = listener;
super.setOnCloseListener(this);
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable state = super.onSaveInstanceState();
return new SearchQueryState(state, mQuery, mSaveText);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SearchQueryState sqs = (SearchQueryState)state;
super.onRestoreInstanceState(sqs.getSuperState());
mQuery = sqs.getSavedQuery();
mSaveText = sqs.getSaveText();
}
@Override
public boolean onQueryTextChange(String arg0) {
mQuery = arg0;
return mQueryListener.onQueryTextChange(mQuery);
}
@Override
public boolean onQueryTextSubmit(String arg0) {
// TODO Auto-generated method stub
return mQueryListener.onQueryTextSubmit(arg0);
}
private TextView getTextView(){
int searchTextViewId = getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
return (TextView) this.findViewById(searchTextViewId);
}
private void setSavedText(String s){
super.setOnQueryTextListener(null);
Log.i("setSavedText()",""+s);
TextView t = getTextView();
t.setText(s);
if(!TextUtils.isEmpty(s))
((EditText)t).setSelection(s.length());
super.setOnQueryTextListener(mQueryListener);
}
private class SearchQueryState extends BaseSavedState{
private boolean mSaveText;
private String mQueryText;
public SearchQueryState(Parcel arg0) {
super(arg0);
this.mQueryText = arg0.readString();
this.mSaveText = arg0.readInt() == 1;
}
public SearchQueryState(Parcelable superState, String queryText, boolean saveText) {
super(superState);
this.mQueryText = queryText;
this.mSaveText = saveText;
}
public boolean getSaveText(){
return this.mSaveText;
}
public String getSavedQuery(){
return mQueryText;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
super.writeToParcel(dest, flags);
dest.writeString(mQueryText);
dest.writeInt(mSaveText? 1: 0);
}
}
@Override
public boolean onClose() {
Log.i("onClose()", "Is from setIconified(): "+fromIconify);
if(!fromIconify){
mQuery = null;
fromIconify = false;
}
return mCloseListener == null ? false : mCloseListener.onClose();
}
}
In demonstration activity: 在示范活动中:
public class MainActivity extends Activity{
private StatefulSearchView mSearchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getActionBar().setHomeButtonEnabled(true);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if(item.getItemId()==android.R.id.home) {
mSearchView.setIconified(true);
return true;
}
return super.onMenuItemSelected(featureId, item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
MenuItem item = menu.findItem(R.id.action_search);
mSearchView =(StatefulSearchView)item.getActionView();
mSearchView.setSaveSearchTextState(true);
mSearchView.setOnStatefulQueryTextListener(new OnQueryTextListener(){
@Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}});
return true;
}
In menu xml: 在菜单xml中:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_search"
android:orderInCategory="100"
android:showAsAction="always"
android:actionViewClass="com.nikola.despotoski.saveablesearchview.StatefulSearchView"
android:title="@string/action_settings"/>
</menu>
In the source of the SearchView
, it clearly says that they change the text to ""
: 在
SearchView
的源代码中,它清楚地表明他们将文本更改为""
:
@Override
public void onActionViewCollapsed() {
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
/**
* {@inheritDoc}
*/
@Override
public void onActionViewExpanded() {
if (mExpandedInActionView) return;
mExpandedInActionView = true;
mCollapsedImeOptions = mQueryTextView.getImeOptions();
mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
mQueryTextView.setText("");
setIconified(false);
}
Let me know if you have issues. 如果您有问题,请告诉我。
I'm not sure I understand your problem but you can just detect when up is clicked like this: 我不确定我是否理解你的问题,但你可以检测到点击的时间是这样的:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
doSOmething();
return true;
}
return super.onOptionsItemSelected(item);
}
If you intercept the up click, you can presumably do anything you want here. 如果您拦截向上点击,您可以在这里做任何你想要的事情。 Returning true will consume the event and that should prevent any default action from taking place.
返回true将消耗该事件,并且应该阻止任何默认操作发生。 This way you can do whatever you want the up button to do while at the same time consuming the up event to prevent clearing of your filters.
通过这种方式,您可以执行任何您想要的向上按钮,同时消耗向上事件以防止清除过滤器。
I struggle with this a little until I found the solution. 在我找到解决方案之前,我有点挣扎。
Declare your menuItem like this, check the showAsAction attribute, type only ifRoom, if you set collapseActionView the widget will collapse and show the back button on the actionbar 像这样声明你的menuItem,检查showAsAction属性,只键入ifRoom,如果设置collapseActionView,小部件将折叠并显示操作栏上的后退按钮
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/search"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/ic_2_action_search"
android:showAsAction="ifRoom"
android:title="@null"/>
</menu>
Set up your SearchView as usual, remember to Add setIconifiedByDefault this will make the icon to start up as an icon 像往常一样设置SearchView,记得添加setIconifiedByDefault这将使图标以图标的形式启动
SearchManager searchManager = (SearchManager)getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setIconifiedByDefault(true);
searchView.setOnQueryTextListener(new SearchViewOnQueryListener());
searchView.setOnCloseListener(new SearchViewOnCloseListener());
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
On your QueryListener is where you handle the end of your search like so, here is where you use onActionViewCollapse() which collapse back the ViewSearch 在您的QueryListener上,您可以像这样处理搜索结束,这里是使用onActionViewCollapse()的地方,它会折叠ViewSearch
@Override
public boolean onQueryTextSubmit(String query) {
makeSearchRequest(SEARCH_TYPE_KEYWORD, query);
searchView.setQuery("", false);
searchView.clearFocus();
searchView.onActionViewCollapsed();
buttonClearSearchResults.setVisibility(View.VISIBLE);
return false;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.