欢迎光临,了解微信小程序开发,就上易用通!

微信小程序开发之带搜索记录的搜索框

发布:2017-12-29 18:14浏览: 来源:网络 作者:tianshu

https://blog.csdn.net/carson_ho/article/details/53366570

 

 

前言

  • 像下图的搜索功能在Android开发中非常常见

 

搜索功能

  • 今天我将手把手教大家如何实现具备历史搜索记录的搜索框

目录

目录


1. 使用场景

在敲下代码前,理解用户的功能使用场景是非常重要的,这样有助于我们更好地去进行功能的实现,使用场景如下:

  • 用户需要进行某类事物的搜索(通过文字输入进行精确搜索)
  • 在搜索框输入时,通过显示搜索历史从而降低用户二次搜索的成本

简单来说,就是输入过字段会保存,当用户再次搜索该字段时,能快速帮助用户输入


2. 功能业务流程

搜索功能场景


3. 明确功能点

  • 功能1:关键字搜索
  • 功能2:实时显示历史搜索记录
  • 功能3:历史搜索记录保存
  • 功能4:将软键盘上的”回车按钮“改为”搜索按钮“

4. 涉及到的知识点

知识点

4.1 SQLite数据库的增删改查操作

  • 在数据库建立一个叫records的表用于存储搜索历史记录 
     里面只有一列name来存储历史记录
        db.execSQL("create table records(id integer primary key autoincrement,name varchar(200))");
  • 通过插入和删除操作数据库里面的数据
  • 通过查询操作来显示数据库里面的数据到ListView上 

    已搜索的关键字再次搜索不重复添加到数据库

注:对于SQLlite数据库的操作详情请看我写的文章:Android:SQLlite数据库操作最详细解析

4.2 ListView和ScrollView的嵌套冲突

  • 问题:ListView和ScrollView一起使用会有冲突,导致ListView显示不全
  • 解决方案:本人采用继承ListView并重写它的onMeasure()方法来解决冲突。

    1. 至于两者的滑动冲突则暂时不需要处理(默认拉动ScrollView),这样用户就会感觉里面的搜索历史项和清空搜索记录项是在ListView里面一样,符合设计。
    2. 更多解决方法请看:ListView和ScrollView的嵌套冲突解决方案
  • 具体代码如下:

//解决ListView和ScrollView的冲突
public class Search_Listview extends ListView {
    public Search_Listview(Context context) {
        super(context);
    }

    //通过复写其onMeasure方法、达到对ScrollView适配的效果
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

Search_View.java

  • 作用:用于封装搜索框功能的所有操作(涵盖历史搜索记录的插入、删除、查询和显示)
  • 具体代码如下:
package scut.carson_ho.search_layout;

import android.content.Context;
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.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Created by Carson_Ho on 16/11/15.
 */
public class Search_View extends LinearLayout {

    private Context context;

    /*UI组件*/
    private TextView tv_clear;
    private EditText et_search;
    private TextView tv_tip;
    private ImageView iv_search;

    /*列表及其适配器*/
    private Search_Listview listView;
    private BaseAdapter adapter;

    /*数据库变量*/
    private RecordSQLiteOpenHelper helper ;
    private SQLiteDatabase db;


    /*三个构造函数*/
    //在构造函数里直接对搜索框进行初始化 - init()
    public Search_View(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public Search_View(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public Search_View(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }


    /*初始化搜索框*/
    private void init(){

        //初始化UI组件
        initView();


        //实例化数据库SQLiteOpenHelper子类对象
        helper = new RecordSQLiteOpenHelper(context);

        // 第一次进入时查询所有的历史记录
        queryData("");

        //"清空搜索历史"按钮
        tv_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //清空数据库
                deleteData();
                queryData("");
            }
        });

