Android自定义流式布局实现淘宝搜索记录

本文实例为大家分享了Android实现淘宝搜索记录的具体代码,供大家参考,具体内容如下

效果如下:

废话不多说

实现代码:

attrs.xml

<declare-styleable name="TagFlowLayout">

<!--最大选择数量-->

<attr name="max_select" format="integer"/>

<!--最大可显示行数-->

<attr name="limit_line_count" format="integer"/>

<!--是否设置多行隐藏-->

<attr name="is_limit" format="boolean"/>

<attr name="tag_gravity">

<enum name="left" value="-1"/>

<enum name="center" value="0"/>

<enum name="right" value="1"/>

</attr>

</declare-styleable>

TagFlowLayout .java

public class TagFlowLayout extends FlowLayout

implements TagAdapter.OnDataChangedListener {

private static final String TAG = "TagFlowLayout";

private TagAdapter mTagAdapter;

private int mSelectedMax = -1;//-1为不限制数量

private Set<Integer> mSelectedView = new HashSet<Integer>();

private OnSelectListener mOnSelectListener;

private OnTagClickListener mOnTagClickListener;

private OnLongClickListener mOnLongClickListener;

public interface OnSelectListener {

void onSelected(Set<Integer> selectPosSet);

}

public interface OnTagClickListener {

void onTagClick(View view, int position, FlowLayout parent);

}

public interface OnLongClickListener {

void onLongClick(View view, int position);

}

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 setOnLongClickListener(OnLongClickListener onLongClickListener) {

mOnLongClickListener = onLongClickListener;

}

public void setAdapter(TagAdapter adapter) {

mTagAdapter = adapter;

mTagAdapter.setOnDataChangedListener(this);

mSelectedView.clear();

changeAdapter();

}

@SuppressWarnings("ResourceType")

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 {

MarginLayoutParams lp = new MarginLayoutParams(

LayoutParams.WRAP_CONTENT,

LayoutParams.WRAP_CONTENT);

lp.setMargins(dip2px(getContext(), 5),

dip2px(getContext(), 5),

dip2px(getContext(), 5),

dip2px(getContext(), 5));

tagViewContainer.setLayoutParams(lp);

}

LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 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);

}

}

});

tagViewContainer.setOnLongClickListener(new View.OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

if (mOnLongClickListener != null) {

mOnLongClickListener.onLongClick(finalTagViewContainer, position);

//消费事件,不让事件继续下去

return true;

}

return false;

}

});

}

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

String selectPos = "";

if (mSelectedView.size() > 0) {

for (int key : mSelectedView) {

selectPos += key + "|";

}

selectPos = selectPos.substring(0, selectPos.length() - 1);

}

bundle.putString(KEY_CHOOSE_POS, selectPos);

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

}

}

TagView

public class TagView extends FrameLayout implements Checkable

{

private boolean isChecked;

private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked};

public TagView(Context context)

{

super(context);

}

public View getTagView()

{

return getChildAt(0);

}

@Override

public int[] onCreateDrawableState(int extraSpace)

{

int[] states = super.onCreateDrawableState(extraSpace + 1);

if (isChecked())

{

mergeDrawableStates(states, CHECK_STATE);

}

return states;

}

/**

* Change the checked state of the view

*

* @param checked The new checked state

*/

@Override

public void setChecked(boolean checked)

{

if (this.isChecked != checked)

{

this.isChecked = checked;

refreshDrawableState();

}

}

/**

* @return The current checked state of the view

*/

@Override

public boolean isChecked()

{

return isChecked;

}

/**

* Change the checked state of the view to the inverse of its current state

*/

@Override

public void toggle()

{

setChecked(!isChecked);

}

}

FlowLayout

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;

private int limitLineCount; //默认显示3行 断词条显示3行,长词条显示2行

private boolean isLimit; //是否有行限制

private boolean isOverFlow; //是否溢出2行

private int mGravity;

protected List<List<View>> mAllViews = new ArrayList<List<View>>();

