Android实现recyclerview城市字母索引列表

转拼音的依赖

implementation 'com.github.SilenceDut:jpinyin:v1.0'

FastIndexView实现列表右侧字母索引列表

public class FastIndexView extends View {

    private static final String INDEX_NAME = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private OnLetterUpdateListener listener;
    private Paint mPaint;
    private float cellHeight, viewWidth;
    private int touchIndex = -1, selectedColor;

    public FastIndexView(Context context) {
        this(context, null);
    }

    public FastIndexView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FastIndexView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setTextSize(AppUtils.dp2px(14));
        mPaint.setAntiAlias(true);
        //获取文字被选中的颜色
//        selectedColor = ContextCompat.getColor(context, );
        selectedColor = Color.parseColor("#999DA1");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < INDEX_NAME.length(); i++) {
            String text = INDEX_NAME.substring(i, i + 1);
            //计算绘制字符的X方向起点
            int x = (int) (viewWidth / 2.0f - mPaint.measureText(text) / 2.0f);
            Rect bounds = new Rect();
            mPaint.getTextBounds(text, 0, text.length(), bounds);
            int textHeight = bounds.height();
            //计算绘制字符的Y方向起点
            int y = (int) (cellHeight / 2.0f + textHeight / 2.0f + i
                    * cellHeight);
            mPaint.setColor(/*touchIndex == i ? Color.WHITE : */selectedColor);
            canvas.drawText(text, x, y, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //计算当前触摸的字符索引
                index = (int) (event.getY() / cellHeight);
                if (index >= 0 && index < INDEX_NAME.length()) {
                    if (listener != null) {
                        listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
                    }
                    touchIndex = index;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //计算当前触摸的字符索引
                index = (int) (event.getY() / cellHeight);
                if (index >= 0 && index < INDEX_NAME.length()) {
                    if (index != touchIndex) {
                        if (listener != null) {
                            listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
                        }
                        touchIndex = index;
                    }
                }
                break;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //得到当前控件的宽度
        viewWidth = getMeasuredWidth();
        int mHeight = getMeasuredHeight();
        //获取单个字符能够拥有的高度
        cellHeight = mHeight * 1.0f / INDEX_NAME.length();
    }

    public interface OnLetterUpdateListener {
        void onLetterUpdate(String letter);
    }

    public void setListener(OnLetterUpdateListener listener) {
        this.listener = listener;
    }

}
public class AppUtils {

    private static float density;

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dp2px(float dpValue) {
        if (density == 0)
            density = Resources.getSystem().getDisplayMetrics().density;
        return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
    }

}

CityAdapter

public class CityAdapter extends RecyclerView.Adapter<CityAdapter.BaseViewHolder> {

    private List<CityInfoModel> mDatas;
    private Context mContext;

    public CityAdapter(Context context, List<CityInfoModel> data) {
        this.mDatas = data;
        this.mContext = context;
    }

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //创建不同的 ViewHolder
        View view = null;
        //根据viewtype来创建条目
        view = LayoutInflater.from(mContext).inflate(R.layout.item_layout_normal, parent, false);
        return new NormalHolder(view);

    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, final int position) {
        CityInfoModel cityInfoModel = mDatas.get(position);
        NormalHolder realHolder = (NormalHolder) holder;
        realHolder.tvContent.setText(cityInfoModel.getCityName());
        realHolder.tvContent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    static class BaseViewHolder extends RecyclerView.ViewHolder {
        BaseViewHolder(View itemView) {
            super(itemView);
        }
    }

    @Override
    public int getItemCount() {
        if (mDatas != null) {
            return mDatas.size();
        }
        return 0;
    }

    private class NormalHolder extends BaseViewHolder {
        TextView tvContent;

        public NormalHolder(View itemView) {
            super(itemView);
            tvContent = itemView.findViewById(R.id.tv_city);
        }
    }

}

MainActivity

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.recy_list)
    RecyclerView recyList;
    @BindView(R.id.fastIndexView)
    FastIndexView fastIndexView;
    //主要用于展示数据的list
    private List<CityInfoModel> list;
    //第一次加载之后缓存的数据
    private List<CityInfoModel> cacheList;

    //页面recyclerview的适配器
    private CityAdapter mainAdapter;
    //布局管理器
    private LinearLayoutManager layoutManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        initAdapter();

        initListener();
    }

    private void initAdapter() {
        list = new ArrayList<>();
        cacheList = new ArrayList<>();
        list.add(new CityInfoModel("安徽省"));
        list.add(new CityInfoModel("北京市"));
        list.add(new CityInfoModel("上海市"));
        list.add(new CityInfoModel("广州市"));
        list.add(new CityInfoModel("深圳市"));
        list.add(new CityInfoModel("天津市"));
        list.add(new CityInfoModel("南京市"));
        list.add(new CityInfoModel("杭州市"));
        list.add(new CityInfoModel("重庆市"));
        list.add(new CityInfoModel("成都市"));
        list.add(new CityInfoModel("石家庄市"));
        list.add(new CityInfoModel("自贡市"));
        list.add(new CityInfoModel("攀枝花市"));
        list.add(new CityInfoModel("泸州市"));
        list.add(new CityInfoModel("德阳市"));
        list.add(new CityInfoModel("绵阳市"));
        list.add(new CityInfoModel("广元市"));
        list.add(new CityInfoModel("遂宁市"));
        List<CityInfoModel> cityInfoModels = bindData(list);
        layoutManager = new LinearLayoutManager(this);
        recyList.setLayoutManager(layoutManager);
        recyList.addItemDecoration(new CustomItemDecoration(this, new CustomItemDecoration.TitleDecorationCallback() {
            @Override
            public String getGroupId(int position) {
                //这个是用来比较是否是同一组数据的
                return list.get(position).getSortId();
            }

            @Override
            public String getGroupName(int position) {
                CityInfoModel cityInfoModel = list.get(position);
                //拼音都是小写的
                return cityInfoModel.getSortId().toUpperCase();
            }
        }));
        mainAdapter = new CityAdapter(this, cityInfoModels);
        recyList.setAdapter(mainAdapter);
    }

    private void initListener() {
        fastIndexView.setListener(new FastIndexView.OnLetterUpdateListener() {
            @Override
            public void onLetterUpdate(String letter) {
                moveToLetterPosition(letter);
            }
        });
    }

    //滚动recyclerview
    private void moveToLetterPosition(String letter) {
        //这里主要是为了跳转到最顶端
        if ("#".equals(letter)) {
            letter = "*";
        }
        for (int i = 0; i < list.size(); i++) {
            CityInfoModel cityInfoModel = list.get(i);
            if (cityInfoModel.getSortId().toUpperCase().equals(letter)) {
                layoutManager.scrollToPositionWithOffset(i, 0);
                return;
            }
        }
    }

    /**
     * 给View绑定数据
     *
     * @param allCity 所有城市列表
     */
    public List<CityInfoModel> bindData(List<CityInfoModel> allCity) {
        if (allCity != null) {
            for (CityInfoModel cityModel : allCity) {
                try {
                    String pingYin = PinyinHelper.convertToPinyinString(cityModel.getCityName(), " ", PinyinFormat.WITHOUT_TONE);
                    cacheList.add(new CityInfoModel(cityModel.getCityName(), pingYin.substring(0, 1), pingYin));
                } catch (PinyinException e) {
                    e.printStackTrace();
                }
            }
            //排序
            Collections.sort(cacheList, new Comparator<CityInfoModel>() {
                @Override
                public int compare(CityInfoModel o1, CityInfoModel o2) {
                    return o1.getSortName().compareTo(o2.getSortName());
                }
            });
            this.list.clear();
            this.list.addAll(cacheList);
        }
        return list;
    }

}

