Android 自定义弹窗 附带搜索过滤功能

简介: 前两天要求在项目中添加个小功能,今天正好有时间随手写了一个小demo,过程分享给大家。以后如果有此类需求可直接移植使用。

项目场景:

前两天要求在项目中添加个小功能,今天正好有时间随手写了一个小demo,过程分享给大家。以后如果有此类需求可直接移植使用。

需求是因为在下拉列表中选择一个项作为数据显示在界面上,但是所有的选项很多,下翻找很麻烦所有需要用个搜索框解决一下这个问题,下面是Demo的效果,可以先看一下。Demo做的比较简单,但是扩展性很大,需要的小伙伴可以自行改造使用,源码放在了文章的最后。

cac26880ec8441c79f512af0b487e2e0.gif



问题描述

开发前有个问题就是想用现成已有的东西放进去直接就能用了,也没有做自定义列表的东西,后面发现ListView的过滤功能不是很友好,它的过滤方式智能对数据的第一个字符进行过滤,如果是中间出现的字符它就会过滤不出来,所以又重写了适配器并且重写了它的过滤方法,最后满足了功能要求。


public Cursor swapCursor(Cursor newCursor) {
        if (newCursor == mCursor) {
            return null;
        }
        Cursor oldCursor = mCursor;
        if (oldCursor != null) {
            if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
            if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
        }
        mCursor = newCursor;
        if (newCursor != null) {
            if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
            if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
            mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
            mDataValid = true;
            // notify the observers about the new cursor
            notifyDataSetChanged();
        } else {
            mRowIDColumn = -1;
            mDataValid = false;
            // notify the observers about the lack of a data set
            notifyDataSetInvalidated();
        }
        return oldCursor;
    }

源码里面的内容就是只能对列表中数据的第一个字进行过滤,这样并不能完全起到过滤的作用,下面看一下解决方式。


解决方案:

1、先创建要自定义的内容,弹窗自定义内容dialog_searchview.xml、列表自定义内容fragment_recomend_item.xml(列表自定义也可以放其他东西,如图片等)。


dialog_searchview.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">
    <androidx.appcompat.widget.SearchView
        android:id="@+id/sv_search"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        ></androidx.appcompat.widget.SearchView>
    <ListView
        android:id="@+id/lv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>

fragment_recomend_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="15dp"
        android:textSize="15sp"
        android:text="123456"
        android:textColor="@color/black"
        android:gravity="center_vertical"></TextView>
</LinearLayout>

2、创建数据Been,并且绑定到适配器。

Recomend.java

package com.example.testdemosearchview;
/**
 * Create by HHCH on 2023/5/23
 */
public class Recomend {
    private String title;
    public Recomend(String title) {
        this.title = title;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

RecomendAdapter.java

public class RecomendAdapter extends BaseAdapter implements Filterable {
    Context context;
    List<Recomend> data; //过滤数据
    List<Recomend> backData;//用来备份原始数据
    MyFilter mFilter ;
    public RecomendAdapter(Context context, List<Recomend> data) {
        this.context = context;
        this.data = data;
        backData = data;
    }
    @Override
    public int getCount() {
        return data.size();
    }
    //获取当前数据
    @Override
    public Object getItem(int i) {
        return data.get(i).getTitle();
    }
    @Override
    public long getItemId(int i) {
        return 0;
    }
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view ==null){
            view = LayoutInflater.from(context).inflate(R.layout.fragment_recomend_item,null);
        }
        TextView tv_title = view.findViewById(R.id.tv_title);
        tv_title.setText(data.get(i).getTitle());
        return view;
    }
    //执行setFilterText()方法时  自动执行
    @Override
    public Filter getFilter() {
        if (mFilter ==null){
            mFilter = new MyFilter();
        }
        return mFilter;
    }
    //我们需要定义一个过滤器的类来定义过滤规则
    class MyFilter extends Filter{
        //我们在performFiltering(CharSequence charSequence)这个方法中定义过滤规则
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            FilterResults result = new FilterResults();
            List<Recomend> list ;
            if (TextUtils.isEmpty(charSequence)){//当过滤的关键字为空的时候,我们则显示所有的数据
                list  = backData;
            }else {//否则把符合条件的数据对象添加到集合中
                list = new ArrayList<>();
                for (Recomend recomend:backData){
                    if (recomend.getTitle().contains(charSequence)){
                        Log.d("","performFiltering:"+recomend.toString());
                        list.add(recomend);
                    }
                }
            }
            result.values = list; //将得到的集合保存到FilterResults的value变量中
            result.count = list.size();//将集合的大小保存到FilterResults的count变量中
            return result;
        }
        //在publishResults方法中告诉适配器更新界面
        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            data = (List<Recomend>)filterResults.values;
            Log.d("","publishResults:"+filterResults.count);
            if (filterResults.count>0){
                notifyDataSetChanged();//通知数据发生了改变
                Log.d("","publishResults:notifyDataSetChanged");
            }else {
                notifyDataSetInvalidated();//通知数据失效
                Log.d("","publishResults:notifyDataSetInvalidated");
            }
        }
    }
}

