手记

Android历史搜索和热门标签

前言

搜索界面一直是一个APP至关重要的部分,也是用户用的最多的界面,那么历史搜索和热门标签的话,也是这个界面所需要的重要的组成部分。
本篇文章旨在帮助大家如何写好两个重要的部分。

用到的控件和框架

1.Android ORM框架 GreenDao3.0

2.SearchView在ToolBar中的使用

3.FlowLayoutTag 标签控件(也是本人写的控件,具体在引用如下)

compile 'com.daidingkang:FlowLayoutTag:1.0.0'

FlowLayoutTag主要代码

FlowLayout.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/**
 * 自定义流式布局
 */
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());
    }

    @Override
    protected 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);

        // wrapContent
        int 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);
            // 得到LayoutParams
            MarginLayoutParams 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);
                // 重置lineWidth
                lineWidth = 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));
    }

    // 储存所有的View
    private ArrayList<ArrayList<View>> mAllViews = new ArrayList<>();
    // 储存每一行的高度
    private ArrayList<Integer> mLineHeight = new ArrayList<>();

    @Override
    protected 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);
                // 记录当前行的view
                mAllViews.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++) {

            // 获取当前行的view
            lineViews = 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
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        // TODO Auto-generated method stub
        return 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() {
                @Override
                public 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() {
                @Override
                public 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() {
            @Override
            public 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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;


    @Override
    public void initView() {
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        initHotTag();
        historyDao = GreenDaoHelper.getDaoSession().getSearchHistoryDao();
//设置我们的SearchView
        initSearchView();


        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() {
            @Override
            public 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;
            }

            @Override
            public 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() {
                @Override
                public 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() {
            @Override
            public void TagClick(String text) {
                MyApplication.toastor.showToast(text);
            }
        });
    }

    @Override
    protected int getContentViewLayoutID() {
        return R.layout.activity_search;
    }

    @Override
    protected void onResume() {
        super.onResume();
        initHistoryTag();
    }

    @Override
    public 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() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        lHistory.setVisibility(View.GONE);
                        hisFlowLayout.cleanTag();
                        historyDao.deleteAll();
                    }
                });
                builder.setNegativeButton("取消", null);
                builder.create().show();
                break;
        }

    }
}

主要布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?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>

如果有疑问和见解,也欢迎大家在下面留言,我会一一回复大家

原文链接:http://www.apkbus.com/blog-875309-62941.html

0人推荐
随时随地看视频
慕课网APP