Android(安卓)按字母排序的通讯录
16lz
2021-12-04
Android 字母排序通讯录
效果图:
代码部门:
Activity
class ContactViewActivity: AppCompatActivity(){ private var mAdater: ContactSortAdapter? = null private var mDataList: MutableList? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_sort_recycler) initView() initData() } fun initView(){ ed_search?.addTextChangedListener(object : TextWatcher { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { if (TextUtils.isEmpty(s.toString().trim())){ contact_view?.initData(mDataList) mAdater?.initData(mDataList) }else{ mAdater?.initData(contact_view?.updateData(s.toString())) } } override fun beforeTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { } override fun afterTextChanged(arg0: Editable) { } }) } fun initData(){ val arrayData = arrayOf("a", "bd", "ced", "de", "as", "东皇太一","宫本武藏","王昭君","李元芳","刘禅","后裔","许爱明","无名","流海" ,"亚瑟","吕布", "秋雅", "夏洛", "公孙离", "张良", "孙尚香", "我", "你", "啊", "哈哈", "嘿" ,"无名","流海","亚瑟","吕布", "夏洛", "公孙离", "张良", "孙尚香","无名","流海","亚瑟","吕布", "刘备", "夏洛", "公孙离", "张良", "孙尚香" ,"无名","流海","亚瑟","吕布", "秋雅", "夏洛", "公孙离", "张良", "孙尚香","无名","流海","亚瑟","吕布", "秋雅", "夏洛", "公孙离", "张良", "孙尚香") var data = mutableListOf() for (i in arrayData){ data.add(i) } mAdater = ContactSortAdapter() RecyclerViewUtil.initNoDecoration(this,contact_view?.getRecycler(),mAdater) mDataList = contact_view?.sortData(data) contact_view?.initData(mDataList) mAdater?.initData(mDataList) }}
布局
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical" > <LinearLayout android:id="@+id/ll_top_search" android:layout_width="match_parent" android:layout_height="56dp" android:gravity="center" android:background="@color/color_0"> <EditText android:id="@+id/ed_search" android:layout_width="match_parent" android:layout_height="40dp" android:background="@drawable/radius_bg" android:drawableLeft="@mipmap/iv_search_normal" android:drawablePadding="4dp" android:paddingLeft="4dp" android:hint="请输入关键字" android:textSize="14dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"/> LinearLayout> <com.zs.various.view.ContactRecyclerView android:id="@+id/contact_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/ll_top_search"/>RelativeLayout>
Activity 页面部分整体是一个RecyclerView,上面是搜索的EditText,主要的逻辑都在自定义的控件里面处理,activity主要是获取数据,然后调用排序方法,把数据根据字母顺序重新排序,填充到adapter中。
class ContactSortAdapter : RecyclerView.Adapter<ContactSortAdapter.ContactHolder>() { var mData: MutableList<SortModel>? = null override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ContactHolder { var view = View.inflate(parent?.context, R.layout.adapter_sort,null) return ContactHolder(view) } override fun getItemCount(): Int { return if (mData == null) 0 else mData!!.size } fun initData(data: MutableList<SortModel>?){ this.mData = data notifyDataSetChanged() } override fun onBindViewHolder(holder: ContactHolder?, position: Int) { holder?.bindData(position) } inner class ContactHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ fun bindData(position: Int) = with(itemView) { var sortModel = mData!![position] name?.text = sortModel.name if (!compareSection(position)){ tv_letter?.visibility = View.VISIBLE tv_letter?.text = sortModel.letter line_view?.visibility = View.GONE }else{ tv_letter?.visibility = View.GONE line_view?.visibility = View.VISIBLE } } } fun compareSection(position: Int): Boolean { return if (position == 0) { false } else { val current = getSectionForPosition(position) val previous = getSectionForPosition(position - 1) current == previous } } // 获取当前位置的首字母(int表示ascii码) fun getSectionForPosition(position: Int): Int { return mData!![position].letter[0].toInt() } // 获取字母首次出现的位置 fun getPositionForSection(section: Int): Int { for (i in 0 until itemCount) { val s = mData!![i].letter val firstChar = s.toUpperCase()[0] if (firstChar.toInt() == section) { return i } } return -1 }}
每个条目都有显示字母的title,adapter中控制显示,主要的判断逻辑是,判断上一个数据中名字的首字母是否和本条目的首字母相同,不相同显示title,否则不显示。
自定义 ContactRecyclerView
布局
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/rl_container_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentTop="true"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@null"/> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" /> <TextView android:id="@+id/tv_letter_show" android:layout_width="80dp" android:layout_height="80dp" android:layout_centerInParent="true" android:background="@color/hint_color" android:gravity="center" android:textColor="@color/white" android:textSize="40dp" android:visibility="gone" /> <include layout="@layout/item_letter_layout"/> <com.zs.various.view.SideBarView android:id="@+id/view_sidebar" android:layout_width="30dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_marginBottom="20dp" android:layout_marginTop="20dp"> com.zs.various.view.SideBarView> RelativeLayout>RelativeLayout>
/** * 数据排序 */ fun sortData(data: MutableList): MutableList { val list = mutableListOf() for (i in data.indices) { val sm = SortModel() sm.name = data[i] val pinyin = mParser.getSelling(data[i]) val sortString = pinyin.substring(0, 1).toUpperCase() if (sortString.matches("[A-Z]".toRegex())) { sm.letter = sortString } else { sm.letter = "#" } list.add(sm) } Collections.sort(list, PinyinComparator()) return list }
把数据进行字母排序
init { LayoutInflater.from(context).inflate(R.layout.contact_list_layout, this) ll_top_title = findViewById(R.id.ll_top_title) tv_letter = findViewById(R.id.tv_letter) view_sidebar?.setLetterTouchListener(this) recycler_view?.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) { super.onScrollStateChanged(recyclerView, newState) mLetterHeight = ll_top_title?.height!! } override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) mLayoutManager = recyclerView?.layoutManager as LinearLayoutManager //找到列表下一个可见的View var view = mLayoutManager?.findViewByPosition(mCurrentPosition + 1) // 检查列表中的letter布局是否显示 if (view != null && view.top <= mLetterHeight && view?.findViewById(R.id.tv_letter)?.visibility == View.VISIBLE){ //被顶掉的效果 ll_top_title?.y = (-(mLetterHeight - view.top)).toFloat() }else{ ll_top_title?.y = 0f } //判断是否需要更新悬浮条 if (mCurrentPosition != mLayoutManager?.findFirstVisibleItemPosition()){ ll_top_title?.y = 0f updateLetter() } } }) }
RecyclerView添加滑动监听事件,处理title顶出的效果,在RecycerView外层添加一层title,recyclerview滑动过程中计算adapter中item的滑动位置,当到达外层title的高度时,动态改变外层title的位置,直到外层title被全部顶出,再把它复位,刷新外层title的字母。
右侧的SideBarView控件控制列表的快速滑动,在ContactRecyclerView中添加触摸监听,处理点击字母和滑动字母时的回调事件。
override fun setLetterVisibility(visibility: Int) { tv_letter_show?.visibility = visibility } override fun setLetter(letter: String?) { if (TextUtils.isEmpty(letter) || letter!!.isEmpty()){ return } tv_letter_show?.text = letter var position = getPositionForSection(letter!![0].toInt()) if (position != -1) { updateLetter() mLetterHeight = ll_top_title?.height!! mLayoutManager?.scrollToPositionWithOffset(position,0) // 使当前位置处于最顶端 } }
源码地址
github源码地址
更多相关文章
- Android的RelativeLayout的layout_height属性设置为wrap_content
- android LinearLayout布局子空间没有填充父控件的问题
- android TextView xml中设置最大行数
- Android(安卓)透明度对应16进制值
- Android(安卓)透明度对应16进制值
- Edittext android:inputType 输入的限制
- android 设置EditText只能输入大写字母,Fragment的软键盘输入模
- Android(安卓)EditText 限制输入数字和字母设置
- EditView某些属性说明