SharedPreferences实现本地搜索历史功能,覆盖搜索重复的文本,可清空

1. 判断搜索内容是否含表情,不需要可以不判断

    /*** 校验字符串是否含有表情* @param content* @return*/public static boolean hasEmoji(String content){Pattern pattern = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]");Matcher matcher = pattern.matcher(content);if(matcher .find()){return true;}return false;}

2.软键盘工具类弹出、关闭,不需要可以不判断

public class KeyBoardUtils {/*** 打开软键盘** @param editText* @param context*/public static void openKeybord(EditText editText, Context context) {InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);imm.showSoftInput(editText, InputMethodManager.RESULT_SHOWN);imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);}/*** 关闭软键盘* @param editText* @param context*/public static void closeKeybord(EditText editText, Context context) {InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);}/*** 判断软键盘是否显示* @param activity* @return*/public static boolean isSoftShowing(Activity activity) {//获取当前屏幕内容的高度int screenHeight = activity.getWindow().getDecorView().getHeight();//获取View可见区域的bottomRect rect = new Rect();//DecorView即为activity的顶级viewactivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);//考虑到虚拟导航栏的情况(虚拟导航栏情况下:screenHeight = rect.bottom + 虚拟导航栏高度)//选取screenHeight*2/3进行判断return screenHeight*2/3 > rect.bottom;}public static void hintKeyboard(Activity activity) {InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);if (imm.isActive() && activity.getCurrentFocus() != null) {if (activity.getCurrentFocus().getWindowToken() != null) {imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);}}}/*** 打开软键盘*/public static void openKeyboard(Handler mHandler, int s, final Activity activity) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);}}, s);}/*** 点击空白处关闭软键盘*/public static void inputClose(View view, Context context) {if (view instanceof EditText) {view.clearFocus();}try {InputMethodManager im = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);im.hideSoftInputFromWindow(view.getWindowToken(), 0);} catch (NullPointerException e) {e.printStackTrace();}}}

3.存储工具类


import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;/*** @author Administrator*         SharedPreferences使用工具类*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class SPUtils {private static SharedPreferences sp;private static SPUtils instance = new SPUtils();public static Context mContext;/*** 保存在手机里面的文件名*/public static final String FILE_NAME = "maigoo";private SPUtils() {}/*** xxx改为你想保存的sp文件名称*/public static SPUtils getInstance(Context context) {mContext = context;if (sp == null) {sp = context.getApplicationContext().getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);}return instance;}/*** 保存数据*/public void put(String key, Object value) {if (value instanceof Integer) {sp.edit().putInt(key, (Integer) value).apply();} else if (value instanceof String) {sp.edit().putString(key, (String) value).apply();} else if (value instanceof Boolean) {sp.edit().putBoolean(key, (Boolean) value).apply();} else if (value instanceof Float) {sp.edit().putFloat(key, (Float) value).apply();} else if (value instanceof Long) {sp.edit().putLong(key, (Long) value).apply();}}/*** 2. 读取数据*/public int getInt(String key, int defValue) {return sp.getInt(key, defValue);}public String getString(String key, String defValue) {return sp.getString(key, defValue);}public boolean getBoolean(String key, boolean defValue) {return sp.getBoolean(key, defValue);}/*** 读取数据** @param key* @param defValue* @return*/public <T> T get(String key, T defValue) {T t = null;if (defValue instanceof String || defValue == null) {String value = sp.getString(key, (String) defValue);t = (T) value;} else if (defValue instanceof Integer) {Integer value = sp.getInt(key, (Integer) defValue);t = (T) value;} else if (defValue instanceof Boolean) {Boolean value = sp.getBoolean(key, (Boolean) defValue);t = (T) value;} else if (defValue instanceof Float) {Float value = sp.getFloat(key, (Float) defValue);t = (T) value;}return t;}/*** 保存搜索记录** @param keyword*/public void save(String keyword) {// 获取搜索框信息SharedPreferences mysp = mContext.getSharedPreferences("search_history", 0);String old_text = mysp.getString("history", "");// 利用StringBuilder.append新增内容,逗号便于读取内容时用逗号拆分开StringBuilder builder = new StringBuilder(old_text);builder.append(keyword + ",");// 判断搜索内容是否已经存在于历史文件,已存在则不重复添加if (!old_text.contains(keyword + ",")) {SharedPreferences.Editor myeditor = mysp.edit();myeditor.putString("history", builder.toString());myeditor.commit();}}public String[] getHistoryList() {// 获取搜索记录文件内容SharedPreferences sp = mContext.getSharedPreferences("search_history", 0);String history = sp.getString("history", "");// 用逗号分割内容返回数组String[] history_arr = history.split(",");// 保留前50条数据if (history_arr.length > 50) {String[] newArrays = new String[50];System.arraycopy(history_arr, 0, newArrays, 0, 50);}return history_arr;}/*** 清除搜索记录*/public void cleanHistory() {SharedPreferences sp = mContext.getSharedPreferences("search_history", 0);SharedPreferences.Editor editor = sp.edit();editor.clear();editor.commit();}
}