代码中有注释,大家可以看注释理解。

3、使用弹窗显示内容。

MainActivity.java


public class MainActivity extends AppCompatActivity {
    private String[] dic = new String[]{"框架平房", "框架楼房", "砖混平房", "砖混楼房", "砖混厦房", "砖混安架房", "砖混起脊房", "砖木房", "砖木厦房",
            "砖木安架房", "土木房", "土木厦房", "土木安架房", "混合房", "混合安架房", "土窑洞", "石窑洞", "砖窑洞", "混合窑洞",
            "砖墙彩钢瓦房", "彩钢瓦活动板房", "砖(石)木简易房", "土木简易房", "其他简易房"};
    private List<Recomend> list = new ArrayList<>();
    private RecomendAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView() {
        Button btn_open = findViewById(R.id.bt_open);
        //填充数据源
        for (int i = 0; i < dic.length;i++){
            list.add(new Recomend(dic[i]));
        }
        btn_open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                View customView  = View.inflate(MainActivity.this,R.layout.dialog_searchview,null);
                SearchView searchView = customView.findViewById(R.id.sv_search);
                ListView listView = customView.findViewById(R.id.lv_list);
                listView.setTextFilterEnabled(true);
                searchView.setIconifiedByDefault(false);
                //        设置该SearchView显示搜索图标
                searchView.setSubmitButtonEnabled(true);
                //        设置该SearchView内默认显示的搜索文字
                searchView.setQueryHint("查找");
                builder.setView(customView);
                adapter = new RecomendAdapter(MainActivity.this,list);
                listView.setAdapter(adapter);
                //searchView输入监听
                searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                    @Override
                    public boolean onQueryTextSubmit(String query) {
                        return false;
                    }
                    //输入内容发送改变时执行下面的方法
                    @Override
                    public boolean onQueryTextChange(String newText) {
                        if (TextUtils.isEmpty(newText)){
                            //清除ListView的过滤
                            listView.clearTextFilter();
                        }else {
                            //使用用户输入的内容对ListView的列表项进行过滤
                            listView.setFilterText(newText);
                        }
                        return true;
                    }
                });
                AlertDialog dialog = builder.create();
                listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                        dialog.dismiss();
                        Toast.makeText(MainActivity.this,adapter.getItem(i).toString(),Toast.LENGTH_SHORT).show();
                    }
                });
                dialog.show();
                dialog.setCanceledOnTouchOutside(true);// dialog弹出后,点击界面其他部分dialog消失
            }
        });
    }
}

71

整体的流程就这样,需要注意的是在使用SearchView的时候,要将数据过滤写在输入内容发生变化的方法onQueryTextChange()下。


相关文章
|
10月前
|
数据库 Android开发
Android使用EditText+Listview实现搜索效果(使用room模糊查询)
本文介绍如何在Android中使用EditText与ListView实现搜索功能,并结合Room数据库完成模糊查询。主要内容包括:Room的模糊查询语句(使用`||`代替`+`号)、布局美化(如去除ListView分割线和EditText下划线)、EditText回车事件监听,以及查询逻辑代码示例。此外,还提供了相关扩展文章链接,帮助读者深入了解ListView优化、动态搜索及Room基础操作。
643 65
|
10月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
659 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
10月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
200 0
|
10月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
440 65
Android自定义view之网易云推荐歌单界面
|
10月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
820 84
|
10月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
295 3
|
10月前
|
Android开发 开发者
Android动态搜索的简单实现
本文介绍了在Android中实现动态搜索功能的方法,重点讲解了通过`SearchView`与`ListView`结合的方式。文章首先简要提及了`addTextChangedListener`的使用场景,随后详细说明了`SearchView`的相关方法,如`setIconified()`、`setOnQueryTextListener()`等,并通过一个示例展示了如何根据用户输入动态过滤`ListView`中的数据。案例中使用了一个字符串数组作为数据源,通过监听输入变化实现搜索功能。最后提供了完整的源码和布局文件,便于开发者参考和实践。
215 3
|
10月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
182 0
Android自定义view之围棋动画(化繁为简)
|
XML 缓存 Android开发
搜索----Android Demo
       在前面的博客中,小编简单的介绍了,点击发现按钮,自动加载热门的相关数据,成长的脚步从不停歇,完成了发现的功能,今天我们来简单看一下如何在搜索栏中输入关键字,搜索出我们所需要的信息,今天这篇博文小编就简单的介绍一下,如何输入关键字,搜索出相应内容的故事。
1022 0
|
5月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
902 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡

热门文章

最新文章