CityInfoModel

public class CityInfoModel {

    private String cityName;//用于显示的城市的名字
    private String sortId;//用于排序的id 在这里是城市拼音的首字母
    private String sortName;//用于排序的全拼音 这个是用于后面的排序以及搜索

    public CityInfoModel(String cityName) {
        this.cityName = cityName;
    }

    public CityInfoModel(String cityName, String sortId, String sortName) {
        this.cityName = cityName;
        this.sortId = sortId;
        this.sortName = sortName;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public String getSortId() {
        return sortId;
    }

    public void setSortId(String sortId) {
        this.sortId = sortId;
    }

    public String getSortName() {
        return sortName;
    }

    public void setSortName(String sortName) {
        this.sortName = sortName;
    }
}

activity_main

<?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:orientation="horizontal">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recy_list"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <com.simin.indexrecyclerview.FastIndexView
        android:id="@+id/fastIndexView"
        android:layout_width="25dp"
        android:layout_height="match_parent"
        app:layout_constraintHeight_percent="0.7" />
</LinearLayout>

到此这篇关于Android实现recyclerview城市字母索引列表的文章就介绍到这了,更多相关Android recyclerview字母索引内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android实现的RecyclerView适配器

    这个适配器我珍藏已久(近两年), 不断看到别人发适配器相关的文章, 但我总觉得没我的好用, 所以今日拿出来分享(宣传)一下, 欢迎各位指正不足. 源码地址: GitHub 功能 无需继承 Adapter, 无需判断 item 类型. 支持页头和页脚. 支持自动展示空数据界面. 通过 Kotlin 的 lambda 大量缩减代码. 支持全局 Item 类型 支持 diff 刷新 使用 添加依赖 implementation "com.dengzii.adapter:$latestVersion&q