4.Activity主要功能实现

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;import kemizhibo.rhkj.com.ijkpalaydemo.search.KeyBoardUtils;
import kemizhibo.rhkj.com.ijkpalaydemo.search.RegularUtils;
import kemizhibo.rhkj.com.ijkpalaydemo.search.SPUtils;public class Main2Activity extends AppCompatActivity {ZFlowLayout historyFl;EditText autoSearch;Button button_search;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);historyFl = findViewById(R.id.history_fl);autoSearch=findViewById(R.id.autoSearch);button_search=findViewById(R.id.button_search);initHistory();button_search.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (KeyBoardUtils.isSoftShowing(Main2Activity.this)) {KeyBoardUtils.hintKeyboard(Main2Activity.this);}String searchKey = autoSearch.getText().toString();if (!isNullorEmpty(searchKey)) {if (RegularUtils.hasEmoji(autoSearch.getText().toString())) {//含有非法字符串} else {//搜索String keyWord = autoSearch.getText().toString();if (!isNullorEmpty(keyWord)) {SPUtils.getInstance(Main2Activity.this).save(autoSearch.getText().toString());}initHistory();}} else {//搜索为空}}});}private boolean isNullorEmpty(String str) {return str == null || "".equals(str);}/*** 初始化  历史记录列表*/private void initHistory() {final String[] data = SPUtils.getInstance(Main2Activity.this).getHistoryList();ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.setMargins(10, 10, 10, 10);historyFl.removeAllViews();for (int i = 0; i < data.length; i++) {if (isNullorEmpty(data[i])) {return;}//有数据往下走final int j = i;//添加分类块View paramItemView = getLayoutInflater().inflate(R.layout.adapter_search_keyword, null);TextView keyWordTv = paramItemView.findViewById(R.id.tv_content);keyWordTv.setText(data[j]);historyFl.addView(paramItemView, layoutParams);keyWordTv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (KeyBoardUtils.isSoftShowing(Main2Activity.this)) {KeyBoardUtils.hintKeyboard(Main2Activity.this);}autoSearch.setText(data[j]);autoSearch.setSelection(data[j].length());//光标在最后if (!isNullorEmpty(data[j])) {SPUtils.getInstance(Main2Activity.this).save(autoSearch.getText().toString());}//点击事件}});// initautoSearch();}}
}

5.布局文件activity_main2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutandroid:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="kemizhibo.rhkj.com.ijkpalaydemo.Main2Activity"><Buttonandroid:id="@+id/button_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="搜索"/><EditTextandroid:layout_width="match_parent"android:layout_height="40dp"android:id="@+id/autoSearch"/><kemizhibo.rhkj.com.ijkpalaydemo.ZFlowLayoutandroid:id="@+id/history_fl"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/title"android:orientation="vertical" /></LinearLayout>

adapter_search_keyword.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/tv_content"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginTop="12dp"android:background="#00f"android:paddingBottom="8dp"android:paddingLeft="12dp"android:paddingRight="12dp"android:includeFontPadding="false"android:paddingTop="8dp"android:textColor="#fff"/>

ZFlowLayout.java

 import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;import java.util.ArrayList;
import java.util.List;/****************************** @Copyright(c) 2014-2018* @Author:dengyalan* @Date:2018/1/16* @Description:自定义搜索标签布局* @Version:v1.0.0*****************************/public class ZFlowLayout extends ViewGroup {/*** 存储所有子View*/private List<List<View>> mAllChildViews = new ArrayList<>();/*** 每一行的高度*/private List<Integer> mLineHeight = new ArrayList<>();public ZFlowLayout(Context context) {this(context, null);}public ZFlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ZFlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}@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);//如果当前ViewGroup的宽高为wrap_content的情况//自己测量的宽度int width = 0;//自己测量的高度int height = 0;//记录每一行的宽度和高度int lineWidth = 0;int lineHeight = 0;//获取子view的个数int childCount = getChildCount();for (int i = 0; i < childCount; 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) {//对比得到最大的宽度width = Math.max(width, lineWidth);//重置lineWidthlineWidth = childWidth;//记录行高height += lineHeight;lineHeight = childHeight;} else {//不换行情况//叠加行宽lineWidth += childWidth;//得到最大行高lineHeight = Math.max(lineHeight, childHeight);}//处理最后一个子View的情况if (i == childCount - 1) {width = Math.max(width, lineWidth);height += lineHeight;}}//wrap_contentsetMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width,modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mAllChildViews.clear();mLineHeight.clear();//获取当前ViewGroup的宽度int width = getWidth();int lineWidth = 0;int lineHeight = 0;//记录当前行的viewList<View> lineViews = new ArrayList<View>();int childCount = getChildCount();for (int i = 0; i < childCount; 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) {//记录LineHeightmLineHeight.add(lineHeight);//记录当前行的ViewsmAllChildViews.add(lineViews);//重置行的宽高lineWidth = 0;lineHeight = childHeight + lp.topMargin + lp.bottomMargin;//重置view的集合lineViews = new ArrayList();}lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);lineViews.add(child);}//处理最后一行mLineHeight.add(lineHeight);mAllChildViews.add(lineViews);//设置子View的位置int left = 0;int top = 0;//获取行数int lineCount = mAllChildViews.size();for (int i = 0; i < lineCount; i++) {//当前行的views和高度lineViews = mAllChildViews.get(i);lineHeight = mLineHeight.get(i);for (int j = 0; j < lineViews.size(); j++) {View child = lineViews.get(j);//判断是否显示if (child.getVisibility() == View.GONE) {continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int cLeft = left + lp.leftMargin;int cTop = top + lp.topMargin;int cRight = cLeft + child.getMeasuredWidth();int cBottom = cTop + child.getMeasuredHeight();//进行子View进行布局child.layout(cLeft, cTop, cRight, cBottom);left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;}left = 0;top += lineHeight;}}/*** 与当前ViewGroup对应的LayoutParams*/@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}
}

