利用SimpleCursorAdapter自定义SearchView实践

android:id=“@+id/search_back”

android:layout_width=“38dp”

android:layout_height=“38dp”

android:layout_gravity=“center_vertical”

android:padding=“10dp”

android:src=“@drawable/back” />

<edu.fjnu.mysearchview.ModEditText

android:id=“@+id/et_search”

android:layout_width=“0dp”

android:layout_height=“fill_parent”

android:layout_weight=“264”

android:background=“@null”

android:drawableLeft=“@drawable/search”

android:drawablePadding=“8dp”

android:gravity=“start|center_vertical”

android:imeOptions=“actionSearch”

android:singleLine=“true”

/>

<ScrollView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”>

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:orientation=“vertical”>

<edu.fjnu.mysearchview.SearchListView

android:id=“@+id/listView”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

</edu.fjnu.mysearchview.SearchListView>

<TextView

android:id=“@+id/tv_clear”

android:layout_width=“match_parent”

android:layout_height=“40dp”

android:background=“#F6F6F6”

android:gravity=“center”

android:visibility=“invisible”

android:text=“清除搜索历史” />

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:orientation=“vertical” android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<ImageView

android:layout_alignParentLeft=“true”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:id=“@+id/ItemImage”/>

<TextView

android:layout_width=“fill_parent”

android:layout_height=“wrap_content”

android:textSize=“20dp”

android:layout_toRightOf=“@id/ItemImage”

android:id=“@+id/ItemTitle”/>

接口

//搜索接口

public interface sCallBack{

void SearchAciton(String string);

}

//返回|退回接口

public interface bCallBack{

void BackAction(String string);

}

SearchView

package edu.fjnu.mysearchview;

import android.content.Context;

import android.content.res.TypedArray;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.text.Editable;

import android.text.TextWatcher;

import android.util.AttributeSet;

import android.view.KeyEvent;

import android.view.LayoutInflater;

import android.view.View;

import android.widget.AdapterView;

import android.widget.BaseAdapter;

import android.widget.Button;

import android.widget.CursorAdapter;

import android.widget.EditText;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.TextView;

import android.widget.Toast;

public class SearchView extends LinearLayout {

private Context context;

//初始化搜索框组件

private EditText editTextSearch;

private TextView textView_Clear;

private LinearLayout search_block;

private ImageView searchBack;

//初始化自定义ListView与adapter

private SearchListView listView;

private SimpleCursorAdapter adapter;//SimpleCursorAdapter是个很灵活的适配器,能灵活的将数据库的搜索结果作为数据源加入ListView,详见接下来的内容

//初始化数据库

private DBSqliteOpenHelper helper;

private SQLiteDatabase db;

//初始化搜索接口与返回接口

private sCallBack sCallBack;

private bCallBack bCallBack;

// 搜索字体属性设置:大小、颜色 & 默认提示

private Float textSizeSearch;

private int textColorSearch;

private String textHintSearch;

// 搜索框设置:高度 & 颜色&历史结果图标

private int searchBlockHeight;

private int searchBlockColor;

private int historyimg;

/**

  • 构造函数

  • 作用:对搜索框进行初始化

*/

public SearchView(Context context) {

super(context);

this.context = context;

initData(context);// ->>初始化数据

init();// ->>初始化设置

}

public SearchView(Context context, AttributeSet attrs) {

super(context, attrs);

this.context = context;

initAttrs(context, attrs); // ->>初始化自定义属性

initData(context);// ->>初始化数据

init();// ->>初始化设置

}

public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

this.context = context;

initAttrs(context, attrs); // ->>初始化自定义属性

initData(context);// ->>初始化数据

init();// ->>初始化设置

}

/**

  • 作用:初始化自定义属性

*/

private void initAttrs(Context context, AttributeSet attrs) {

// 控件资源名称

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Search_View);

// 搜索框字体大小(dp)

textSizeSearch = typedArray.getDimension(R.styleable.Search_View_textSizeSearch, 20);