protected List<Integer> mLineHeight = new ArrayList<Integer>();

protected List<Integer> mLineWidth = new ArrayList<Integer>();

private List<View> lineViews = new ArrayList<>();

public boolean isOverFlow() {

return isOverFlow;

}

private void setOverFlow(boolean overFlow) {

isOverFlow = overFlow;

}

public boolean isLimit() {

return isLimit;

}

public void setLimit(boolean limit) {

if (!limit) {

setOverFlow(false);

}

isLimit = limit;

}

public FlowLayout(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);

mGravity = ta.getInt(R.styleable.TagFlowLayout_tag_gravity, LEFT);

limitLineCount = ta.getInt(R.styleable.TagFlowLayout_limit_line_count, 3);

isLimit = ta.getBoolean(R.styleable.TagFlowLayout_is_limit, false);

int layoutDirection = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault());

if (layoutDirection == LayoutDirection.RTL) {

if (mGravity == LEFT) {

mGravity = RIGHT;

} else {

mGravity = 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);

// wrap_content

int width = 0;

int height = 0;

int lineWidth = 0;

int lineHeight = 0;

//在每一次换行之后记录,是否超过了行数

int lineCount = 0;//记录当前的行数

int cCount = getChildCount();

for (int i = 0; i < cCount; i++) {

View child = getChildAt(i);

if (child.getVisibility() == View.GONE) {

if (i == cCount - 1) {

if (isLimit) {

if (lineCount == limitLineCount) {

setOverFlow(true);

break;

} else {

setOverFlow(false);

}

}

width = Math.max(lineWidth, width);

height += lineHeight;

lineCount++;

}

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()) {

if (isLimit) {

if (lineCount == limitLineCount) {

setOverFlow(true);

break;

} else {

setOverFlow(false);

}

}

width = Math.max(width, lineWidth);

lineWidth = childWidth;

height += lineHeight;

lineHeight = childHeight;

lineCount++;

} else {

lineWidth += childWidth;

lineHeight = Math.max(lineHeight, childHeight);

}

if (i == cCount - 1) {

if (isLimit) {

if (lineCount == limitLineCount) {

setOverFlow(true);

break;

} else {

setOverFlow(false);

}

}

width = Math.max(lineWidth, width);

height += lineHeight;

lineCount++;

}

}

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 lineCount = 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()) {

if (isLimit) {

if (lineCount == limitLineCount) {

break;

}

}

mLineHeight.add(lineHeight);

mAllViews.add(lineViews);

mLineWidth.add(lineWidth);

lineWidth = 0;

lineHeight = childHeight + lp.topMargin + lp.bottomMargin;

lineViews = new ArrayList<View>();

lineCount++;

}

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:

// 适配了rtl,需要补偿一个padding值

left = width - (currentLineWidth + getPaddingLeft()) - getPaddingRight();

// 适配了rtl,需要把lineViews里面的数组倒序排

Collections.reverse(lineViews);

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

}

}

TagAdapter

public abstract class TagAdapter<T> {

private List<T> mTagDatas;

private OnDataChangedListener mOnDataChangedListener;

@Deprecated

private HashSet<Integer> mCheckedPosList = new HashSet<Integer>();

public TagAdapter(List<T> datas) {

mTagDatas = datas;

}

public void setData(List<T> datas) {

mTagDatas = datas;

}

@Deprecated

public TagAdapter(T[] datas) {

mTagDatas = new ArrayList<T>(Arrays.asList(datas));

}

interface OnDataChangedListener {

void onChanged();

}

void setOnDataChangedListener(OnDataChangedListener listener) {

mOnDataChangedListener = listener;

}

@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

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;

}

}

RecordsDao

