Android—-搜索历史(带区分切换用户id)

释放双眼,带上耳机,听听看~!

老规矩,先上图:

功能描述:①用户搜索功能,存本地历史记录;②采用流式布局

存储方式: 采用SharedPreferences

优点:避免使用本地数据库导致项目更新版本升级版本号问题,避免sql常规操作失误引发的bug问题。简单实用

一 布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:fitsSystemWindows="false"
android:orientation="vertical">
<!--搜索界面false-->
<RelativeLayout
android:id="@+id/rl_yellow_search"
android:layout_width="match_parent"
android:layout_height="83dp"
android:background="@drawable/bg_title_base">
<!--搜索-->
<RelativeLayout
android:id="@+id/rl_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/ds_10dp"
android:layout_marginLeft="@dimen/ds_12dp"
android:layout_toLeftOf="@+id/tv_search_cancel"
android:background="@drawable/bg_white_round_small"
android:paddingBottom="@dimen/ds_8dp"
android:paddingTop="@dimen/ds_8dp"
tools:ignore="RtlHardcoded">
<ImageButton
android:id="@+id/btn_gray_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/ds_16dp"
android:background="@drawable/icon_xiaoxi_sousuo"
tools:ignore="ContentDescription,RtlHardcoded" />
<com.yc.stscf.widget.LastInputEditText
android:id="@+id/ce_search"
android:layout_width="match_parent"
android:layout_height="@dimen/ds_30dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginRight="@dimen/ds_36dp"
android:layout_toRightOf="@+id/btn_gray_search"
android:background="@null"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text|number"
android:gravity="left|center_horizontal|center_vertical"
android:hint="请输入要搜索的关键词"
android:imeOptions="actionSearch"
android:textColor="@color/cs_999999"
android:textColorHint="@color/cs_999999"
android:textSize="@dimen/ds_14sp"
tools:ignore="HardcodedText,InefficientWeight,NestedWeights,RelativeOverlap,RtlHardcoded,SmallSp" />
<ImageButton
android:id="@+id/btn_gray_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="gone"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/ds_16dp"
android:layout_marginRight="@dimen/ds_6dp"
android:background="@drawable/icon_xiaoxi_sousuo_delete"
android:padding="@dimen/ds_10dp"
tools:ignore="ContentDescription,RtlHardcoded" />
</RelativeLayout>
<!--取消-->
<TextView
android:id="@+id/tv_search_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/ds_20dp"
android:layout_marginLeft="@dimen/ds_13dp"
android:layout_marginRight="@dimen/ds_16dp"
android:paddingBottom="@dimen/ds_8dp"
android:paddingTop="@dimen/ds_8dp"
android:text="取消"
android:textColor="@color/white"
android:textSize="@dimen/ds_15sp"
tools:ignore="HardcodedText,RtlHardcoded" />
</RelativeLayout>
<!--无数据-->
<RelativeLayout
android:id="@+id/rl_no_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:drawablePadding="@dimen/ds_30dp"
android:drawableTop="@drawable/bd_zanwuxiangguannsousuo"
android:gravity="center"
android:text="暂无相关搜索"
android:textColor="@color/cs_ff000000"
android:textSize="@dimen/ds_14sp"
tools:ignore="HardcodedText" />
</RelativeLayout>
<!--1有数据本地历史的-->
<LinearLayout
android:id="@+id/ll_history"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--History搜索-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ds_40dp"
android:background="@color/white"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/ds_16dp"
android:layout_weight="1"
android:text="历史搜索"
android:textColor="@color/cs_4a4a4a"
android:textSize="@dimen/ds_13sp"
tools:ignore="HardcodedText,PxUsage,RtlHardcoded" />
<ImageButton
android:id="@+id/btn_clean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="@dimen/ds_16dp"
android:background="@drawable/icon_xiaoxi_sousuo_shanchu"
tools:ignore="ContentDescription,RtlHardcoded" />
</LinearLayout>
<com.yc.stscf.widget.TagFlowLayout
android:id="@+id/flow_history"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/ds_18dp"
android:layout_marginLeft="@dimen/ds_13dp"
android:layout_marginRight="@dimen/ds_13dp" />
</LinearLayout>
<!--2有数据服务器-->
<com.handmark.pulltorefresh.library.PullToRefreshScrollView
android:id="@+id/pr_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:background="@color/white"
android:scrollbars="none"
app:ptrAnimationStyle="flip"
app:ptrMode="both">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_myRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:nestedScrollingEnabled="false" />
</com.handmark.pulltorefresh.library.PullToRefreshScrollView>
</LinearLayout>