  • android RecyclerView的一些优化点介绍

    目录 1.RecycledPool的重用 2.setHasFixedSize(boolean)的使用 3.setHasStableIds(boolean)的使用 4.ViewCacheExtension的使用 5.预加载 6.更新列表的方式 item局部更新 整体列表更新 总结 1.RecycledPool的重用 场景以及使用: 多个RecyclerView出现,并且他们的item布局结构一致,这时候可以进行重用. 在进行RecyclerView的初始化设置时候进行RecycledPool的设置

  • Android列表RecyclerView排列布局

    本文实例为大家分享了Android列表RecyclerView排列布局的具体代码,供大家参考,具体内容如下 效果图: 1.要添加相关的依赖 implementation 'androidx.recyclerview:recyclerview:1.1.0' 2.然后布局文件中准备容器 这个标签是显示目标容器对象的,其他需求可自定义 <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_list" android

  • Android实现recyclerview城市字母索引列表

    转拼音的依赖 implementation 'com.github.SilenceDut:jpinyin:v1.0' FastIndexView实现列表右侧字母索引列表 public class FastIndexView extends View { private static final String INDEX_NAME = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private OnLetterUpdateListener listener; priva

  • Android手机联系人带字母索引的快速查找

    喜欢另辟蹊径的我,在这里废话不多说了,直接上代码和图片了. 效果图如下: 第一步:MainActivity的代码如下: package net.loonggg.test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.TreeSet; import android.os.Bundle; import and

  • Android中RecyclerView实现多级折叠列表效果(TreeRecyclerView)

    前言 首先不得不吐槽一下产品,尼玛为啥要搞这样的功能....搞个两级的不就好了嘛...自带控件,多好.三级,四级,听说还有六级的....这样丧心病狂的设计,后台也不好给数据吧. 先看看效果: 两级的效果: 三级的效果: 全部展开的效果(我只写了五级) 说说为什么写这货吧: 公司产品提出三级这个需求后,我就在网上找啊找. 找的第一个,发现实现其实是ExpandListview嵌套. 找的第二个,ExpandRecyclview,然后就用呗,发现三级展开很卡,看源码, 发现是RecyclerView

  • Android中RecyclerView实现多级折叠列表效果(二)

    前言 在本文开始之前请大家先看一下这篇文章:http://www.jb51.net/article/113510.htm 上面的这篇文章是之前写的,里面发现有很多不好用地方,也学到些新姿势,改动了许多地方.下面来看看详细的介绍: 要点: 1.可以通过后台控制Item的展示. 2.TreeRecyclerAdapter,可以展开,折叠.多级展示 3.adapter可以使用装饰者模式进行扩展.支持EmptyAdapter.可以添加headview和footview 4.item的样式可以编写文档,t

  • Android基于RecyclerView实现高亮搜索列表

    话不多说先看今天的实现的效果: 相信这种效果很多项目都会用到,今天就讲讲利用RecycleView来实现他,博主把此篇文章定位初级篇,可能因为这确实很简单,所以我要更要讲的详细一点让新手也可以能看的懂. 饭要开始做了,我们要准备哪些食材呢. 1.一个RecyclerView或是listview或是其他可以显示多item的控件(主要的干货) 2.搞清楚EditText的实时监听 3.让一个textview出现不同的颜色 4.如何穿过Adpter找出textview中key值(也就是高亮字符串) 当

  • Android ItemDecoration 实现分组索引列表的示例代码

    本文介绍了Android ItemDecoration 实现分组索引列表的示例代码,分享给大家.具体如下: 先来看看效果: 我们要实现的效果主要涉及三个部分: 分组 GroupHeader 分割线 SideBar 前两个部分涉及到一个ItemDecoration类,也是我们接下来的重点,该类是RecyclerView的一个抽象静态内部类,主要作用就是给RecyclerView的ItemView绘制额外的装饰效果,例如给RecyclerView添加分割线. 使用ItemDecoration时需要继

  • Android自定义View实现通讯录字母索引(仿微信通讯录)

    一.效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,QQ,还有美团选择地区等等.这里我截了一张美团选择城市的图片来看看: 我们今天就来实现图片中右侧模块的索引功能,包括触摸显示以选中的索引字母.这里我的UI界面主要是参照微信的界面来实现,所以各位也可以对照微信来看看效果,什么都不说了,只有效果图最具有说服力! 二.分析: 我们看到这样的效果我们心理都回去琢磨,他是如何实现的: 首先,它肯定是通过自定义 View 来实现的,因为 Android 没有提供类似这样的控件

  • Android 实现带字母索引的侧边栏功能

    之前已经用自定义View做出如下这样一个效果了 这两天需要重新拿来使用,发现效果虽然做出来了,不过思路不太对,就重新参考写了一个,用法也更为简单了 首要的自然是需要继承View绘制出侧边栏,并向外提供一个监听字母索引变化的方法 /** * 作者:叶应是叶 * 时间:2017/8/20 11:38 * 描述: */ public class LetterIndexView extends View { public interface OnTouchingLetterChangedListener

  • Android使用RecyclerView实现自定义列表、点击事件以及下拉刷新

    Android使用RecyclerView 1. 什么是RecyclerView RecyclerView 是 Android-support-v7-21 版本中新增的一个 Widgets,官方对于它的介绍则是:RecyclerView 是 ListView 的升级版本,更加先进和灵活. 简单来说就是:RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式.它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持. 2.

  • android仿微信通讯录搜索示例(匹配拼音,字母,索引位置)

    前言: 仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置 一:先看效果图 字母索引 搜索匹配 二:功能分析 1:汉字转拼音 通讯录汉字转拼音(首个字符当考虑姓氏多音字), 现在转换拼音常见的有pinyin4j和tinypinyin, pinyin4j的功能强大,包含声调多音字,tinypinyin执行快占用内存少, 如果只是简单匹配通讯录,建议使用tinypinyin,用法也很简单这里不详细介绍 拼音类 public class CNPinyin <T extends

随机推荐