文章来源:https://blog.csdn.net/qq_39734239/article/details/100888193

Android 实现搜索历史(1)相关推荐

  1. android的UDC功能,Android实现搜索历史功能

    本文实例为大家分享了Android实现搜索历史的具体代码,供大家参考,具体内容如下 SharedPreferences实现本地搜索历史功能,覆盖搜索重复的文本,可清空 1. 判断搜索内容是否含表情,不 ...

  2. Android保存搜索历史

    在我项目中,有这样一个功能实现:先看图 搜索后实时将搜索内容显示到RecyclerView中,可以删除单个历史,也可以清空全部,点击其中一项显示到EditText中.将会涉及到的内容有: Recycl ...

  3. Android实现搜索功能并本地保存搜索历史记录

    本案例实现起来很简单,所以可以直接拿来嵌入项目中使用,涉及到的知识点:  - 数据库的增删改查操作  - ListView和ScrollView的嵌套冲突解决  - 监听软键盘回车按钮设置为搜索按钮  ...

  4. android热门搜索标签,Android网易云历史搜索和热门标签

    Android网易云历史搜索和热门标签 最近开发了一个网易云音乐播放器,有这么一个需求,需要展示搜索建议,历史搜索记录 项目地址: github.com/shellhub/Ne- search_ent ...

  5. Android浏览历史sqlite功能,[Android]greendao实现搜索历史功能

    使用greendao实现搜索历史功能 ezgif-1-378e749b52.gif device-2017-08-31-103330.png 之前封装sqlite实现过这功能,不过原生封装使用sql语 ...

  6. android 搜索历史流布局,FlowLayout流式布局实现搜索清空历史记录

    本文实例为大家分享了FlowLayout实现搜索清空历史记录的具体代码,供大家参考,具体内容如下 效果图:点击搜索框将搜索的历史在流式布局中展示出来,清空历史记录就会将历史清空,每次搜索后都存入sp中 ...

  7. android 历史搜索布局,《Android APP可能有的东西》之UI篇:流式标签搜索历史

    说在前面 很多APP都有热门排行热门搜索什么的,这个时候可能需要用到标签,也就是流式布局,而还有可能用到的就是搜索历史记录,这种一般都是使用listview展示.但是,相当有可能是反过来的UI展示效果 ...

  8. SharedPreferences保存对象以及集合,腾讯MMKV使用,保存搜索历史

    腾讯MMKV使用 implementation 'com.tencent:mmkv-static:1.2.9' MMKV.initialize(this);//会返回MMVK存储的目录(String) ...

  9. GreenDao+SearchView+FlowLoyout实现搜索历史和热门搜索

    之前写过一个静态的搜索页 FlowLayout流式布局实现标签.类似热门搜索这种效果 只是能实现界面效果,但是往往开发中是要把搜索历史缓存到本地数据库中,所以在原基础上添加了数据库功能. 并且把搜索框 ...

  10. android 实现 搜索保存历史记录功能

    大家应该做这个功能 首先想到的是用AutoCompleteTextView 这个控件非常好用 ,而且代码写起来也是非常简单 而且还是自动匹配提示 具体实现方法: 代码实现: <AutoCompl ...

