您的位置:首页 > 其它

关键词搜索历史

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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: