自定义通讯录字母索引

2024-05-27 01:48

本文主要是介绍自定义通讯录字母索引,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、先来看下布局的效果

布局的代码如下,其中LetterIndexView为我们将要自定义的控件,使用相对布局置于界面的右侧;

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"tools:context="com.itemp.letterindexview.MainActivity"><ListView
        android:id="@+id/lvFriends"android:layout_width="match_parent"android:layout_height="match_parent"/><TextView
        android:id="@+id/tvCurrentLetter"android:layout_width="100dp"android:layout_height="100dp"android:background="@drawable/shape_letterindexview_bg_pressed"android:gravity="center"android:textSize="50sp"android:layout_centerInParent="true"android:textColor="@color/white"android:textStyle="bold"android:visibility="visible"android:text="A" /><com.itemp.letterindexview.LetterIndexView
        android:id="@+id/liv"android:layout_width="35dp"android:layout_height="match_parent"android:layout_margin="5dp"android:layout_alignParentRight="true"/></RelativeLayout>

2、继承于View并使用绘图法在画布上绘制字母:

public class LetterIndexView extends View

3、实现构造方法,在其中初始化画笔,并为控件设置背景图(shape资源制作的圆角矩形)

    public LetterIndexView(Context context) {this(context, null);}public LetterIndexView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public LetterIndexView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//setBackgroundResourece();setBackgroundResource(R.drawable.shape_letterindexview_bg);paint = new Paint();paint.setAntiAlias(true);//抗锯齿}

4、shape资源的定义代码:res/drawable/shape_letterindexview_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#fff" /><stroke
        android:width="1dp"android:color="#ddd" /><corners android:radius="10dp" />
</shape>

这是一个白色实心的圆角矩形,按下后将其变为黄色实心的圆角矩形,文件为res/drawable/shape_letterindexview_bg_pressed.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#ff0" /><stroke
        android:width="1dp"android:color="#ddd" /><corners android:radius="10dp" />
</shape>

5、定义字符串数组作为索引的文本:

String[] letters = new String[]{"A", "B", "C", "D", "E", "F", "G","H", "I", "J", "K", "L", "M", "N","O", "P", "Q", "R", "S", "T","U", "V", "W", "X", "Y", "Z", "#",
};

6、覆写onDraw()方法,将字母纵向排列均匀地绘制在画布上:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (width == 0) {width = getWidth();height = getHeight();}//把字母画在控件上,【选中字母】用红色画笔,否则黑色for (int i = 0; i < letters.length; i++) {//计算startX,控件宽度的一半减去字母宽度的一半String letter = letters[i];float letterSize = paint.measureText(letter);float startX = (width - letterSize) / 2;//startY,上方所有单元格的高度之和+(单元格高度的一半+字母高度的一半)float unitHeight = (height - 40) / 27f;float startY = 20 + i * unitHeight + (unitHeight + letterSize) / 2;//高亮字母为红色,否则为黑色if(i == currentPosition){paint.setColor(Color.RED);}else {paint.setColor(Color.BLACK);}paint.setTextSize(35);paint.setStyle(Paint.Style.FILL_AND_STROKE);//使用加粗效果canvas.drawText(letter, startX, startY, paint);//绘制字母}}

7、接下来覆写onTouchEvent()定义手指在控件上的滑动响应,逻辑为:
·手指按下,整个控件的背景色变为黄色,并根据手指按下的y的位置,确认哪个字母为选中字母,并重绘以将该字母高亮显示,并通知外界响应按下事件(比如显示小窗口见本文末尾GIF)
·手指滑动,动态改变选中字母,并重绘以将该字母高亮显示
·手指抬起,控件背景恢复为默认的白色,并通知外界响应(比如隐藏小窗口见文章末尾GIF)

    @Overridepublic boolean onTouchEvent(MotionEvent event) {float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN://改变背景效果setBackgroundResource(R.drawable.shape_letterindexview_bg_pressed);//根据手指位置设置高亮字母并重绘invalidateCurrentPosition(y);//通知外界手指按下if (callback != null) {callback.onFingerDown(true);}break;case MotionEvent.ACTION_MOVE://根据手指位置设置高亮字母并重绘invalidateCurrentPosition(y);//通知外界字母变化if (callback != null) {callback.onLetterChanged(letters[currentPosition]);}break;case MotionEvent.ACTION_UP://恢复背景效果setBackgroundResource(R.drawable.shape_letterindexview_bg);//通知外界手指抬起if (callback != null) {callback.onFingerDown(false);}break;}return true;}/*** 根据手指位置动态设置高亮字母并重绘* @param y*/private void invalidateCurrentPosition(float y) {currentPosition = (int) ((y / height) * letters.length);if(currentPosition > 26){currentPosition = 26;}invalidate();}

11、以接口的方式通知外界:手指按下或抬起,高亮字母发生改变:

    LetterIndexCallback callback;public void setCallback(LetterIndexCallback callback) {this.callback = callback;}public interface LetterIndexCallback {void onFingerDown(boolean down);void onLetterChanged(String letter);}

12、最后当外界ListView主动滚动时,字母索引的选中字母也随之变化,我们为外界提供公共方法,用于更新选中字母的位置:

    /*** 供外界ListView滚动时通知到当前控件* @param firstLetter*/public void setCurrentLetter(String firstLetter) {for (int i = 0; i < letters.length; i++) {if(letters[i].equals(firstLetter)){setCurrentPosition(i);return;}}}

13、Activity实现【索引控件】的回调接口,并将自身设置给【索引控件】:

public class MainActivity extends AppCompatActivity implements LetterIndexView.LetterIndexCallback 
@Overridepublic void onLetterChanged(String letter) {tvCurrentLetter.setText(letter);}@Overridepublic void onFingerDown(boolean fingerDown) {if(fingerDown){tvCurrentLetter.setVisibility(View.VISIBLE);}else {tvCurrentLetter.setVisibility(View.GONE);}}
letterIndexView.setCallback(this);

效果如下:
这里写图片描述

这篇关于自定义通讯录字母索引的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1006192

相关文章

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

MySQL 索引简介及常见的索引类型有哪些

《MySQL索引简介及常见的索引类型有哪些》MySQL索引是加速数据检索的特殊结构,用于存储列值与位置信息,常见的索引类型包括:主键索引、唯一索引、普通索引、复合索引、全文索引和空间索引等,本文介绍... 目录什么是 mysql 的索引?常见的索引类型有哪些?总结性回答详细解释1. MySQL 索引的概念2

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束