样式解析,部分图片资源什么的,大家自己替换下即将

布局中用到的自定义控件:(PullToRefreshScrollView就不提供了,这块大家注释掉吧)

自定义的edit,可以让光标一直显示在后面。

package com.yc.stscf.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
/**
* ================================================
*
* @author :vip
* @version :V 1.0.0
* @date :2019/6/6 14:56
* 描    述:光标在后的editView
* 修订历史:
* ================================================
*/
@SuppressLint("AppCompatCustomView")
public class LastInputEditText extends EditText {
public LastInputEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LastInputEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LastInputEditText(Context context) {
super(context);
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
super.onSelectionChanged(selStart, selEnd);
//保证光标始终在最后面,//防止不能多选
if (selStart == selEnd) {
setSelection(getText().length());
}
}
}

流式布局三部曲之一,全粘贴即可

package com.yc.stscf.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.yc.stscf.R;
import com.yc.stscf.adapter.TagAdapter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* ================================================
*
* @author:vip 版    本:V 1.0.0
* 创建日期:2018/12/05
* 描    述:搜索自定义布局
* 修订历史:
* ================================================
*/
public class TagFlowLayout extends FlowLayout implements TagAdapter.OnDataChangedListener {
private TagAdapter mTagAdapter;
/**
* -1为不限制数量
**/
private int mSelectedMax = -1;
private static final String TAG = "TagFlowLayout";
private Set<Integer> mSelectedView = new HashSet<Integer>();
private OnSelectListener mOnSelectListener;
private OnTagClickListener mOnTagClickListener;
public interface OnSelectListener {
void onSelected(Set<Integer> selectPosSet);
}
public interface OnTagClickListener {
boolean onTagClick(View view, int position, FlowLayout parent);
}
public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1);
ta.recycle();
}
public TagFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagFlowLayout(Context context) {
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
TagView tagView = (TagView) getChildAt(i);
if (tagView.getVisibility() == View.GONE) {
continue;
}
if (tagView.getTagView().getVisibility() == View.GONE) {
tagView.setVisibility(View.GONE);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setOnSelectListener(OnSelectListener onSelectListener) {
mOnSelectListener = onSelectListener;
}
public void setOnTagClickListener(OnTagClickListener onTagClickListener) {
mOnTagClickListener = onTagClickListener;
}
public void setAdapter(TagAdapter adapter) {
mTagAdapter = adapter;
mTagAdapter.setOnDataChangedListener(this);
mSelectedView.clear();
changeAdapter();
}
private void changeAdapter() {
removeAllViews();
TagAdapter adapter = mTagAdapter;
TagView tagViewContainer = null;
HashSet preCheckedList = mTagAdapter.getPreCheckedList();
for (int i = 0; i < adapter.getCount(); i++) {
View tagView = adapter.getView(this, i, adapter.getItem(i));
tagViewContainer = new TagView(getContext());
tagView.setDuplicateParentStateEnabled(true);
if (tagView.getLayoutParams() != null) {
tagViewContainer.setLayoutParams(tagView.getLayoutParams());
} else {
ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins(dip2px(getContext(), 5),
dip2px(getContext(), 5),
dip2px(getContext(), 5),
dip2px(getContext(), 5));
tagViewContainer.setLayoutParams(lp);
}
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
tagView.setLayoutParams(lp);
tagViewContainer.addView(tagView);
addView(tagViewContainer);
if (preCheckedList.contains(i)) {
setChildChecked(i, tagViewContainer);
}
if (mTagAdapter.setSelected(i, adapter.getItem(i))) {
setChildChecked(i, tagViewContainer);
}
tagView.setClickable(false);
final TagView finalTagViewContainer = tagViewContainer;
final int position = i;
tagViewContainer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doSelect(finalTagViewContainer, position);
if (mOnTagClickListener != null) {
mOnTagClickListener.onTagClick(finalTagViewContainer, position,
TagFlowLayout.this);
}
}
});
}
mSelectedView.addAll(preCheckedList);
}
public void setMaxSelectCount(int count) {
if (mSelectedView.size() > count) {
Log.w(TAG, "you has already select more than " + count + " views , so it will be clear .");
mSelectedView.clear();
}
mSelectedMax = count;
}
public Set<Integer> getSelectedList() {
return new HashSet<Integer>(mSelectedView);
}
private void setChildChecked(int position, TagView view) {
view.setChecked(true);
mTagAdapter.onSelected(position, view.getTagView());
}
private void setChildUnChecked(int position, TagView view) {
view.setChecked(false);
mTagAdapter.unSelected(position, view.getTagView());
}
private void doSelect(TagView child, int position) {
if (!child.isChecked()) {
//处理max_select=1的情况
if (mSelectedMax == 1 && mSelectedView.size() == 1) {
Iterator<Integer> iterator = mSelectedView.iterator();
Integer preIndex = iterator.next();
TagView pre = (TagView) getChildAt(preIndex);
setChildUnChecked(preIndex, pre);
setChildChecked(position, child);
mSelectedView.remove(preIndex);
mSelectedView.add(position);
} else {
if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) {
return;
}
setChildChecked(position, child);
mSelectedView.add(position);
}
} else {
setChildUnChecked(position, child);
mSelectedView.remove(position);
}
if (mOnSelectListener != null) {
mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView));
}
}
public TagAdapter getAdapter() {
return mTagAdapter;
}
private static final String KEY_CHOOSE_POS = "key_choose_pos";
private static final String KEY_DEFAULT = "key_default";
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState());
StringBuilder selectPos = new StringBuilder();
if (mSelectedView.size() > 0) {
for (int key : mSelectedView) {
selectPos.append(key).append("|");
}
selectPos = new StringBuilder(selectPos.substring(0, selectPos.length() - 1));
}
bundle.putString(KEY_CHOOSE_POS, selectPos.toString());
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
String mSelectPos = bundle.getString(KEY_CHOOSE_POS);
if (!TextUtils.isEmpty(mSelectPos)) {
String[] split = mSelectPos.split("\|");
for (String pos : split) {
int index = Integer.parseInt(pos);
mSelectedView.add(index);
TagView tagView = (TagView) getChildAt(index);
if (tagView != null) {
setChildChecked(index, tagView);
}
}
}
super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT));
return;
}
super.onRestoreInstanceState(state);
}
@Override
public void onChanged() {
mSelectedView.clear();
changeAdapter();
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

流式布局三部曲之二,全粘贴即可

package com.yc.stscf.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.yc.stscf.R;
import java.util.ArrayList;
import java.util.List;
/**
* ================================================
*
* @author :Vip
* @version :V 1.0.0
* @date :2019/7/8 14:12
* 描    述:搜索自定义控件
* 修订历史:
* ================================================
*/
public class FlowLayout extends ViewGroup {
private static final String TAG = "FlowLayout";
private static final int LEFT = -1;
private static final int CENTER = 0;
private static final int RIGHT = 1;
protected List<List<View>> mAllViews = new ArrayList<>();
protected List<Integer> mLineHeight = new ArrayList<>();
protected List<Integer> mLineWidth = new ArrayList<>();
private int mGravity;
private List<View> lineViews = new ArrayList<>();
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
@SuppressLint("CustomViewStyleable") TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
mGravity = ta.getInt(R.styleable.TagFlowLayout_tag_gravity, LEFT);
ta.recycle();
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context) {
this(context, null);
}
@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);
int width = 0;
int height = 0;
int lineWidth = 0;
int lineHeight = 0;
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
if (i == cCount - 1) {
width = Math.max(lineWidth, width);
height += lineHeight;
}
continue;
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int childWidth = child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.topMargin
+ lp.bottomMargin;
if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) {
width = Math.max(width, lineWidth);
lineWidth = childWidth;
height += lineHeight;
lineHeight = childHeight;
} else {
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
}
if (i == cCount - 1) {
width = Math.max(lineWidth, width);
height += lineHeight;
}
}
setMeasuredDimension(
modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),
modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()
);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mAllViews.clear();
mLineHeight.clear();
mLineWidth.clear();
lineViews.clear();
int width = getWidth();
int lineWidth = 0;
int lineHeight = 0;
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
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);
mAllViews.add(lineViews);
mLineWidth.add(lineWidth);
lineWidth = 0;
lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
lineViews = new ArrayList<>();
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin);
lineViews.add(child);
}
mLineHeight.add(lineHeight);
mLineWidth.add(lineWidth);
mAllViews.add(lineViews);
int left = getPaddingLeft();
int top = getPaddingTop();
int lineNum = mAllViews.size();
for (int i = 0; i < lineNum; i++) {
lineViews = mAllViews.get(i);
lineHeight = mLineHeight.get(i);
// set gravity
int currentLineWidth = this.mLineWidth.get(i);
switch (this.mGravity) {
case LEFT:
left = getPaddingLeft();
break;
case CENTER:
left = (width - currentLineWidth) / 2 + getPaddingLeft();
break;
case RIGHT:
left = width - currentLineWidth + getPaddingLeft();
break;
default:
break;
}
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 lc = left + lp.leftMargin;
int tc = top + lp.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
child.layout(lc, tc, rc, bc);
left += child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
}
top += lineHeight;
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
return new MarginLayoutParams(p);
}
}