// 搜索框字体颜色

int defaultColor = context.getResources().getColor(R.color.colorText); // 默认颜色 = 灰色

textColorSearch = typedArray.getColor(R.styleable.Search_View_textColorSearch, defaultColor);

// 搜索框提示内容(String)

textHintSearch = typedArray.getString(R.styleable.Search_View_textHintSearch);

// 搜索框高度

searchBlockHeight = typedArray.getInteger(R.styleable.Search_View_searchBlockHeight, 150);

// 搜索框颜色

int defaultColor2 = context.getResources().getColor(R.color.colorDefault);

searchBlockColor = typedArray.getColor(R.styleable.Search_View_searchBlockColor, defaultColor2);

//设置历史记录图标

historyimg = R.mipmap.history_32px;

// 释放资源

typedArray.recycle();

}

/**

  • 初始化数据库数据

*/

public void initData(Context context) {

helper = new DBSqliteOpenHelper(context);

db = helper.getWritableDatabase();

String sql=“insert into records(name,photo_id) values(?,?)”;

db.execSQL(sql,new Object[]{“C语言程序设计”,historyimg});

db.execSQL(sql,new Object[]{“算法第四版”,historyimg});

db.execSQL(sql,new Object[]{“Android实战手册”,historyimg});

db.execSQL(sql,new Object[]{“Java程序与设计”,historyimg});

db.execSQL(sql,new Object[]{“数据结构与算法”,historyimg});

db.close();

}

/**

  • 作用:初始化搜索框

*/

private void init() {

// 1. 初始化UI组件

initView();

// 2. 实例化数据库对象

helper = new DBSqliteOpenHelper(context);

// 3. 第1次进入时查询所有的历史搜索记录

queryData(“”);

/**

  • "清空搜索历史"按钮

*/

textView_Clear.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// 清空数据库

deleteData();

// 模糊搜索空字符 = 显示当前所有的搜索历史(此时是没有搜索记录的)

queryData(“”);

}

});

/**

  • 监听输入键盘更换后的搜索按键

  • 调用时刻:点击键盘上的搜索键时

*/

editTextSearch.setOnKeyListener(new View.OnKeyListener() {

public boolean onKey(View v, int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {

// 1. 点击搜索按键后,根据输入的搜索字段进行查询

if (!(sCallBack == null)) {

sCallBack.SearchAction(editTextSearch.getText().toString());

}

Toast.makeText(context, “你搜索的是” + editTextSearch.getText(), Toast.LENGTH_SHORT).show();

// 2. 点击搜索键后,对该搜索字段在数据库是否存在进行检查(查询)->> 关注1

boolean hasData = hasData(editTextSearch.getText().toString().trim());

// 3. 若存在,则不保存;若不存在,则将该搜索字段保存(插入)到数据库,并作为历史搜索记录

if (!hasData) {

//获取搜索栏中的文字并去除两侧的符号,作为records的name属性传入insertData方法

insertData(editTextSearch.getText().toString().trim());

queryData(“”);

}

}

return false;

}

});

/**

  • 搜索框的文本变化监听

*/

editTextSearch.addTextChangedListener(new TextWatcher() {

private Editable s;

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

// 每次输入后,模糊查询数据库 & 显示

// 注:若搜索框为空,则模糊搜索空字符 = 显示所有的搜索历史

String tempName = editTextSearch.getText().toString();

queryData(tempName); // ->>关注1

}

});

/**

  • 搜索记录列表(ListView)监听

  • 即当用户点击搜索历史里的字段后,会直接将结果当作搜索字段进行搜索

*/

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

// 获取用户点击列表里的文字,并自动填充到搜索框内

TextView textView = (TextView) view.findViewById(R.id.ItemTitle);

String name = textView.getText().toString();

editTextSearch.setText(name);

Toast.makeText(context, name, Toast.LENGTH_SHORT).show();

}

});

/**

  • 点击返回按键后的事件

*/

