众人登山围拢教师,见他异样神情皆不解。纷纷问道:“你看什么?浑沌干啥?”教师答:“下棋。”“深山旷野,与谁下棋?”教师沉默不语。良久,沉甸甸道出一字:“天!”
俗人浅见,喳喳追问:“赢了还是输了?”
教师细细数目。数至右下角,见到那个决定胜负的劫。浑沌长跪于地,充当一枚黑子,恰恰劫胜!教师崇敬浑沌精神,激情澎湃。他双手握拳冲天高举,喊得山野震荡,林木悚然——
“胜天半子!”
最近很喜欢“胜天半子”,故引用原文结尾作为本篇开头,也勉励自己。上周的安卓开发遇到在ActionBar上添加搜索栏的问题,然而现在Toolbar大行其道,导致这方面的资源比较少,所以我花了很大的力气慢慢调教。以下是自己的一点心得。
ActionBar是比较老的组件,不能支持SearchView,所以我选择了EditView作为我搜索栏的Search Bar。因为一些身不由己的原因只能使用ActionBar的同学们,一定是能感同身受我只能选择EditView的纠结的 :( 。作为一个完整的搜索栏,Search Bar里的清空按钮和整个搜索栏的推出按钮也是必不可少的。以下是我用纯JAVA代码写的整个搜索栏的样子:
整个搜索栏放在一个LinearLayout里
//ADD A SEARCH HEADER INSTEAD OF THE OLD HEADER, AFTER CLICKING SEARCH BUTTON
LinearLayout searchHeader = new LinearLayout(context);
searchHeader.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
searchHeader.setOrientation(LinearLayout.HORIZONTAL);
searchHeader.setBackgroundColor(Color.BLACK);
searchHeader.setVisibility(View.GONE);
在这之前我有个搜索图标设置了点击跳转搜索栏的功能,很简单我就不放出来了。这里是整个搜索栏的框架,之所以用LinearLayout是因为它可以自动横向排列,比RelativeLayout省去很多布置的代码。
然后就是EditView:
Search Bar
//ADD A SEARCH BAR IN SEARCH HEADER, WHICH SHOWS AFTER CLICKING SEARCH BUTTON
EditText search = new EditText(mainActivity);
search.setInputType(InputType.TYPE_CLASS_TEXT);
search.setSingleLine();
search.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
search.setHint("Search");
//ADD A SEARCH ICON INSIDE THE SEARCH BAR
Drawable searchIcon = context.getResources().getDrawable(R.drawable.places_ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(searchIcon, null, null, null);
LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 8);// Create lp for setting up margins
lp2.setMargins(50, 20, 0, 20);
search.setLayoutParams(lp2);
search.setPadding(5, 5, 5, 5);
search.setBackgroundColor(Color.WHITE);
search.setTextColor(Color.BLACK);
这里
search.setSingleLine();
与
search.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
是这个搜索栏能实现功能的关键。其他的都是一下外观上的东西。比如那个Drawable就是一个放大镜的图标,放到搜索栏的最左边。接下来是里面的Clear按钮,负责清楚文本和收回键盘:
Close Button
//ADD A CLOSE BUTTON IN SEARCH HEADER, WHICH SHOWS AFTER CLICKING SEARCH BUTTON
ImageButton closeButton = new ImageButton(mainActivity);
closeButton.setBackgroundColor(Color.WHITE);
closeButton.setColorFilter(Color.GRAY);
closeButton.setScaleType(ImageView.ScaleType.FIT_CENTER);
closeButton.setImageResource(R.drawable.delete_filled);
LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1);// Create lp for setting up margins
lp1.setMargins(0, 20, 0, 20);
closeButton.setLayoutParams(lp1);
closeButton.setVisibility(View.GONE);
这里R.drawable.delete_filled是我自定义的图标,大家可以使用ic_delete这种自带图标。最后是关掉整个搜索栏的Cancel按钮:
Cancel Button
//ADD A CANCEL BUTTON IN SEARCH HEADER, WHICH SHOWS AFTER CLICKING SEARCH BUTTON
Button cancelButton = new Button(mainActivity);
String cancelText = "Cancel";
SpannableString content = new SpannableString(cancelText);
content.setSpan(new UnderlineSpan(), 0, cancelText.length(), 0);
cancelButton.setText(content);
cancelButton.setTypeface(LVATabUtilities.latoRegular);
cancelButton.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 2));
cancelButton.setPadding(5, 5, 5, 5);
cancelButton.setTextColor(Color.parseColor(LVATabUtilities.getAppProperty("HighlightHEX")));
cancelButton.setBackgroundColor(Color.BLACK);`
为了做得跟IOS像一点,我在文本上加了下划线。
##最后是把他们都放到LinearLayout里面去
`searchHeader.addView(search);
searchHeader.addView(closeButton);
searchHeader.addView(cancelButton);
这里还有一点是,因为我用的LinearLayout,所以可以按权重分配各部分的大小,所以上述代码里SearchBar : CloseButton : CancelButton = 8 : 1 : 2。 他们的高度必须是Match_Parent, 宽度既不是Match_Parent也不是Wrap_Content, 而是0。这样做是为了固定他们的大小,而不会因为文本过长导致整个搜索栏变形。这样我们的搜索栏外观就完成了,然而万里长征也才走完了第一步。
接下来是实现这个搜索栏的功能。我们首先从简单的开始。
CloseButton的功能是清空文本和收回键盘
//ADD CLOSE BUTTON'S FUNCTIONALITY
closeButton.setVisibility(View.VISIBLE);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
search.setText("");
closeButton.setVisibility(View.GONE);
hideKeyboard();
}
});
CancelButton的功能是收回搜索栏和强制退出键盘
public static void clickOnCancelButton(final Button button, final ImageButton imageButton, final LinearLayout linearLayout){
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageButton.setVisibility(View.VISIBLE);
linearLayout.setVisibility(View.GONE);
removeFragmentFromCurrentViewPagerTab("SearchView");
hideSoftKeyboard(button);
}
});
}
上面的removeFragment方法是把我当年搜索所添加的Fragment再关掉,以此达到“关掉搜索界面” :)。怎么remove我就不贴代码了,因为是我们具体的app功能,只要做到这个思想就行了。
这个是自己写的强制退出键盘的方法,和上面CloseButton不同,用系统自带的hideKeyBoard()不能在Cancel时使用。
public static void hideSoftKeyboard(Button button) {
InputMethodManager imm = (InputMethodManager) mainActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(button.getWindowToken(), 0);
}
在某个位置调用方法实现功能
//ADD A CLICKLISTENER FOR CANCEL BUTTON, WHICH RETURNS BACK TO NORMAL SCREEM
clickOnCancelButton(cancelButton, searchButton, searchHeader);
最后就是数据的处理,这需要根据自己的情况量身定做。基本的思路就是找到自己这个Fragment的Adapter,在里面创建一个方法。然后把数据在里面处理了在调用到展示的Fragment页面中来。Adapter里的方法我就不放出来了,也没有参考价值。最后我们需要一个TextWacther监听EditText的所有动作,以下是它的代码:
在EditText中加入TextWatcher
//ADD A TEXTCHANGEDLISTENER FOR SEARCH BAR
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//NOTHING
}
@Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
//这里定义SearchView和SearchViewAdapter
//ADD CLOSE BUTTON'S FUNCTIONALITY
closeButton.setVisibility(View.VISIBLE);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
search.setText("");
closeButton.setVisibility(View.GONE);
hideKeyboard();
}
});
//ADD SEARCH'S FUNCTIONALITY
search.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
//这行用定义好的SearchView和SearchViewAdapter写处理数据的代码
detachAndAttachCurrentFragment();
hideKeyboard();
return true;
}
return false;
}
});
//REPLACE CURRENT FRAGMENT
removeFragmentFromCurrentViewPagerTab();
}
@Override
public void afterTextChanged(Editable s) {
//NOTHING
}
};
search.addTextChangedListener(textWatcher);
这样大体上我们就大功告成啦。这里detachAndAttachCurrentFragment()和removeFragmentFromCurrentViewPagerTab()是我自定义的方法。一个是用来刷新页面,一个是移除现在的页面(因为我们要添加搜索得到的页面)。