A-Z排序控件的实现
- 前言
最近项目需要做一个地区首字母a-z排序的效果,记录一下自己如何实现的.
先看下效果图:

- 分析
这种效果自己实现还是第一次;之前见过这种效果:

这些字母都是onDraw画上去的;只要知道每个字母的left,top,right,bottom就能知道它的具体位置,所以onMeasure方法中要确定每个单元格的宽高.文字排序可以先把汉字转换成拼音,再去比较首字母的顺序(特殊地区特殊处理,比如重庆);
具体看下是如何确定字母的位置:

于是乎,代码就出来了:
public class QuickIndexBar extends View {
private OnLetterUpdateListener onLetterUpdateListener;
public interface OnLetterUpdateListener{
void onLetterUpdate(String letter);
}
public OnLetterUpdateListener getOnLetterUpdateListener() {
return onLetterUpdateListener;
}
public void setOnLetterUpdateListener(
OnLetterUpdateListener onLetterUpdateListener) {
this.onLetterUpdateListener = onLetterUpdateListener;
}
private static final 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"
};
private Paint paint;
// 单元格宽度
private int cellWidth;
// 单元格高度
private float cellHeight;
public QuickIndexBar(Context context) {
this(context, null);
}
public QuickIndexBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 创建一个抗锯齿的画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 画笔文本加粗
paint.setTypeface(Typeface.DEFAULT_BOLD);
// 颜色
paint.setColor(Color.WHITE);
}
@Override
protected void onDraw(Canvas canvas) {
// 遍历26个英文字母, 计算坐标, 进行绘制
for (int i = 0; i < LETTERS.length; i++) {
String letter = LETTERS[i];
// 计算x坐标
float x = cellWidth * 0.5f - paint.measureText(letter) * 0.5f;
// 计算y坐标
Rect bounds = new Rect();
// 获取文本的矩形区域
paint.getTextBounds(letter, 0, letter.length(), bounds);
float y = cellHeight * 0.5f + bounds.height() * 0.5f + i * cellHeight;
// 绘制文本
canvas.drawText(letter, x, y, paint);
}
}
private int lastIndex = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
float y;
int currentIndex;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 获取被点击到的字母索引
y = event.getY();
// 根据y值, 计算当前按下的字母位置
currentIndex = (int) (y / cellHeight);
if(currentIndex != lastIndex){
if(currentIndex >= 0 && currentIndex < LETTERS.length){
String letter = LETTERS[currentIndex];
if(onLetterUpdateListener != null){
onLetterUpdateListener.onLetterUpdate(letter);
}
System.out.println("letter: " + letter);
// 记录上一次触摸的字母
lastIndex = currentIndex;
}
}
break;
case MotionEvent.ACTION_MOVE:
// 获取被点击到的字母索引
y = event.getY();
// 根据y值, 计算当前按下的字母位置
currentIndex = (int) (y / cellHeight);
if(currentIndex != lastIndex){
if(currentIndex >= 0 && currentIndex < LETTERS.length){
String letter = LETTERS[currentIndex];
if(onLetterUpdateListener != null){
onLetterUpdateListener.onLetterUpdate(letter);
}
System.out.println("letter: " + letter);
// 记录上一次触摸的字母
lastIndex = currentIndex;
}
}
break;
case MotionEvent.ACTION_UP:
lastIndex = -1;
break;
default:
break;
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mHeight = getMeasuredHeight();
cellWidth = getMeasuredWidth();
cellHeight = mHeight * 1.0f / LETTERS.length;
}
}
这种竖直的简单快速索引就搞定了,此外还添加了触摸和点击的监听
- 实现
再来看下我们要的效果图那种效果是如何实现的;主要区别就是字母所在位置和触摸位置的差异,偷点懒,直接上代码了:
@Override
protected void onDraw(Canvas canvas) { // 遍历26个英文字母, 计算坐标, 进行绘制
for (int i = 0; i < LETTERS.length; i++) {
String letter = LETTERS[i]; // 计算x坐标
// float x = cellWidth * 0.5f - paint.measureText(letter) * 0.5f;
float y = cellHeight * 0.5f + paint.measureText(letter) * 0.5f;
// 计算y坐标
Rect bounds = new Rect();
// 获取文本的矩形区域
paint.getTextBounds(letter, 0, letter.length(), bounds); // float y = cellHeight * 0.5f + bounds.height() * 0.5f + i * cellHeight;
float x = cellWidth * 0.5f + bounds.width() * 0.5f + i * cellWidth;
// 绘制文本
canvas.drawText(letter, x, y, paint);
}
} private int lastIndex = -1; @Override
public boolean onTouchEvent(MotionEvent event) { float x;
int currentIndex; switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 获取被点击到的字母索引
x = event.getX();
// 根据x值, 计算当前按下的字母位置
currentIndex = (int) (x / cellWidth);
if (currentIndex != lastIndex) {
if (currentIndex >= 0 && currentIndex < LETTERS.length) {
String letter = LETTERS[currentIndex];
if (onLetterUpdateListener != null) {
onLetterUpdateListener.onLetterUpdate(letter);
}
// 记录上一次触摸的字母
lastIndex = currentIndex;
}
} break;
case MotionEvent.ACTION_MOVE:
// 获取被点击到的字母索引
x = event.getX();
// 根据y值, 计算当前按下的字母位置
currentIndex = (int) (x / cellWidth);
if (currentIndex != lastIndex) {
if (currentIndex >= 0 && currentIndex < LETTERS.length) {
String letter = LETTERS[currentIndex];
if (onLetterUpdateListener != null) {
onLetterUpdateListener.onLetterUpdate(letter);
}
// 记录上一次触摸的字母
lastIndex = currentIndex;
}
} break;
case MotionEvent.ACTION_UP:
lastIndex = -1;
break;
default:
break;
} return true;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mWidth = getMeasuredWidth();
cellWidth = mWidth * 1.0f / LETTERS.length;
cellHeight = getMeasuredHeight();
}
可以看到主要区别就是单元格的宽度和高度相应改变了;后面会补充一张计算草图.
A-Z排序控件的实现的更多相关文章
- Android开源系列:仿网易Tab分类排序控件实现
前言 产品:网易新闻那个Tab排序好帅. 开发:哦~ 然后这个东东在几天后就出现了..... (PS:差不多一年没回来写博客了~~~~(>_<)~~~~,顺便把名字从 enjoy风铃 修改 ...
- DevExpress控件汉化类 z
更新了一些字段,VER9.3.3 using System; using DevExpress.XtraEditors.Controls; using DevExpress.XtraGrid.Loca ...
- 扩展GridView实现的一个自定义无刷新分页,排序,支持多种数据源的控件TwfGridView
最近项目View层越来越趋向于无刷新化,特别是数据展示方面,还要对Linq有很好的支持.在WebFrom模式的开发中,GridView是一个功能很强大,很常用的控件,但是他也不是完美的,没有自带的无刷 ...
- [DataTable]控件排序事件中用DataView及DataTable排序
控件排序事件中用DataView及DataTable排序 文章分类:.net编程 在做ASP.NET页面开发时,经常要用到dataset(或者DataTable),绑定到DataGrid或GridVi ...
- c++ builder TListView控件按字符串排序(根据网上代码亲测ok)
//--------------------------------------------------------------------------- /* 首先将一个列表框控件安放在Form上, ...
- DevExpress控件学习总结 z
1.Navigation & Layout 1.1 Bar Manager 如果想在窗体或用户控件(user control)上添加工具条(bars)或弹出菜单(popup menus),我们 ...
- dev中gridview控件 z
目录:一.客户端常用1.常用API2.聚焦行变更事件3.客户端选择多行4.客户端选择行5. 获取选择的行数目6.单击行时,选中行7.通过checkbox 选择行8.选择所有行9.启动编辑框,Conta ...
- DEV控件自定义排序实现
一般的控件或者组件都支持按照某一列进行排序.但是,这种排序是根据数据源里的数据默认按照降序或升序排序的,同时这样的排序与字段的类型有关. 假设现在字段的类型是字符串类型 ,但是,存储的数据时数字加一些 ...
- C# 调整控件的Z顺序
当窗口或者容器控件中的控件在布局过程中发生重叠的时候,会出现层次性.Z顺序较大的控件会遮挡Z顺序较小的控件,放在顶层的控件会挡住放在底层的控件. 1.编辑一个这样的窗口(使用Label控件) 2.添加 ...
随机推荐
- POJ 1062 昂贵的聘礼 【带限制的最短路/建模】
年轻的探险家来到了一个印第安部落里.在那里他和酋长的女儿相爱了,于是便向酋长去求亲.酋长要他用10000个金币作为聘礼才答应把女儿嫁给他.探险家拿不出这么多金币,便请求酋长降低要求.酋长说:" ...
- 洛谷P1908 逆序对 [权值线段树]
题目传送门 逆序对 题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的 ...
- python datetime处理时间(转)
Python提供了多个内置模块用于操作日期时间,像calendar,time,datetime.time模块,它提供 的接口与C标准库time.h基本一致.相比于time模块,datetime模块的接 ...
- 【BZOJ 1216】 1216: [HNOI2003]操作系统 (模拟+优先队列)
1216: [HNOI2003]操作系统 Description 写一个程序来模拟操作系统的进程调度.假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的.其中运行优先级用自 ...
- [BZOJ 2298] Problem A
Link: BZOJ 2298 传送门 Solution: 可以将每个人的话转化为$[l[i],r[i]]$的人得分相同 用$map$记录认为$[i,j]$相同的人数,$pos[i][j]$记录以$i ...
- 【线段树】hdu6183 Color it
题意: 维护一个数据结构,支持三种操作: ①在平面上(x,y)处添加一个颜色为c的点. ②询问平面上(1,y1)-(x,y2)范围内,有多少种不同颜色的点. ③清除平面上所有点. 颜色数量很少,对于每 ...
- (原创)Stanford Machine Learning (by Andrew NG) --- (week 10) Large Scale Machine Learning & Application Example
本栏目来源于Andrew NG老师讲解的Machine Learning课程,主要介绍大规模机器学习以及其应用.包括随机梯度下降法.维批量梯度下降法.梯度下降法的收敛.在线学习.map reduce以 ...
- Problem B: 颠倒字符串
#include<stdio.h> #include<string.h> //用来调用strlen(str)函数 int main() { int i,n; ]; while( ...
- BUG:upstream timed out (10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected
更换Apache扑向Nginx,刚搭建完WNMP,nginx能访问php页面 但是访问现有开发项目报错 [error] 4112#3724: *9 upstream timed out (10060: ...
- ORACLE启动 切换实例命令
启动服务器的其他实例 export ORACLE_SID=数据库实例名 sqlplus /nolog conn /as sysdba select name from v$database; !lsn ...