public class RecordsDao {

private final String TABLE_NAME = "records";

private SQLiteDatabase recordsDb;

private RecordSQLiteOpenHelper recordHelper;

private NotifyDataChanged mNotifyDataChanged;

private String mUsername;

public RecordsDao(Context context, String username) {

recordHelper = new RecordSQLiteOpenHelper(context);

mUsername = username;

}

public interface NotifyDataChanged {

void notifyDataChanged();

}

/**

* 设置数据变化监听

*/

public void setNotifyDataChanged(NotifyDataChanged notifyDataChanged) {

mNotifyDataChanged = notifyDataChanged;

}

/**

* 移除数据变化监听

*/

public void removeNotifyDataChanged() {

if (mNotifyDataChanged != null) {

mNotifyDataChanged = null;

}

}

private synchronized SQLiteDatabase getWritableDatabase() {

return recordHelper.getWritableDatabase();

}

private synchronized SQLiteDatabase getReadableDatabase() {

return recordHelper.getReadableDatabase();

}

/**

* 如果考虑操作频繁可以到最后不用数据库时关闭

* <p>

* 关闭数据库

*/

public void closeDatabase() {

if (recordsDb != null) {

recordsDb.close();

}

}

/**

* 添加搜索记录

*

* @param record 记录

*/

public void addRecords(String record) {

//如果这条记录没有则添加,有则更新时间

int recordId = getRecordId(record);

try {

recordsDb = getReadableDatabase();

if (-1 == recordId) {

ContentValues values = new ContentValues();

values.put("username", mUsername);

values.put("keyword", record);

//添加搜索记录

recordsDb.insert(TABLE_NAME, null, values);

} else {

Date d = new Date();

@SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

//更新搜索历史数据时间

ContentValues values = new ContentValues();

values.put("time", sdf.format(d));

recordsDb.update(TABLE_NAME, values, "_id = ?", new String[]{Integer.toString(recordId)});

}

if (mNotifyDataChanged != null) {

mNotifyDataChanged.notifyDataChanged();

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 判断是否含有该搜索记录

*

* @param record 记录

* @return true | false

*/

public boolean isHasRecord(String record) {

boolean isHasRecord = false;

Cursor cursor = null;

try {

recordsDb = getReadableDatabase();

cursor = recordsDb.query(TABLE_NAME, null, "username = ?", new String[]{mUsername}, null, null, null);

while (cursor.moveToNext()) {

if (record.equals(cursor.getString(cursor.getColumnIndexOrThrow("keyword")))) {

isHasRecord = true;

}

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} finally {

if (cursor != null) {

//关闭游标

cursor.close();

}

}

return isHasRecord;

}

/**

* 判断是否含有该搜索记录

*

* @param record 记录

* @return id

*/

public int getRecordId(String record) {

int isHasRecord = -1;

Cursor cursor = null;

try {

recordsDb = getReadableDatabase();

cursor = recordsDb.query(TABLE_NAME, null, "username = ?", new String[]{mUsername}, null, null, null);

while (cursor.moveToNext()) {

if (record.equals(cursor.getString(cursor.getColumnIndexOrThrow("keyword")))) {

isHasRecord = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));

}

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} finally {

if (cursor != null) {

//关闭游标

cursor.close();

}

}

return isHasRecord;

}

/**

* 获取当前用户全部搜索记录

*

* @return 记录集合

*/

public List<String> getRecordsList() {

List<String> recordsList = new ArrayList<>();

Cursor cursor = null;

try {

recordsDb = getReadableDatabase();

cursor = recordsDb.query(TABLE_NAME, null, "username = ?", new String[]{mUsername}, null, null, "time desc");

while (cursor.moveToNext()) {

String name = cursor.getString(cursor.getColumnIndexOrThrow("keyword"));

recordsList.add(name);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} finally {

if (cursor != null) {

//关闭游标

cursor.close();

}

}

return recordsList;

}

/**

* 获取指定数量搜索记录

*

* @return 记录集合

*/

public List<String> getRecordsByNumber(int recordNumber) {

List<String> recordsList = new ArrayList<>();

if (recordNumber < 0) {

throw new IllegalArgumentException();

} else if (0 == recordNumber) {

return recordsList;

} else {

Cursor cursor = null;

try {

recordsDb = getReadableDatabase();

cursor = recordsDb.query(TABLE_NAME, null, "username = ?", new String[]{mUsername}, null, null, "time desc limit " + recordNumber);

while (cursor.moveToNext()) {

String name = cursor.getString(cursor.getColumnIndexOrThrow("keyword"));

recordsList.add(name);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} finally {

if (cursor != null) {

//关闭游标

cursor.close();

}

}

}

return recordsList;

}

/**

* 模糊查询

*

* @param record 记录

* @return 返回类似记录

*/

public List<String> querySimlarRecord(String record) {

List<String> similarRecords = new ArrayList<>();

Cursor cursor = null;

try {

recordsDb = getReadableDatabase();

cursor = recordsDb.query(TABLE_NAME, null, "username = ? and keyword like '%?%'", new String[]{mUsername, record}, null, null, "order by time desc");

while (cursor.moveToNext()) {

String name = cursor.getString(cursor.getColumnIndexOrThrow("keyword"));

similarRecords.add(name);

}

} catch (IllegalArgumentException e) {

e.printStackTrace();

} finally {

if (cursor != null) {

//关闭游标

cursor.close();

}

}

return similarRecords;

}

/**

* 清除指定用户的搜索记录

*/

public void deleteUsernameAllRecords() {

try {

recordsDb = getWritableDatabase();

recordsDb.delete(TABLE_NAME, "username = ?", new String[]{mUsername});

if (mNotifyDataChanged != null) {

mNotifyDataChanged.notifyDataChanged();

}

} catch (SQLException e) {

e.printStackTrace();

Log.e(TABLE_NAME, "清除所有历史记录失败");

} finally {

}

}

/**

* 清空数据库所有的历史记录

*/

public void deleteAllRecords() {

try {

recordsDb = getWritableDatabase();

recordsDb.execSQL("delete from " + TABLE_NAME);

if (mNotifyDataChanged != null) {

mNotifyDataChanged.notifyDataChanged();

}

} catch (SQLException e) {

e.printStackTrace();

Log.e(TABLE_NAME, "清除所有历史记录失败");

} finally {

}

}

/**

* 通过id删除记录

*

* @param id 记录id

* @return 返回删除id

*/

public int deleteRecord(int id) {

int d = -1;

try {

recordsDb = getWritableDatabase();

d = recordsDb.delete(TABLE_NAME, "_id = ?", new String[]{Integer.toString(id)});

if (mNotifyDataChanged != null) {

mNotifyDataChanged.notifyDataChanged();

}

} catch (Exception e) {

e.printStackTrace();

Log.e(TABLE_NAME, "删除_id:" + id + "历史记录失败");

}

return d;

}

/**

* 通过记录删除记录

*

* @param record 记录

*/

public int deleteRecord(String record) {

int recordId = -1;

try {

recordsDb = getWritableDatabase();

recordId = recordsDb.delete(TABLE_NAME, "username = ? and keyword = ?", new String[]{mUsername, record});

if (mNotifyDataChanged != null) {

mNotifyDataChanged.notifyDataChanged();

}

} catch (SQLException e) {

e.printStackTrace();

Log.e(TABLE_NAME, "清除所有历史记录失败");

}

return recordId;

}

}

RecordSQLiteOpenHelper

public class RecordSQLiteOpenHelper extends SQLiteOpenHelper {

private final static String DB_NAME = "search_history.db";

private final static int DB_VERSION = 1;

public RecordSQLiteOpenHelper(Context context) {

super(context, DB_NAME, null, DB_VERSION);

}

@Override

public void onCreate(SQLiteDatabase db) {

String sqlStr = "CREATE TABLE IF NOT EXISTS records (_id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, keyword TEXT, time NOT NULL DEFAULT (datetime('now','localtime')));";

db.execSQL(sqlStr);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

item_background.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">

<solid android:color="#F8F8F8">

</solid>

<corners android:radius="40dp"/>

<padding

android:bottom="4dp"

android:left="12dp"

android:right="12dp"

android:top="4dp"/>

</shape>

search_item_background.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">

<solid android:color="#F8F8F8">

</solid>

<corners android:radius="40dp"/>

<padding

android:bottom="2dp"

android:left="10dp"

android:right="10dp"

android:top="2dp"/>

</shape>

tv_history.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5dp"

android:background="@drawable/item_background"

android:text="搜索历史"

android:singleLine="true"

android:textColor="#666666"

android:textSize="13sp">

</TextView>

activity_main.xml

<android.support.constraint.ConstraintLayout

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="@android:color/white"

tools:context="com.demo.www.MainActivity">

<!--标题栏-->

<android.support.constraint.ConstraintLayout

android:id="@+id/cl_toolbar"

android:layout_width="match_parent"

android:layout_height="?attr/actionBarSize"

android:background="@color/colorAccent"

android:orientation="horizontal"

app:layout_constraintTop_toTopOf="parent">

<ImageView

android:id="@+id/iv_back"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:paddingLeft="@dimen/space_large"

android:paddingRight="@dimen/space_large"

android:src="@mipmap/home"/>

<LinearLayout

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_marginBottom="10dp"

android:layout_marginTop="10dp"

android:background="@drawable/search_item_background"

android:focusable="true"

android:focusableInTouchMode="true"

android:gravity="center"

android:orientation="horizontal"

android:paddingLeft="12dp"

android:paddingRight="12dp"

app:layout_constraintLeft_toRightOf="@+id/iv_back"

app:layout_constraintRight_toLeftOf="@+id/iv_search">

<EditText

android:id="@+id/edit_query"

android:layout_width="0dp"

android:layout_height="match_parent"

android:layout_weight="1"

android:background="@null"

android:hint="请输入搜索关键字"

android:imeOptions="actionSearch"

android:singleLine="true"

android:textSize="14sp"/>

<ImageView

android:id="@+id/iv_clear_search"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginBottom="@dimen/space_normal"

android:layout_marginTop="@dimen/space_normal"

android:src="@mipmap/ic_delete"/>

</LinearLayout>

<TextView

android:id="@+id/iv_search"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:gravity="center"

android:paddingLeft="@dimen/space_large"

android:paddingRight="@dimen/space_large"

android:text="搜索"

android:textColor="@android:color/white"

app:layout_constraintRight_toRightOf="parent"/>

</android.support.constraint.ConstraintLayout>

<!--历史搜索-->

<LinearLayout

android:id="@+id/ll_history_content"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical"

android:paddingLeft="@dimen/space_large"

android:paddingRight="@dimen/space_large"

android:paddingTop="@dimen/space_normal"

app:layout_constraintTop_toBottomOf="@+id/cl_toolbar">

<android.support.constraint.ConstraintLayout

android:layout_width="match_parent"

android:layout_height="wrap_content">

<TextView

android:id="@+id/tv_history_hint"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="搜索历史"

android:textColor="#383838"

android:textSize="14sp"/>

<ImageView

android:id="@+id/clear_all_records"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:src="@mipmap/ic_delete_history"

app:layout_constraintBottom_toTopOf="parent"

app:layout_constraintRight_toRightOf="parent"

app:layout_constraintTop_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

<TagFlowLayout

android:id="@+id/fl_search_records"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:paddingTop="@dimen/space_normal"

app:is_limit="true"

app:limit_line_count="3"

app:max_select="1">

</TagFlowLayout>

<ImageView

android:id="@+id/iv_arrow"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:src="@mipmap/ic_arrow"

android:visibility="gone"/>

</LinearLayout>

</android.support.constraint.ConstraintLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

private RecordsDao mRecordsDao;

//默然展示词条个数

private final int DEFAULT_RECORD_NUMBER = 10;

private List<String> recordList = new ArrayList<>();

private TagAdapter mRecordsAdapter;

private LinearLayout mHistoryContent;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//默认账号

String username = "007";

//初始化数据库

mRecordsDao = new RecordsDao(this, username);

final EditText editText = findViewById(R.id.edit_query);

final TagFlowLayout tagFlowLayout = findViewById(R.id.fl_search_records);

final ImageView clearAllRecords = findViewById(R.id.clear_all_records);

final ImageView moreArrow = findViewById(R.id.iv_arrow);

TextView search = findViewById(R.id.iv_search);

ImageView clearSearch = findViewById(R.id.iv_clear_search);

mHistoryContent = findViewById(R.id.ll_history_content);

initData();

//创建历史标签适配器

//为标签设置对应的内容

mRecordsAdapter = new TagAdapter<String>(recordList) {

@Override

public View getView(FlowLayout parent, int position, String s) {

TextView tv = (TextView) LayoutInflater.from(MainActivity.this).inflate(R.layout.tv_history,

tagFlowLayout, false);

//为标签设置对应的内容

tv.setText(s);

return tv;

}

};

tagFlowLayout.setAdapter(mRecordsAdapter);

tagFlowLayout.setOnTagClickListener(new TagFlowLayout.OnTagClickListener() {

@Override

public void onTagClick(View view, int position, FlowLayout parent) {

//清空editText之前的数据

editText.setText("");

//将获取到的字符串传到搜索结果界面,点击后搜索对应条目内容

editText.setText(recordList.get(position));

editText.setSelection(editText.length());

}

});

//删除某个条目

tagFlowLayout.setOnLongClickListener(new TagFlowLayout.OnLongClickListener() {

@Override

public void onLongClick(View view, final int position) {

showDialog("确定要删除该条历史记录?", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//删除某一条记录

mRecordsDao.deleteRecord(recordList.get(position));

}

});

}

});

//view加载完成时回调

tagFlowLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

boolean isOverFlow = tagFlowLayout.isOverFlow();

boolean isLimit = tagFlowLayout.isLimit();

if (isLimit && isOverFlow) {

moreArrow.setVisibility(View.VISIBLE);

} else {

moreArrow.setVisibility(View.GONE);

}

}

});

moreArrow.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

tagFlowLayout.setLimit(false);

mRecordsAdapter.notifyDataChanged();

}

});