searchBack.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (!(bCallBack == null)) {

bCallBack.BackAction();

}

//根据输入的内容模糊查询item,并跳转到另一个界面

Toast.makeText(context, “返回到上一页”, Toast.LENGTH_SHORT).show();

}

});

}

/**

  • 绑定搜索框xml视图

*/

private void initView() {

// 1. 绑定R.layout.search_layout作为搜索框的xml文件

LayoutInflater.from(context).inflate(R.layout.search_layout, this);

// 2. 绑定搜索框EditText

editTextSearch = (EditText) findViewById(R.id.et_search);

editTextSearch.setTextSize(textSizeSearch);

editTextSearch.setTextColor(textColorSearch);

editTextSearch.setHint(textHintSearch);

// 3. 搜索框背景颜色

search_block = (LinearLayout) findViewById(R.id.search_block);

LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) search_block.getLayoutParams();

params.height = searchBlockHeight;

search_block.setBackgroundColor(searchBlockColor);

search_block.setLayoutParams(params);

// 4. 历史搜索记录 = ListView显示

listView = (SearchListView) findViewById(R.id.listView);

// 5. 删除历史搜索记录 按钮

textView_Clear = (TextView) findViewById(R.id.tv_clear);

textView_Clear.setVisibility(INVISIBLE);

// 6. 返回按键

searchBack = (ImageView) findViewById(R.id.search_back);

}

/**

  • 模糊查询数据 & 显示到ListView列表上

*/

private void queryData(String tempName) {

// 1. 模糊搜索

Cursor cursor = helper.getReadableDatabase().rawQuery(

“select id as _id,name,photo_id,deletebtn from records where name like '%” + tempName + "%’ order by id desc ", null);

// 2. 创建adapter适配器对象 & 装入模糊搜索的结果

String[] from = new String[]{“name”, “photo_id”};

int[] to = new int[]{R.id.ItemTitle, R.id.ItemImage};

adapter = new SimpleCursorAdapter(context, R.layout.item, cursor, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

// 3. 设置适配器

listView.setAdapter(adapter);

adapter.notifyDataSetChanged();

System.out.println(cursor.getCount());

// 当输入框为空 & 数据库中有搜索记录时,显示 "删除搜索记录"按钮

if (tempName.equals(“”) && cursor.getCount() != 0) {

textView_Clear.setVisibility(VISIBLE);

} else {

textView_Clear.setVisibility(INVISIBLE);

}

}

/**

  • 清空数据库

*/

private void deleteData() {

db = helper.getWritableDatabase();

db.execSQL(“delete from records”);

db.close();

textView_Clear.setVisibility(INVISIBLE);

}

/**

  • 检查数据库中是否已经有该搜索记录

*/

private boolean hasData(String tempName) {

// 从数据库中Record表里找到name=tempName的id

Cursor cursor = helper.getReadableDatabase().rawQuery(

“select id as _id,name,photo_id from records where name =?”, new String[]{tempName});

// 判断是否有下一项数据

return cursor.moveToNext();

}

/**

  • 插入数据到数据库,即写入搜索字段到历史搜索记录

*/

private void insertData(String tempName) {

db = helper.getWritableDatabase();

db.execSQL(“insert into records(name,photo_id) values(?,?)”,new Object[]{tempName,historyimg});

db.close();

}

}

SimpleCursorAdapter

在这里插入图片描述

在这里插入图片描述

我们可以看到SimpleCursorAdapter继承于灵活可拓展的BaseAdapter的子类CursorAdapter;

最后的最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的

最后,互联网不存在所谓的寒冬,只是你没有努力罢了!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

}

}

SimpleCursorAdapter

在这里插入图片描述

在这里插入图片描述

我们可以看到SimpleCursorAdapter继承于灵活可拓展的BaseAdapter的子类CursorAdapter;

最后的最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的

[外链图片转存中…(img-Xm5u582V-1715015964655)]

最后,互联网不存在所谓的寒冬,只是你没有努力罢了!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值