流式布局三部曲之三,全粘贴即可

package com.yc.stscf.adapter;
import android.util.Log;
import android.view.View;
import com.yc.stscf.widget.FlowLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* ================================================
*
* @author:vip 版    本:V 1.0.0
* 创建日期:2018/12/19
* 描    述:搜索及评价列表使用适配器(流式布局)
* 注:
* 修订历史:
* ================================================
*/
public abstract class TagAdapter<T> {
private List<T> mTagDatas;
public OnDataChangedListener mOnDataChangedListener;
@Deprecated
private HashSet<Integer> mCheckedPosList = new HashSet<Integer>();
public TagAdapter(List<T> datas) {
mTagDatas = datas;
}
@Deprecated
public TagAdapter(T[] datas) {
mTagDatas = new ArrayList<T>(Arrays.asList(datas));
}
public interface OnDataChangedListener {
void onChanged();
}
public void setOnDataChangedListener(OnDataChangedListener listener) {
mOnDataChangedListener = listener;
}
/**
* 清除选中的tab
**/
@Deprecated
public void setSelectedList(int... poses) {
Set<Integer> set = new HashSet<>();
for (int pos : poses) {
set.add(pos);
}
setSelectedList(set);
}
@Deprecated
public void setSelectedList(Set<Integer> set) {
mCheckedPosList.clear();
if (set != null) {
mCheckedPosList.addAll(set);
}
notifyDataChanged();
}
@Deprecated
public HashSet<Integer> getPreCheckedList() {
return mCheckedPosList;
}
public int getCount() {
return mTagDatas == null ? 0 : mTagDatas.size();
}
public void notifyDataChanged() {
if (mOnDataChangedListener != null) {
mOnDataChangedListener.onChanged();
}
}
public T getItem(int position) {
return mTagDatas.get(position);
}
public abstract View getView(FlowLayout parent, int position, T t);
public void onSelected(int position, View view) {
Log.d("zhy", "onSelected " + position);
}
public void unSelected(int position, View view) {
Log.d("zhy", "unSelected " + position);
}
public boolean setSelected(int position, T t) {
return false;
}
}

