仿微信联系人列表字母侧滑控件, 侧滑控件参考了以下博客:

Android实现ListView的A-Z字母排序和过滤搜索功能
首先分析一下字母侧滑控件应该如何实现,根据侧滑控件的高度和字母的数量来平均计算每个字母应该占据的高度。
在View的onDraw()方法下绘制每一个字母
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int height = getHeight();// 获取对应高度
int width = getWidth(); // 获取对应宽度
int singleHeight = height / getData().size();// 获取每一个字母的高度
for (int i = 0; i < getData().size(); i++) {
mPaint.setColor(getLetterColor());//绘制字母的颜色
mPaint.setTypeface(Typeface.DEFAULT);
mPaint.setAntiAlias(true);
mPaint.setTextSize(singleHeight);
// 如果是选中的状态
if (i == mPosition) {
mPaint.setColor(getLetterPressedColor());
mPaint.setFakeBoldText(true);
}
// x坐标等于总体宽度中间的位置减去字符串宽度的一半.
float xPos = width / 2 - mPaint.measureText(getData().get(i)) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(getData().get(i), xPos, yPos, mPaint);
mPaint.reset();// 重置画笔
}
}
然后再看一下触控事件的拦截处理
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();// 点击y坐标
final int lastPosition = mPosition;//记录上一次选中字母的位置
final int position = (int) (y / getHeight() * getData().size());// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
switch (action) {
//当手指离开
case MotionEvent.ACTION_UP:
//设置侧滑控件的背景色
setBackgroundColor(getBackgroundNormalColor());
mPosition = -1;
invalidate();
if (getOnTouchLetterListener() != null) {
//回调事件,告知当前手指已经离开当前区域
getOnTouchLetterListener().onTouchOutside();
}
break;
default:
//更改当字母为选中状态时控件的背景色
setBackgroundColor(getBackgroundPressedColor());
//如果选中字母的位置不等于上一次选中的位置
if (lastPosition != position) {
if (position >= 0 && position < getData().size()) {
if (getOnTouchLetterListener() != null) {
//回调事件,返回当前选中的字母
getOnTouchLetterListener().onTouchLetter(getData().get(position));
}
mPosition = position;
invalidate();
}
}
break;
}
return true;
}
public interface OnTouchLetterListener {
/**
* 当接触到某个key的时候会调用;
* @param s
*/
void onTouchLetter(String s);
/**
* 当离开控件可触摸区域时会调用;
*/
void onTouchOutside();
}
侧滑控件完成后, 再分析一下分组界面是怎么实现的,不同分组由不同的字母作为标题,用ListView就可以实现,ListView里使用的Adapter里面有一个方法getItemViewType()方法用于区分返回多种类型的View,这里我们就两种, 一个是标题,一个是联系人信息;顶部里那些新的朋友、群聊等可以用ListView的addHeaderView()实现。但是用最SDK自带的BaseAdapter实现分组的话也不方便,实际上我们可以进一步包装;
首先看一下最基本的Adapter封装:
public abstract class SimpleAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List<T> mData;
public SimpleAdapter(){}
public SimpleAdapter(Context context, List<T> data){
init(context, data);
}
public void init(Context context, List<T> data){
this.mContext = context;
this.mData = data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public T getItem(int position) {
if(checkPositionIsOutOfRange(position)){
return null;
}
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
public void refresh(List<T> data){
if(data == null){
this.mData.clear();
}else{
this.mData = data;
}
notifyDataSetChanged();
}
public boolean checkPositionIsOutOfRange(int position){
if(0 <= position && position < mData.size()){
return false;
}
return true;
}
public Context getContext(){
return mContext;
}
public List<T> getData(){
return mData;
}
}
这个SimpleAdapter实现了数据基于List的最基本方法的实现,使得每次继承BaseAdapter不用再实现一些基本的方法,接下来再看一下用于更好实现分组的Adapter的进一步封装:
public abstract class SortAdapter<K extends SortKey, V, VH_G extends ViewHolder, VH_C extends ViewHolder> extends SimpleAdapter<Object> {
public final static int VIEW_TYPE_GROUP = 0;
public final static int VIEW_TYPE_CHILD = 1;
private HashMap<SortKey, Integer> mKeyIndex = new HashMap<>();
public SortAdapter(Context context, Map<K, List<V>> map) {
init(context, convertMapToList(map));
}
public SortAdapter(Context context, List<Object> list) {
init(context, list);
}
/**
* 转换分组数据为List,并且更新键值的索引
* @param map
* @return
*/
public List<Object> convertMapToList(Map<K, List<V>> map) {
List<Object> mData = new ArrayList<>();
mKeyIndex.clear();
for (Map.Entry<K, List<V>> entry : map.entrySet()) {
mData.add(entry.getKey());
mKeyIndex.put(entry.getKey(), mData.size() - 1);
for (V v : entry.getValue()) {
mData.add(v);
}
}
return mData;
}
public void refresh(Map<K, List<V>> map) {
super.refresh(convertMapToList(map));
}
@Override
public void refresh(List<Object> data) {
super.refresh(data);
mKeyIndex.clear();
}
/**
* 得到键值的索引值
* @param k
* @return
*/
public int getKeyIndex(K k){
Integer integer = mKeyIndex.get(k);
if(integer == null){
return getKeyIndexFromList(k);
}
return integer;
}
public int getKeyIndexFromList(K k){
for(int i = 0; i < getCount(); i++){
Object obj = getItem(i);
if(obj != null && obj instanceof SortKey){
if(obj.equals(k)){
mKeyIndex.put(k, i);
return i;
}
}
}
return -1;
}
@Override
public int getItemViewType(int position) {
Object obj = getItem(position);
if (obj instanceof SortKey) {
return VIEW_TYPE_GROUP;
}
return VIEW_TYPE_CHILD;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
if (0 <= position && position < mData.size()) {
return mData.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int viewType = getItemViewType(position);
View view = null;
Object obj = getItem(position);
switch (viewType) {
case VIEW_TYPE_GROUP:
view = getGroupView((K)obj, position, convertView, parent);
break;
case VIEW_TYPE_CHILD:
view = getChildView((V)obj, position, convertView, parent);
break;
}
return view;
}
public View getGroupView(K key, int position, View convertView, ViewGroup parent){
VH_G vh;
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(getGroupLayoutId(), null);
vh = onCreateGroupViewHolder(convertView, parent);
convertView.setTag(vh);
}else{
vh = (VH_G)convertView.getTag();
}
onBindGroupViewHolder(vh, key, position);
return convertView;
}
public View getChildView(V value, int position, View convertView, ViewGroup parent){
VH_C vh;
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(getChildLayoutId(), null);
vh = onCreateChildViewHolder(convertView, parent);
convertView.setTag(vh);
}else{
vh = (VH_C)convertView.getTag();
}
onBindChildViewHolder(vh, value, position);
return convertView;
}
public abstract @LayoutRes int getGroupLayoutId();
public abstract VH_G onCreateGroupViewHolder(View convertView, ViewGroup parent);
public abstract void onBindGroupViewHolder(VH_G vh, K key, int position);
public abstract @LayoutRes int getChildLayoutId();
public abstract VH_C onCreateChildViewHolder(View convertView, ViewGroup parent);
public abstract void onBindChildViewHolder(VH_C vh, V value, int position);
public interface SortKey {
}
public static class ViewHolder{
public View mParent;
public ViewHolder(View parent){
mParent = parent;
}
public View findViewById(@IdRes int id){
return mParent.findViewById(id);
}
}
本项目Github地址(基于AndroidStudio构建):
https://github.com/yuhengye/LetterSort
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android仿微信联系人列表侧滑控件
# Android联系人列表字母侧滑
# Android侧滑控件
# Android 实现带字母索引的侧边栏功能
# Android自定义字母选择侧边栏
# Android自定义字母导航栏
# Android自定义View实现字母导航栏
# Android开发实现根据字母快速定位侧边栏
# 看一下
# 回调
# 键值
# 背景色
# 也不
# 是怎么
# 两种
# 可以用
# 我们可以
# 然后再
# 再看
# 自带
# 接触到
# 不等于
# 就等于
# 大家多多
# 如何实现
# 就可以
# 搜索功能
# 有一个
相关文章:
如何在Tomcat中配置并部署网站项目?
家庭建站与云服务器建站,如何选择更优?
阿里云网站制作公司,阿里云快速搭建网站好用吗?
招贴海报怎么做,什么是海报招贴?
已有域名能否直接搭建网站?
一键网站制作软件,义乌购一件代发流程?
实例解析angularjs的filter过滤器
如何选择高效可靠的多用户建站源码资源?
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
如何通过VPS建站实现广告与增值服务盈利?
黑客入侵网站服务器的常见手法有哪些?
如何选择域名并搭建高效网站?
如何快速搭建高效服务器建站系统?
一键制作网站软件下载安装,一键自动采集网页文档制作步骤?
深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?
北京的网站制作公司有哪些,哪个视频网站最好?
建站主机无法访问?如何排查域名与服务器问题
利用JavaScript实现拖拽改变元素大小
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
如何用PHP快速搭建高效网站?分步指南
如何在沈阳梯子盘古建站优化SEO排名与功能模块?
武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?
定制建站哪家更专业可靠?推荐榜单揭晓
详解jQuery停止动画——stop()方法的使用
建站之星伪静态规则如何设置?
南宁网站建设制作定制,南宁网站建设可以定制吗?
C++如何使用std::optional?(处理可选值)
官网建站费用明细查询_企业建站套餐价格及收费标准指南
已有域名建站全流程解析:网站搭建步骤与建站工具选择
建站之星logo尺寸如何设置最合适?
网站代码制作软件有哪些,如何生成自己网站的代码?
大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?
定制建站策划方案_专业建站与网站建设方案一站式指南
如何正确下载安装西数主机建站助手?
相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?
如何构建满足综合性能需求的优质建站方案?
建站之星后台管理系统如何操作?
如何制作算命网站,怎么注册算命网站?
如何选择香港主机高效搭建外贸独立站?
怀化网站制作公司,怀化新生儿上户网上办理流程?
建站主机数据库如何配置才能提升网站性能?
建站VPS配置与SEO优化指南:关键词排名提升策略
网站制作需要会哪些技术,建立一个网站要花费多少?
如何用免费手机建站系统零基础打造专业网站?
营销式网站制作方案,销售哪个网站招聘效果最好?
浅谈Javascript中的Label语句
C#怎么使用委托和事件 C# delegate与event编程方法
如何制作一个表白网站视频,关于勇敢表白的小标题?
公司网站制作价格怎么算,公司办个官网需要多少钱?
如何在IIS中新建站点并配置端口与IP地址?
*请认真填写需求信息,我们会在24小时内与您取得联系。