关键词搜索历史
2017-12-26 10:56
309 查看
需求
商品搜索,资讯搜索等都需要搜索历史主要就是一个流式布局 加本地存储
以及一些操作上的优化
这里来一篇自己手写的全过程
效果
分析
1.需要一个流式布局这里使用的是鸿洋大神写过的开源库
不怕麻烦的大家也可以自己去写一个
技术点就是计算换行
这里给出依赖
compile ‘com.hyman:flowlayout-lib:1.1.2
2.本地数据保存
这是我用的是最简单的sp保存
但在写代码过程中还是发现了很多的问题
首先,排版方式,搜索历史保存肯定是要 最近使用最靠前然后得去重 还得防注入 看了下淘宝的
如果搜索关键词加空格就会被分成两个关键词
显然不是用户第一手的搜索历史
这里给出 sp 的工具类
和保存关键词的 工具类
sputil
/** * <pre> * author: Blankj * blog : http://blankj.com * time : 2016/8/2 * desc : SP读写工具类 * </pre> */ public class SPUtils { private SPUtils() { throw new UnsupportedOperationException("u can't fuck me..."); } /** * SP的name值 * <p>可通过修改PREFERENCE_NAME变量修改SP的name值</p> */ public static String PREFERENCE_NAME = "ANDROID_UTIL_CODE"; /** * SP中写入String类型value * * @param context 上下文 * @param key 键 * @param value 值 * @return true: 写入成功<br>false: 写入失败 */ public static boolean putString(Context context, String key, String value) { return getSP(context).edit().putString(key, value).commit(); } /** * SP中读取String * * @param context 上下文 * @param key 键 * @return 存在返回对应值,不存在返回默认值null */ public static String getString(Context context, String key) { return getString(context, key, null); } /** * SP中读取String * * @param context 上下文 * @param key 键 * @param defaultValue 默认值 * @return 存在返回对应值,不存在返回默认值defaultValue */ public static String getString(Context context, String key, String defaultValue) { return getSP(context).getString(key, defaultValue); } /** * SP中写入int类型value * * @param context 上下文 * @param key 键 * @param value 值 * @return true: 写入成功<br>false: 写入失败 */ public static boolean putInt(Context context, String key, int value) { return getSP(context).edit().putInt(key, value).commit(); } /** * SP中读取int * * @param context 上下文 * @param key 键 * @return 存在返回对应值,不存在返回默认值-1 */ public static int getInt(Context context, String key) { return getInt(context, key, -1); } /** * SP中读取int * * @param context 上下文 * @param key 键 * @param defaultValue 默认值 * @return 存在返回对应值,不存在返回默认值defaultValue */ public static int getInt(Context context, String key, int defaultValue) { return getSP(context).getInt(key, defaultValue); } /** * SP中写入long类型value * * @param context 上下文 * @param key 键 * @param value 值 * @return true: 写入成功<br>false: 写入失败 */ public static boolean putLong(Context context, String key, long value) { return getSP(context).edit().putLong(key, value).commit(); } /** * SP中读取long * * @param context 上下文 * @param key 键 * @return 存在返回对应值,不存在返回默认值-1 */ public static long getLong(Context context, String key) { return getLong(context, key, -1); } /** * SP中读取long * * @param context 上下文 * @param key 键 * @param defaultValue 默认值 * @return 存在返回对应值,不存在返回默认值defaultValue */ public static long getLong(Context context, String key, long defaultValue) { return getSP(context).getLong(key, defaultValue); } /** * SP中写入float类型value * * @param context 上下文 * @param key 键 * @param value 值 * @return true: 写入成功<br>false: 写入失败 */ public static boolean putFloat(Context context, String key, float value) { return getSP(context).edit().putFloat(key, value).commit(); } /** * SP中读取float * * @param context 上下文 * @param key 键 * @return 存在返回对应值,不存在返回默认值-1 */ public static float getFloat(Context context, String key) { return getFloat(context, key, -1); } /** * SP中读取float * * @param context 上下文 * @param key 键 * @param defaultValue 默认值 * @return 存在返回对应值,不存在返回默认值defaultValue */ public static float getFloat(Context context, String key, float defaultValue) { return getSP(context).getFloat(key, defaultValue); } /** * SP中写入boolean类型value * * @param context 上下文 * @param key 键 * @param value 值 * @return true: 写入成功<br>false: 写入失败 */ public static boolean putBoolean(Context context, String key, boolean value) { return getSP(context).edit().putBoolean(key, value).commit(); } /** * SP中读取boolean * * @param context 上下文 * @param key 键 * @return 存在返回对应值,不存在返回默认值false */ public static boolean getBoolean(Context context, String key) { return getBoolean(context, key, false); } /** * SP中读取boolean * * @param context 上下文 * @param key 键 * @param defaultValue 默认值 * @return 存在返回对应值,不存在返回默认值defaultValue */ public static boolean getBoolean(Context context, String key, boolean defaultValue) { return getSP(context).getBoolean(key, defaultValue); } /** * 获取name为PREFERENCE_NAME的SP对象 * * @param context 上下文 * @return SP */ private static SharedPreferences getSP(Context context) { return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); } }
HistoryKeyWordSaveUtil.java
/** * Created by ccb on 2017/11/4. * 搜索历史关键词保存工具类 */ public class HistoryKeyWordSaveUtil { /** * 搜索历史 关键词 sp保存key */ private static final String SEARCH_HISTORY_KEY = "search_history_key"; /** * 分隔符 防注入 */ public static final String SPLITE_SIGNAL = "!@#$"; public static final String SPLITE_SIGNAL_FORMAT = "\\!\\@\\#\\$"; /** * 关键词 总字数 数量上限 45 三行 */ private static final int KEY_LENGTH = 45; /*** * 插入搜索历史关键词 * @param context * @param searchKey */ public static void insert(Context context, String searchKey) { LinkedList<String> list = query(context); list.add(0, searchKey); for (int i = 1; i < list.size(); i++) { //去重 if (list.get(i).equals(list.get(0))) { list.remove(i); break; } } //计算总长度 过长 去尾部数据 int length = 0; for (int i = 0; i < list.size(); i++) { length += list.get(i).length(); } while (length > KEY_LENGTH) { list.remove(list.size() - 1); length = 0; for (int i = 0; i < list.size(); i++) { length += list.get(i).length(); } } //存储数据到sp String str = ""; for (int i = 0; i < list.size(); i++) { if (i != list.size() - 1) { str += list.get(i) + SPLITE_SIGNAL; } else { str += list.get(i); } } SPUtils.putString(context, SEARCH_HISTORY_KEY, str); } /*** * 查询 搜索历史关键词 * @return */ public static LinkedList<String> query(Context context) { LinkedList<String> list = new LinkedList<>(); String keys = SPUtils.getString(context, SEARCH_HISTORY_KEY, ""); if (!TextUtils.isEmpty(keys)) { String[] keyStrs = keys.split(SPLITE_SIGNAL_FORMAT); for (int i = 0; i < keyStrs.length; i++) { list.add(i, keyStrs[i]); } } return list; } }
这里采用链表进行保存,去重通过遍历
xml布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:zhy="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" android:paddingTop="24dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#3F51B5" android:minHeight="?attr/actionBarSize" android:theme="@style/ToolBarStyle" app:contentInsetEnd="0dp" app:contentInsetLeft="0dp" app:contentInsetRight="0dp" app:contentInsetStart="0dp" app:paddingEnd="0dp" app:paddingStart="0dp" app:titleMarginStart="0dp" app:titleTextColor="@android:color/black"> <LinearLayout android:id="@+id/ll_search" android:layout_width="match_parent" android:layout_height="30dp" android:layout_marginRight="15dp" android:background="#fff" android:gravity="center_vertical" android:orientation="horizontal" android:paddingRight="10dp"> <ImageView android:paddingLeft="10dp" android:paddingRight="5dp" android:paddingTop="5dp" android:paddingBottom="5dp" android:id="@+id/iv_search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_search"/> <EditText android:id="@+id/et_search" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_weight="1" android:singleLine="true" android:imeOptions="actionSearch" android:background="@android:color/transparent" android:hint="搜索你喜欢的商品" android:textColorHint="#b2b7bf" android:textSize="12sp"/> <ImageView android:id="@+id/iv_search_del" android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/login_delete_font_icon" android:visibility="invisible"/> </LinearLayout> <TextView android:id="@+id/toolbar_title" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" android:singleLine="true" android:text="123" android:textColor="#222222" android:textSize="20sp"/> </android.support.v7.widget.Toolbar> <View style="@style/style_line_gray_h"/> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/ll_history_hot" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_history" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="14dp" android:textSize="18sp" android:layout_marginTop="14dp" android:paddingLeft="14dp" android:text="搜索历史" android:textColor="#5f92fc"/> <com.zhy.view.flowlayout.TagFlowLayout android:id="@+id/flow_layout_history" zhy:max_select="1" android:paddingLeft="10dp" android:layout_width="fill_parent" android:layout_height="wrap_content"> </com.zhy.view.flowlayout.TagFlowLayout> </LinearLayout> </FrameLayout> </LinearLayout>
主程序代码
package com.example.searchhistory; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.zhy.view.flowlayout.FlowLayout; import com.zhy.view.flowlayout.TagAdapter; import com.zhy.view.flowlayout.TagFlowLayout; import java.util.LinkedList; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity { @BindView(R.id.iv_search) ImageView mIvSearch; @BindView(R.id.et_search) EditText mEtSearch; @BindView(R.id.iv_search_del) ImageView mIvSearchDel; @BindView(R.id.ll_search) LinearLayout mLlSearch; @BindView(R.id.toolbar_title) TextView mToolbarTitle; @BindView(R.id.toolbar) Toolbar mToolbar; @BindView(R.id.tv_history) TextView mTvHistory; @BindView(R.id.flow_layout_history) TagFlowLayout mFlowLayoutHistory; @BindView(R.id.ll_history_hot) LinearLayout mLlHistoryHot; private MainActivity context; private MainActivity activity; private String mSearchKey; private LinkedList<String> mHistroyList; private TagAdapter<String> mHistroyAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); context = this; activity = this; initSearchView(); initHistoryFlowLayout(); } /** * 初始化搜索条 */ private void initSearchView() { SoftInputUtil.showSoftInputFromWindow(activity, mEtSearch); mEtSearch.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { if (!TextUtils.isEmpty(editable.toString().trim())) { mIvSearchDel.setVisibility(View.VISIBLE); } else { mIvSearchDel.setVisibility(View.INVISIBLE); } } }); mEtSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { if (actionId == EditorInfo.IME_ACTION_SEARCH) { String key = mEtSearch.getText().toString().trim(); if (!TextUtils.isEmpty(key)) { HistoryKeyWordSaveUtil.insert(context, key); mSearchKey = key; requestSearch(key); /*隐藏软键盘*/ InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager.isActive()) { inputMethodManager.hideSoftInputFromWindow(mEtSearch.getApplicationWindowToken(), 0); } return true; } else { Toast.makeText(context, "搜索内容不能为空", Toast.LENGTH_SHORT).show(); } return false; } return false; } }); } /** * 搜索历史 流式布局 */ private void initHistoryFlowLayout() { //初始化历史搜索流式布局 mHistroyList = HistoryKeyWordSaveUtil.query(context); if (mHistroyList.size() == 0) { mFlowLayoutHistory.setVisibility(View.GONE); mTvHistory.setVisibility(View.GONE); } mHistroyAdapter = new TagAdapter<String>(mHistroyList) { @Override public View getView(FlowLayout parent, int position, String key) { View view = View.inflate(context, R.layout.item_tag_flow_layout, null); TextView mTv = view.findViewById(R.id.tv_tag); mTv.setText(key); return view; } }; mFlowLayoutHistory.setAdapter(mHistroyAdapter); mFlowLayoutHistory.setOnTagClickListener(new TagFlowLayout.OnTagClickListener() { @Override public boolean onTagClick(View view, int position, FlowLayout parent) { setSearchContent(mHistroyList.get(position)); /*隐藏软键盘*/ InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager.isActive()) { inputMethodManager.hideSoftInputFromWindow(mEtSearch.getApplicationWindowToken(), 0); } return true; } }); } /** * 设置搜索内容 并移动光标到指定位置 */ private void setSearchContent(String searchStr) { mEtSearch.setText(searchStr); mEtSearch.setSelection(searchStr.length()); HistoryKeyWordSaveUtil.insert(context, searchStr);//添加 搜索关键词 到本地 mSearchKey = searchStr; requestSearch(searchStr); } /** * 搜索商品 * * @param searchStr */ private void requestSearch(String searchStr) { mFlowLayoutHistory.setVisibility(View.INVISIBLE); mTvHistory.setVisibility(View.INVISIBLE); } @Override public void onBackPressed() { if (mTvHistory.getVisibility() == View.INVISIBLE) { mTvHistory.setVisibility(View.VISIBLE); mFlowLayoutHistory.setVisibility(View.VISIBLE); initHistoryFlowLayout(); } else { finish(); } } @OnClick(R.id.iv_search_del) public void onViewClicked() { mEtSearch.setText(""); SoftInputUtil.showSoftInputFromWindow(activity, mEtSearch); mTvHistory.setVisibility(View.VISIBLE); mFlowLayoutHistory.setVisibility(View.VISIBLE); initHistoryFlowLayout(); } }
软键盘显示工具类
public class SoftInputUtil { /** * EditText获取焦点并显示软键盘 */ public static void showSoftInputFromWindow(Activity activity, EditText editText) { InputMethodManager inputManager = (InputMethodManager) editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); editText.setFocusable(true); editText.setFocusableInTouchMode(true); editText.requestFocus(); activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); inputManager.showSoftInput(editText, 0); } }
相关文章推荐
- 历史记录+模糊搜索+高亮关键词
- 谷歌趋势图显示“QR码”关键词搜索量创历史新高
- doccms的全站关键词搜索标签使用和doc_order的内容调用(php)
- 搜索历史堆砌效果的实现
- 百度搜索关键词工具升级:百度流量一目了然
- threshold for buffer fratricide搜索的关键词而有的结果
- Android实现关键词批量搜索EditText
- ECSHOP热门搜索关键词随机显示
- 从“关键词搜索”到“全息路径搜索”
- 2004 Year-End Google Zeitgeist(Google年度热门搜索关键词)
- Android流式布局实现历史搜索记录功能
- 发现Google也出了关键词“相关搜索”
- 简单好用、含历史搜索记录的搜索框
- 搜索关键词统计
- 搜索关键词高亮显示
- 昨日重现,Google推出"我的搜索历史" 【ZZ】出处:PConline
- asp 多关键词搜索的简单实现方法
- QQ群屏蔽SEO关键词:QQ群搜索开始地域化
- asp实现关键词不区分大小写搜索并高亮显示
- 使用EditText和SharedPreferences实现搜索历史记录提示功能