样式引用

<!--搜索-->
<declare-styleable name="TagFlowLayout">
<attr name="max_select" format="integer" />
<attr name="tag_gravity">
<enum name="left" value="-1" />
<enum name="center" value="0" />
<enum name="right" value="1" />
</attr>
</declare-styleable>

二 主界面逻辑

package com.yc.stscf.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.handmark.pulltorefresh.library.PullToRefreshScrollView;
import com.yc.stscf.R;
import com.yc.stscf.adapter.MessageReminderAdapter;
import com.yc.stscf.adapter.TagAdapter;
import com.yc.stscf.base.BaseActivity;
import com.yc.stscf.model.MessageReminderBean;
import com.yc.stscf.storage.PreferenceCache;
import com.yc.stscf.utils.Tt;
import com.yc.stscf.widget.FlowLayout;
import com.yc.stscf.widget.LastInputEditText;
import com.yc.stscf.widget.TagFlowLayout;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
/**
* ================================================
*
* @author :Vip
* @version :V 1.0.0
* @date :2019/7/8 13:40
* 描    述:搜索界面
* 修订历史:
* ================================================
*/
public class SearchActivity extends BaseActivity implements View.OnClickListener {
TagAdapter tagAdapter;
@BindView(R.id.btn_gray_search)
ImageButton btnGraySearch;
@BindView(R.id.ce_search)
LastInputEditText ceSearch;
@BindView(R.id.btn_gray_delete)
ImageButton btnGrayDelete;
@BindView(R.id.rl_search)
RelativeLayout rlSearch;
@BindView(R.id.tv_search_cancel)
TextView tvSearchCancel;
@BindView(R.id.rl_yellow_search)
RelativeLayout rlYellowSearch;
@BindView(R.id.rl_no_date)
RelativeLayout rlNoDate;
@BindView(R.id.rv_myRecycler)
RecyclerView rvMyRecycler;
@BindView(R.id.pr_scroll_view)
PullToRefreshScrollView prScrollView;
@BindView(R.id.btn_clean)
ImageButton btnClean;
@BindView(R.id.flow_history)
TagFlowLayout flowHistory;
List<MessageReminderBean.DataBean> dataBeanList = new ArrayList<>();
MessageReminderAdapter messageReminderAdapter;
@BindView(R.id.ll_history)
LinearLayout llHistory;
private List<String> vip = new ArrayList<>();
/**
* 缓存为用户登录id
**/
public  String KEY_SEARCH_HISTORY_KEYWORD = PreferenceCache.getUsername();
/**
* 使用SharedPreferences记录搜索历史
**/
private SharedPreferences mPref;
@Override
public void initRootView() {
setContentView(R.layout.activity_search);
}
@Override
public void initView() {
//换行变搜索
ceSearch.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
ceSearch.setInputType(EditorInfo.TYPE_CLASS_TEXT);
//限制名称只能输入中文和字母
editLimit();
//输入内容监听刷新
listenerEdit();
}
/**
* 输入文本内容类型限制
**/
private void editLimit() {
ceSearch.setFilters(new InputFilter[]{
new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!Character.isLetterOrDigit(source.charAt(i))
&& !"_".equals(Character.toString(source.charAt(i)))
&& !"-".equals(Character.toString(source.charAt(i)))) {
return "";
}
}
return null;
}
}
});
}
@Override
public void initData() {
mPref = getSharedPreferences("input", Activity.MODE_PRIVATE);
//初始化历搜
initHistory();
//服务器内容
initRecycler();
}
/**
* 初始化历史搜索
**/
private void initHistory() {
String history = mPref.getString(KEY_SEARCH_HISTORY_KEYWORD, "");
if (!TextUtils.isEmpty(history)) {
List<String> list = new ArrayList<String>();
for (Object o : history.split(",")) {
list.add((String) o);
}
vip = list;
historySetData(list);
}
}
/**
* 服务器内容
**/
private void initRecycler() {
if (rvMyRecycler.getRecycledViewPool() != null) {
rvMyRecycler.getRecycledViewPool().setMaxRecycledViews(0, 10);
}
rvMyRecycler.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
messageReminderAdapter = new MessageReminderAdapter(R.layout.item_message_reminder, dataBeanList);
rvMyRecycler.setAdapter(messageReminderAdapter);
/**通知类型,读取状态,内容,日期**/
MessageReminderBean.DataBean messageReminderBean = new MessageReminderBean.DataBean();
messageReminderBean.setTzType("0");
messageReminderBean.setContent("您的授信申请SGJK-SX-SX-201905-0001已审批完成。");
messageReminderBean.setDqStatus("0");
messageReminderBean.setDate("2019-10-01");
MessageReminderBean.DataBean messageReminderBean1 = new MessageReminderBean.DataBean();
messageReminderBean1.setTzType("1");
messageReminderBean1.setContent("您的授信申请SGJK-SX-SX-201905-0001已审批完成。");
messageReminderBean1.setDqStatus("1");
messageReminderBean1.setDate("2019-10-01");
MessageReminderBean.DataBean messageReminderBean2 = new MessageReminderBean.DataBean();
messageReminderBean2.setTzType("2");
messageReminderBean2.setContent("您的授信申请SGJK-SX-SX-201905-0001已审批完成。");
messageReminderBean2.setDqStatus("0");
messageReminderBean2.setDate("2019-10-01");
MessageReminderBean.DataBean messageReminderBean3 = new MessageReminderBean.DataBean();
messageReminderBean3.setTzType("0");
messageReminderBean3.setContent("您的授信申请SGJK-SX-SX-201905-0001已审批完成。");
messageReminderBean3.setDqStatus("0");
messageReminderBean3.setDate("2019-10-01");
dataBeanList.add(messageReminderBean);
dataBeanList.add(messageReminderBean1);
dataBeanList.add(messageReminderBean2);
dataBeanList.add(messageReminderBean3);
messageReminderAdapter.notifyDataSetChanged();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void initListener() {
btnClean.setOnClickListener(this);
btnGrayDelete.setOnClickListener(this);
tvSearchCancel.setOnClickListener(this);
//搜索框的触摸事件(不写无法唤起焦点)
ceSearch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//点击输入框显示搜索并获取焦点
ceSearch.setFocusable(true);
ceSearch.setFocusableInTouchMode(true);
return false;
}
});
//换行改为搜索按钮
ceSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
clickSearchAfter();
return true;
}
return false;
}
});
}
/**
* 搜索输入按钮监听显隐删除按钮
**/
private void listenerEdit() {
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (ceSearch.getText().toString().trim().length() > 0) {
btnGrayDelete.setVisibility(View.VISIBLE);
} else {
btnGrayDelete.setVisibility(View.GONE);
}
}
};
ceSearch.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
ceSearch.addTextChangedListener(textWatcher);
} else {
ceSearch.removeTextChangedListener(textWatcher);
}
}
});
}
/**
* 点击搜索按钮之后的共通逻辑
* 注:丢光标不需要处理了,搜索后直接跳页面,键盘则会自动隐藏
**/
@SuppressLint("ApplySharedPref")
private void clickSearchAfter() {
if (ceSearch.getText().toString().trim().length() > 0) {
//TODO  临时为了展示
if ("小猫".equals(ceSearch.getText().toString().trim())) {
rlNoDate.setVisibility(View.VISIBLE);
} else {
rlNoDate.setVisibility(View.GONE);
}
String text = ceSearch.getText().toString().trim();
String oldText = mPref.getString(KEY_SEARCH_HISTORY_KEYWORD, "");
List<String>shaList=Arrays.asList(oldText.split(","));
Log.e("tag", "" + oldText);
Log.e("Tag", "" + text);
Log.e("Tag", "" + oldText.contains(text));
if (!TextUtils.isEmpty(text) && !(shaList.contains(text))) {
//Todo 限制位数
//                    if (vip != null) {
//                        if (vip.size() > 5) {
//                            //最多保存条数
//                            return;
//                        }
//                    }
SharedPreferences.Editor editor = mPref.edit();
editor.putString(KEY_SEARCH_HISTORY_KEYWORD, text + "," + oldText);
editor.commit();
vip.add(0, text);
} else {
Tt.showToast(mContext, "历史搜索已存在您想要输入的内容~!");
}
historySetData(vip);
ceSearch.setFocusable(false);
ceSearch.setFocusableInTouchMode(false);
ceSearch.clearFocus();
String searchContent = ceSearch.getText().toString().trim();
Toast.makeText(mContext, "搜索内容为:" + searchContent, Toast.LENGTH_SHORT).show();
//TODO  点了搜索以后,而且查到东西了,先显示列表,
llHistory.setVisibility(View.GONE);
prScrollView.setVisibility(View.VISIBLE);
} else {
prScrollView.setVisibility(View.GONE);
llHistory.setVisibility(View.VISIBLE);
Tt.showShort(mContext, "搜索内容不能为空");
}
hintKeyBoard();
}
/**
* 清空数据
*/
@SuppressLint("ApplySharedPref")
private void deleteData() {
mPref = getSharedPreferences("input", MODE_PRIVATE);
SharedPreferences.Editor editor = mPref.edit();
editor.remove(KEY_SEARCH_HISTORY_KEYWORD).commit();
vip.clear();
historySetData(vip);
Toast.makeText(mContext, "清楚搜索历史成功", Toast.LENGTH_LONG).show();
}
/**
* 历史记录填充数据
**/
private void historySetData(final List<String> history) {
flowHistory.setAdapter(tagAdapter = new TagAdapter<String>(history) {
@Override
public View getView(FlowLayout parent, int position, String s) {
TextView tv = new TextView(mContext);
tv.setTextSize(12);
tv.setPadding(40, 18, 40, 18);
tv.setTextColor(getResources().getColor(R.color.cs_4a4a4a));
tv.setBackgroundResource(R.drawable.bg_gray_round_small);
tv.setText(s);
return tv;
}
});
flowHistory.setOnTagClickListener(new TagFlowLayout.OnTagClickListener() {
@Override
public boolean onTagClick(View view, int position, FlowLayout parent) {
Toast.makeText(mContext, history.get(position), Toast.LENGTH_SHORT).show();
return true;
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_clean:
//清空缓存
deleteData();
break;
case R.id.btn_gray_delete:
ceSearch.setText("");
prScrollView.setVisibility(View.GONE);
llHistory.setVisibility(View.VISIBLE);
rlNoDate.setVisibility(View.GONE);
break;
case R.id.tv_search_cancel:
finish();
break;
default:
break;
}
}
/**
* 关闭键盘
**/
public void hintKeyBoard() {
View view = getWindow().peekDecorView();
if (view != null) {
InputMethodManager inputManger = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert inputManger != null;
inputManger.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}

补充:BaseActivity 是我自己封装的界面,大家可以替换成原始的Activity,没任何影响。

三精髓剖析:

自己先建立一个缓存,存用户id,作为唯一标识,登录时候就存。我没给提供PreferenceCache这个类,大家可以先按正规操作去处理,或者临时写个:“abc”.

防止输入的edit输入了表情符号等诡异内容,因为在正规搜索的时候,我们第一是要存本地缓存,第二是将输入内容传到服务器做关联查询,防止服务器这边java后端未做处理导致的异常,我们在移动端提前预判一下。

一进到页面,查这个缓存里,有没有东西,有的话,就循环找处理,添加到最开始我们放的全局的vip这个list里,命名有点随意了,见谅。

这两个方法按注释描述执行即可,需要加,一个是增加了搜索的焦点,能让你操作edit很省心,二是唤起键盘时候,把键盘的换行按钮改写为搜索,因为有的需求没有搜索按钮。

删除按钮 的显隐,没什么大用这玩意。也是为了满足需求写的。

搜索内容不为空的情况下,图中的“小猫”是为了显示无数据时候的占位图,只是为了测试逻辑,这里你可以按自己实际需求替换,这可以理解为:当你输入了内容,点击了搜索,把输入内容传入服务,调用服务器返回了成功情况下,无查询到数据,那么显示占位图。

下方的String text 是输入的内容,oldText是从本地缓存拿到的历史内容,如果输入的内容在历史记录里有,不存并提示,否则存进去。,存这个拼接的。这个是指,你心里有没有我的方法。

清空。很简洁了。清空完了刷新数据,给吐司提示。

填充数据,常规写法。就这么去动态设置文本的间距样式吧。

总结:

没什么总结的了,肯定好用。切换用户账号是好用的,博主采用了3个手机号登录,输入了不同的搜索内容,切换账号登录均能显示对应的历史记录,清空操作也好用,清除的是单独的用户的搜索记录。有问题欢迎留言,代码写的粗糙了点,只为实现功能,等项目有了服务器数据,再二次封装优化。

重点:

          

图中 老的历史数据要转换成List之后再去比较,否则在执行 contains方法时候会被包含。

人已赞赏
Android文章

Android----知识小补充(在适配器关闭当前界面)

2020-3-19 21:15:30

Android文章

Android 串口通讯

2020-3-19 21:24:35

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索