最新文章

  1. 水晶报表乱码中文乱码问题(收藏)
  2. NSString 用法总结与陷阱
  3. boost::format模块测试 wchar_t 格式的使用
  4. 数据挖掘竞赛-美国King County房价预测训练赛
  5. 谈谈这些年前端的变化
  6. Linux指令小记(简明实用)
  7. 云图说|图解DGC:基于华为智能数据湖解决方案的一体化数据治理平台
  8. HBase 中文文档0.97
  9. 企业云成本浪费高达30%!行云管家、Cloudyn等厂商给出解决方案...
  10. 【网络安全】从零开始的CTF生活
  11. android fragment 设置透明,DialogFragment背景透明设置
  12. 阿里 Java 性能调优手册,简直yyds
  13. php图片显示不了,如何解决php显示不了图片的问题
  14. dB、dBFS、dBV、dBu...都是啥啊..
  15. Mixly米思齐_点阵
  16. 我看韩寒-话题2010读后
  17. 随身WIFI刷机记录 UF1003
  18. 安卓修改电池容量教程_手机电池校正 - 安卓最精确的电量校正方法 - iTeknical
  19. 3.原子操作的实现原理
  20. android7 强制gpu渲染,安卓手机开启强制GPU渲染功能的方法

热门文章

  1. 日常修行中离不开观想
  2. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day29】
  3. 云数智驱动数据高速增长,浪潮存储提供EB级容量扩展
  4. 无代码生产新模式探索
  5. mac更新后Git无法使用的问题
  6. SCAR:Scalable Consensus Algorithm 灵活共识算法
  7. 左手鼠标指针——Windows11Aeroleft
  8. MVC下压缩输入的HTML内容
  9. 出租司机微软上MBA课 精辟理论让其月入1万6
  10. 实体门店营销,抽奖系统为何独占鳌头