//清除所有记录

clearAllRecords.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

showDialog("确定要删除全部历史记录?", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

tagFlowLayout.setLimit(true);

//清除所有数据

mRecordsDao.deleteUsernameAllRecords();

}

});

}

});

search.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

String record = editText.getText().toString();

if (!TextUtils.isEmpty(record)) {

//添加数据

mRecordsDao.addRecords(record);

}

}

});

clearSearch.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//清除搜索历史

editText.setText("");

}

});

mRecordsDao.setNotifyDataChanged(new RecordsDao.NotifyDataChanged() {

@Override

public void notifyDataChanged() {

initData();

}

});

}

private void showDialog(String dialogTitle, @NonNull DialogInterface.OnClickListener onClickListener) {

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

builder.setMessage(dialogTitle);

builder.setPositiveButton("确定", onClickListener);

builder.setNegativeButton("取消", null);

builder.create().show();

}

private void initData() {

Observable.create(new ObservableOnSubscribe<List<String>>() {

@Override

public void subscribe(ObservableEmitter<List<String>> emitter) throws Exception {

emitter.onNext(mRecordsDao.getRecordsByNumber(DEFAULT_RECORD_NUMBER));

}

}).subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Consumer<List<String>>() {

@Override

public void accept(List<String> s) throws Exception {

recordList.clear();

recordList = s;

if (null == recordList || recordList.size() == 0) {

mHistoryContent.setVisibility(View.GONE);

} else {

mHistoryContent.setVisibility(View.VISIBLE);

}

if (mRecordsAdapter != null) {

mRecordsAdapter.setData(recordList);

mRecordsAdapter.notifyDataChanged();

}

}

});

}

@Override

protected void onDestroy() {

mRecordsDao.closeDatabase();

mRecordsDao.removeNotifyDataChanged();

super.onDestroy();

}

}

欢迎大家点赞,评论!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 Android自定义流式布局实现淘宝搜索记录 的全部内容, 来源链接: utcz.com/p/243089.html

回到顶部