        //搜索框的文本变化实时监听
        et_search.addTextChangedListener(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 (s.toString().trim().length() == 0) {
                    //若搜索框为空,则模糊搜索空字符,即显示所有的搜索历史
                    tv_tip.setText("搜索历史");
                } else {
                    tv_tip.setText("搜索结果");
                }

                //每次输入后都查询数据库并显示
                //根据输入的值去模糊查询数据库中有没有数据
                String tempName = et_search.getText().toString();
                queryData(tempName);

            }
        });


        // 搜索框的键盘搜索键
        // 点击回调
        et_search.setOnKeyListener(new View.OnKeyListener() {// 输入完后按键盘上的搜索键


            // 修改回车键功能
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
                    // 隐藏键盘,这里getCurrentFocus()需要传入Activity对象,如果实际不需要的话就不用隐藏键盘了,免得传入Activity对象,这里就先不实现了
//                    ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
//                            getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

                    // 按完搜索键后将当前查询的关键字保存起来,如果该关键字已经存在就不执行保存
                    boolean hasData = hasData(et_search.getText().toString().trim());
                    if (!hasData) {
                        insertData(et_search.getText().toString().trim());

                        queryData("");
                    }
                    //根据输入的内容模糊查询商品,并跳转到另一个界面,这个需要根据需求实现
                    Toast.makeText(context, "点击搜索", Toast.LENGTH_SHORT).show();

                }
                return false;
            }
        });



        //列表监听
        //即当用户点击搜索历史里的字段后,会直接将结果当作搜索字段进行搜索
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                //获取到用户点击列表里的文字,并自动填充到搜索框内
                TextView textView = (TextView) view.findViewById(android.R.id.text1);
                String name = textView.getText().toString();
                et_search.setText(name);
                Toast.makeText(context, name, Toast.LENGTH_SHORT).show();

            }
        });


        //点击搜索按钮后的事件
        iv_search.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean hasData = hasData(et_search.getText().toString().trim());
                if (!hasData) {
                    insertData(et_search.getText().toString().trim());

                    //搜索后显示数据库里所有搜索历史是为了测试
                    queryData("");
                }
                //根据输入的内容模糊查询商品,并跳转到另一个界面,这个根据需求实现
                Toast.makeText(context, "clicked!", Toast.LENGTH_SHORT).show();
            }
        });




    }





    /**
     * 封装的函数
     */

    /*初始化组件*/
    private void initView(){
        LayoutInflater.from(context).inflate(R.layout.search_layout,this);
        et_search = (EditText) findViewById(R.id.et_search);
        tv_clear = (TextView) findViewById(R.id.tv_clear);
        tv_tip = (TextView) findViewById(R.id.tv_tip);
        listView = (Search_Listview) findViewById(R.id.listView);
        iv_search = (ImageView) findViewById(R.id.iv_search);
    }

    /*插入数据*/
    private void insertData(String tempName) {
        db = helper.getWritableDatabase();
        db.execSQL("insert into records(name) values('" + tempName + "')");
        db.close();
    }

    /*模糊查询数据 并显示在ListView列表上*/
    private void queryData(String tempName) {

        //模糊搜索
        Cursor cursor = helper.getReadableDatabase().rawQuery(
                "select id as _id,name from records where name like '%" + tempName + "%' order by id desc ", null);
        // 创建adapter适配器对象,装入模糊搜索的结果
        adapter = new SimpleCursorAdapter(context, android.R.layout.simple_list_item_1, cursor, new String[] { "name" },
                new int[] { android.R.id.text1 }, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        // 设置适配器
        listView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    }

    /*检查数据库中是否已经有该条记录*/
    private boolean hasData(String tempName) {
        //从Record这个表里找到name=tempName的id
        Cursor cursor = helper.getReadableDatabase().rawQuery(
                "select id as _id,name from records where name =?", new String[]{tempName});
        //判断是否有下一个
        return cursor.moveToNext();
    }

    /*清空数据*/
    private void deleteData() {
        db = helper.getWritableDatabase();
        db.execSQL("delete from records");
        db.close();
    }
}

search_layout.xml

  • 作用:搜索框的布局
  • 具体代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:background="#E54141"
        android:orientation="horizontal"
        android:paddingRight="16dp">

        <ImageView
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:layout_gravity="center_vertical"
            android:padding="10dp"
            android:src="@drawable/back" />

        <EditText
            android:id="@+id/et_search"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="264"
            android:background="@null"
            android:drawablePadding="8dp"
            android:gravity="start|center_vertical"
            android:hint="输入查询的关键字"
            android:imeOptions="actionSearch"
            android:singleLine="true"
            android:textColor="@android:color/white"
            android:textSize="16sp" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/search"
            android:layout_gravity="center_vertical"
            android:id="@+id/iv_search"/>

    </LinearLayout>


    <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">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingLeft="20dp"
                >

                <TextView
                    android:id="@+id/tv_tip"
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:gravity="left|center_vertical"
                    android:text="搜索历史" />

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:background="#EEEEEE"/>

                <scut.carson_ho.search_layout.Search_Listview
                    android:id="@+id/listView"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                </scut.carson_ho.search_layout.Search_Listview>


            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#EEEEEE"/>

            <TextView
                android:id="@+id/tv_clear"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#F6F6F6"
                android:gravity="center"
                android:text="清除搜索历史" />

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:layout_marginBottom="20dp"
                android:background="#EEEEEE"/>
        </LinearLayout>

    </ScrollView>
</LinearLayout>

5.3 测试结果

测试结果

5.4 Demo地址

Carson的Github地址:Search_Layout_Demo


6. 总结

  • 通过阅读本文,你已经全面了解Android中如何实现具备历史搜索记录的搜索框
  • 接下来会介绍继续介绍Android开发中的常用知识,有兴趣可以继续关注Carson_Ho的安卓开发笔记




免责声明:本站所有文章和图片均来自用户分享和网络收集,文章和图片版权归原作者及原出处所有,仅供学习与参考,请勿用于商业用途,如果损害了您的权利,请联系网站客服处理。