关键词搜索历史

需求

商品搜索,资讯搜索等都需要搜索历史
主要就是一个流式布局 加本地存储
以及一些操作上的优化
这里来一篇自己手写的全过程

效果

这里写图片描述

分析

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);
    }
}

猜你喜欢

转载自blog.csdn.net/jiushiwo12340/article/details/78899962