前言
搜索界面一直是一个APP至关重要的部分,也是用户用的最多的界面,那么历史搜索和热门标签的话,也是这个界面所需要的重要的组成部分。
本篇文章旨在帮助大家如何写好两个重要的部分。话不多说,先上图
界面
用到的控件和框架
1.Android ORM框架 GreenDao3.0
2.SearchView在ToolBar中的使用
3.FlowLayoutTag 标签控件(也是本人写的控件,具体在引用如下)
compile’com.daidingkang:flowlayouttag:1.0.0’
FlowLayoutTag主要代码
FlowLayout.class
/*** 自定义流式布局*/
public class FlowLayout extends ViewGroup {private LayoutInflater mInflater;private boolean isColorful;public FlowLayout(Context context) {this(context, null);}public FlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);mInflater = LayoutInflater.from(getContext());}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);// wrapContentint width = 0;int height = 0;// 记录每一行的宽和高int lineWidth = 0;int lineHeight = 0;// 得到内部元素的个数int count = getChildCount();for (int i = 0; i < count; i++) {View child = getChildAt(i);// 测量子View的宽和高measureChild(child, widthMeasureSpec, heightMeasureSpec);// 得到LayoutParamsMarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();// 子view的占据的宽度int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;// 子view占据的高度int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;// 换行if (lineWidth + childWidth > sizeWidth - getPaddingLeft()- getPaddingRight()) {// 对比得到最大的宽度width = Math.max(width, lineWidth);// 重置lineWidthlineWidth = childWidth;// 记录行高height += lineHeight;lineHeight = childHeight;} else {// 未换行// 叠加行宽lineWidth += childWidth;// 得到当前最大高度lineHeight = Math.max(lineHeight, childHeight);}// 最后一个控件if (i == count - 1) {width = Math.max(lineWidth, width);height += lineHeight;}}
// Log.i("test", "sizeWidth" + sizeWidth);
// Log.i("test", "sizeHeight" + sizeHeight);setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth: width + getPaddingLeft() + getPaddingRight(),modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height+ getPaddingTop() + getPaddingBottom());setPadding(dp2px(20), dp2px(10), dp2px(20), dp2px(10));}// 储存所有的Viewprivate ArrayList<ArrayList<View>> mAllViews = new ArrayList<>();// 储存每一行的高度private ArrayList<Integer> mLineHeight = new ArrayList<>();@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stub// 清除一下list集合mAllViews.clear();mLineHeight.clear();// 得到viewGroup当前宽度int width = getWidth();int lineWidth = 0;int lineHeight = 0;ArrayList<View> lineViews = new ArrayList<>();int count = getChildCount();for (int i = 0; i < count; i++) {View child = getChildAt(i);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();// 如果需要换行if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width- getPaddingLeft() - getPaddingRight()) {// 记录当前行高mLineHeight.add(lineHeight);// 记录当前行的viewmAllViews.add(lineViews);// 重置行宽和行高lineWidth = 0;lineHeight = childHeight + lp.topMargin + lp.bottomMargin;// 重置lineViews集合lineViews = new ArrayList<>();}lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin+ lp.bottomMargin);lineViews.add(child);}// 处理最后一行mLineHeight.add(lineHeight);mAllViews.add(lineViews);// 设置子view的位置int left = getPaddingLeft();int top = getPaddingTop();// 有多少行int lineNum = mLineHeight.size();for (int i = 0; i < lineNum; i++) {// 获取当前行的viewlineViews = mAllViews.get(i);// 当前行高lineHeight = mLineHeight.get(i);int lineViewSize = lineViews.size();for (int j = 0; j < lineViewSize; j++) {View child = lineViews.get(j);// 判断子view的状态if (child.getVisibility() == View.GONE) {continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();int lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc = lc + childWidth;int bc = tc + childHeight;// 为子view布局child.layout(lc, tc, rc, bc);// 同一行view坐起点坐标的变换left += childWidth + lp.leftMargin + lp.rightMargin;}// 换行时将left重置left = getPaddingLeft();// top要加上上一行的行高top += lineHeight;}}/*** 默认返回的LayoutParams*/@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {// TODO Auto-generated method stubreturn new MarginLayoutParams(getContext(), attrs);}/*** 设置数据*/public void setData(String[] strings) {int count = strings.length;for (int i = 0; i < count; i++) {final TextView tv = (TextView) mInflater.inflate(R.layout.flowlayout_textview, this,false);tv.setText(strings[i]);tv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (onTagClickListener != null)onTagClickListener.TagClick(tv.getText().toString());}});if(isColorful){Random random = new Random();int ranColor = 0xff000000 | random.nextInt(0x00ffffff);tv.setBackgroundColor(ranColor);}this.addView(tv);}}/*** 设置数据*/public void setListData(List<String> list) {int count = list.size();for (int i = 0; i < count; i++) {final TextView tv = (TextView) mInflater.inflate(R.layout.flowlayout_textview, this,false);tv.setText(list.get(i));tv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (onTagClickListener != null)onTagClickListener.TagClick(tv.getText().toString());}});this.addView(tv);}}/*** 添加标签** @param text*/public void addTag(String text) {final TextView tv = (TextView) mInflater.inflate(R.layout.flowlayout_textview, this,false);tv.setText(text);tv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (onTagClickListener != null)onTagClickListener.TagClick(tv.getText().toString());}});if(isColorful){Random random = new Random();int ranColor = 0xff000000 | random.nextInt(0x00ffffff);tv.setBackgroundColor(ranColor);}this.addView(tv);}/*** 设置多彩颜色* @param isColorful*/public void setColorful(boolean isColorful) {this.isColorful = isColorful;}/*** 删除所有标签*/public void cleanTag() {this.removeAllViews();}public int dp2px(int dp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());}private OnTagClickListener onTagClickListener;public void setOnTagClickListener(OnTagClickListener onTagClickListener) {this.onTagClickListener = onTagClickListener;}public interface OnTagClickListener {void TagClick(String text);}
}
SearchActivity主要代码
SearchActivity.class
public class SearchActivity extends BaseActivity implements View.OnClickListener {@BindView(R.id.searchView)SearchView searchView;@BindView(R.id.toolbar)Toolbar toolbar;@BindView(R.id.hot_flowLayout)FlowLayout hotFlowLayout;@BindView(R.id.his_flowLayout)FlowLayout hisFlowLayout;@BindView(R.id.ll_history)LinearLayout lHistory;@BindView(R.id.delete)ImageView delete;SearchHistoryDao historyDao;@Overridepublic void initView() {setSupportActionBar(toolbar);getSupportActionBar().setDisplayHomeAsUpEnabled(true);initHotTag();historyDao = GreenDaoHelper.getDaoSession().getSearchHistoryDao();
//设置我们的SearchViewinitSearchView();delete.setOnClickListener(this);}private void initSearchView() {searchView.setIconifiedByDefault(true);//设置展开后图标的样式,这里只有两种,一种图标在搜索框外,一种在搜索框内searchView.onActionViewExpanded();// 写上此句后searchView初始是可以点击输入的状态,如果不写,那么就需要点击下放大镜,才能出现输入框,也就是设置为ToolBar的ActionView,默认展开
// searchView.requestFocus();//输入焦点searchView.setSubmitButtonEnabled(true);//添加提交按钮,监听在OnQueryTextListener的onQueryTextSubmit响应
// searchView.setFocusable(true);//将控件设置成可获取焦点状态,默认是无法获取焦点的,只有设置成true,才能获取控件的点击事件searchView.setIconified(false);//输入框内icon不显示
// searchView.requestFocusFromTouch();//模拟焦点点击事件searchView.setFocusable(false);searchView.clearFocus();
// mSearchView.setIconifiedByDefault(true);searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {@Overridepublic boolean onQueryTextSubmit(String query) {SnackbarUtil.show(toolbar, query);//插入之前先查询,如果有相同的就不在插入进去SearchHistory unique = historyDao.queryBuilder().where(SearchHistoryDao.Properties.SearchContent.eq(query)).unique();if (unique == null) {historyDao.insert(new SearchHistory(null, query));}return false;}@Overridepublic boolean onQueryTextChange(String newText) {return false;}});}/*** 历史搜索*/private void initHistoryTag() {List<SearchHistory> searchHistories = historyDao.loadAll();if (historyDao != null && searchHistories != null && searchHistories.size() != 0) {List<String> historyList = new ArrayList<>();for (SearchHistory searchHistory : searchHistories) {historyList.add(searchHistory.getSearchContent());}lHistory.setVisibility(View.VISIBLE);hisFlowLayout.setListData(historyList);hisFlowLayout.setOnTagClickListener(new FlowLayout.OnTagClickListener() {@Overridepublic void TagClick(String text) {MyApplication.toastor.showToast(text);}});}}/*** 热门搜索*/private void initHotTag() {String[] mStrings = {"apple", "百度CEO", "阿里巴巴", "绩效股", "中国股市", "美团", "google", "淘宝", "雷军 小米公司", "大疆无人机"};hotFlowLayout.setColorful(true);hotFlowLayout.setData(mStrings);hotFlowLayout.setOnTagClickListener(new FlowLayout.OnTagClickListener() {@Overridepublic void TagClick(String text) {MyApplication.toastor.showToast(text);}});}@Overrideprotected int getContentViewLayoutID() {return R.layout.activity_search;}@Overrideprotected void onResume() {super.onResume();initHistoryTag();}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.delete:AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage("确定要删除全部历史记录?");builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {lHistory.setVisibility(View.GONE);hisFlowLayout.cleanTag();historyDao.deleteAll();}});builder.setNegativeButton("取消", null);builder.create().show();break;}}
}
主要布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayout
android:visibility="gone"android:id="@+id/ll_history"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><RelativeLayout
android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:paddingLeft="10dp"android:paddingRight="10dp"><TextView
android:id="@+id/his_vertical_bar"android:layout_width="3dp"android:layout_height="20dp"android:background="?attr/colorPrimary"android:layout_marginRight="4dp"/><TextView
android:layout_toRightOf="@+id/his_vertical_bar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:gravity="left"android:text="历史搜索"android:textColor="@color/font"android:textSize="15sp"/><ImageView
android:id="@+id/delete"android:layout_width="wrap_content"android:layout_height="15dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:src="@mipmap/ic_delete"/></RelativeLayout><com.pulamsi.photomanager.widght.fitsystemwindowlayout.FlowLayout
android:id="@+id/his_flowLayout"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout><LinearLayout
android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><RelativeLayout
android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:paddingLeft="10dp"android:paddingRight="10dp"><TextView
android:id="@+id/hot_vertical_bar"android:layout_width="3dp"android:layout_height="20dp"android:background="?attr/colorPrimary"android:layout_marginRight="4dp"/><TextView
android:layout_toRightOf="@+id/hot_vertical_bar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:gravity="left"android:text="热门搜索"android:textColor="@color/font"android:textSize="15sp"/></RelativeLayout><com.pulamsi.photomanager.widght.fitsystemwindowlayout.FlowLayout
android:id="@+id/hot_flowLayout"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>
</LinearLayout>
如果有疑问和见解,也欢迎大家在下面留言,我会一一回复大家
以上