相信大家在许多App中都见到过带字母索引的界面,比如我最近看到的这个开源控件:

WaveSideBar

很酷是不是?!!!如果加在例如联系人列表界面上,大大提升了用户体验。

那么这个索引控件要怎么做呢,说到底就是自定义一个view,因为自身能力原因我并不能做出这样的效果,当然各位大神们可以自行去研究这类开源索引控件的源码。


以我的能力,现在只能做这样的:

虽然简单,但是对于新手来说学习一番还是不错的。

下面我们开始一步步写一个字母索引控件 SimpleSideBar


准备一些知识

这里推荐博主guolin的一系列文章

http://blog.csdn.net/guolin_blog/article/details/12921889

http://blog.csdn.net/guolin_blog/article/details/16330267

http://blog.csdn.net/jdsjlzx/article/details/41113969

第一步,创建类SimpleSideBar继承View

public class SimpleSideBar extends View {

    public SimpleSideBar(Context context) {
super(context);
} public SimpleSideBar(Context context, AttributeSet attrs) {
super(context, attrs);
} public SimpleSideBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} }

第二步,声明所需要的变量

    // 索引字母数组
private String[] alphabet = {
"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 int currentChoosenAlphabetIndex=-1; // 画笔
private Paint mPaint=new Paint(); // 索引字母绘制大小
private int alphabetTextSize=20;

第三步,重写onDraw函数

该函数是绘制函数,通过它将控件内容显现出来

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // 获得控件高度
int viewHeight=getHeight();
// 获得控件宽度
int viewWidth=getWidth();
// 控件高度除以索引字母个数得到每个索引字母的高度
int heightPerAlphabet=viewHeight/alphabet.length; //通过循环每个索引字母,并绘制出来
for (int i=0;i<alphabet.length;i++){ // 设置画笔颜色、画笔绘制文字粗细和大小,设置抗锯齿
mPaint.setColor(Color.BLACK);
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
mPaint.setTextSize(alphabetTextSize);
mPaint.setAntiAlias(true); // 如果当前选择的索引字母下标和循环到的索引字母下标相同
if(currentChoosenAlphabetIndex==i){ // 设置画笔颜色,绘制文字大小和加粗
mPaint.setColor(Color.YELLOW);
mPaint.setTextSize(alphabetTextSize);
mPaint.setFakeBoldText(true); } // 索引字母的相对于控件的x坐标,此处算法结果为居中
float xPos=viewWidth/2-mPaint.measureText(alphabet[i])/2;
// 索引字母的相对于控件的y坐标,索引字母的高度乘以索引字母下标+1即为y坐标
float yPos=heightPerAlphabet*i+heightPerAlphabet;
// 绘制索引字母
canvas.drawText(alphabet[i],xPos,yPos,mPaint);
// 重置画笔,为绘制下一个索引字母做准备
mPaint.reset(); }
}

到这里,我们直接把该控件加入layout中已经可以显示出来,只是没有触摸到索引字母使ListView/RecyclerView滚动到相应位置的功能。

如果要实现这个功能,我们需要重写dispatchTouchEvent函数来处理控件触摸事件,并且要对外提供一个接口来实现列表滚动到相应位置。

下面我们继续实现它。

第四步,提供一个接口

首先定义一个接口

    public interface OnLetterTouchedChangeListener{

        void onTouchedLetterChange(String letterTouched);

    }

接着声明一个接口变量,提供set方法

    OnLetterTouchedChangeListener onLetterTouchedChangeListener;

    public void setOnLetterTouchedChangeListener(OnLetterTouchedChangeListener onLetterTouchedChangeListener) {
this.onLetterTouchedChangeListener = onLetterTouchedChangeListener;
}

第五步,重写dispatchTouchEvent函数

该函数是控件触摸事件分发函数,当返回值为true时表示处理完毕不分发到下一级处理。

    @Override
public boolean dispatchTouchEvent(MotionEvent event) { // 获得触摸后的动作
int action = event.getAction();
// 获得触摸点的Y轴坐标
float touchYPos=event.getY(); // 控件高度除以索引字母的个数得到每个索引字母的高度(这里进行int强转),触摸点的Y轴坐标除以每个索引字母的高度就得到触摸到的索引字母的下标
int currentTouchIndex= (int) (touchYPos/getHeight()*alphabet.length); switch (action){
// 当触摸的动作为按下或者按下移动时
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
// 设置背景颜色
setBackgroundResource(R.color.grey_600); // 设置当前选的索引字母的下标值为当前选择的值
currentChoosenAlphabetIndex=currentTouchIndex; // 如果接口存在和索引下标值合法,执行接口方法,传入当前触摸的索引字母,供外部调用接收
if(onLetterTouchedChangeListener!=null&&currentTouchIndex<alphabet.length&&currentTouchIndex>-1){
onLetterTouchedChangeListener.onTouchedLetterChange(alphabet[currentTouchIndex]);
} // 重新绘制控件,即重新执行onDraw函数
invalidate(); break;
case MotionEvent.ACTION_UP: setBackgroundResource(R.color.grey_50);
// 当停止触摸控件的时候,将当前选择的索引字母下标值设为-1
currentChoosenAlphabetIndex=-1;
invalidate();
break;
default:break; } // 返回true表明该触摸事件处理完毕不分发出去
return true;
}

第六步,使用自定义的SimpleSideBar控件

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/> </LinearLayout> <me.pwcong.simplesidebar.view.SimpleSideBar
android:id="@+id/sideBar"
android:layout_width="30dp"
android:layout_height="wrap_content" /> </LinearLayout>

MainActivity.java

        ...

        sideBar= (SimpleSideBar) findViewById(R.id.sideBar);

        // 这里使用前面定义的接口
sideBar.setOnLetterTouchedChangeListener(new SimpleSideBar.OnLetterTouchedChangeListener() {
@Override
public void onTouchedLetterChange(String letterTouched) { // 获得触摸到的索引字母,再通过索引字母获取相应item的下标,执行列表滚动方法
int pos=simpleAdapter.getLetterPosition(letterTouched);
if(pos!=-1){
recyclerView.scrollToPosition(pos);
}
}
});

到这里我们的简单索引字母控件完成了,SimpleSideBar 的 Demo 可以在这里下载

https://github.com/pwcong/SimpleSideBar

做个简单的Android列表字母索引控件的更多相关文章

  1. Android常用酷炫控件(开源项目)github地址汇总

    转载一个很牛逼的控件收集帖... 第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.Gri ...

  2. Android 常用炫酷控件(开源项目)git地址汇总

    第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.P ...

  3. Android自定义控件之日历控件

      标签: android 控件 日历 应用 需求 2015年09月26日 22:21:54 25062人阅读 评论(109) 收藏 举报 分类: Android自定义控件系列(7) 版权声明:转载注 ...

  4. MaterialEditText——Android Material Design EditText控件

    MaterialEditText是Android Material Design EditText控件.可以定制浮动标签.主要颜色.默认的错误颜色等. 随着 Material Design 的到来, ...

  5. 一起写一个Android图片轮播控件

    注:本文提到的Android轮播控件Demo地址: Android图片轮播控件 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用 ...

  6. Android零基础入门第17节:Android开发第一个控件,TextView属性和方法大全

    原文:Android零基础入门第17节:Android开发第一个控件,TextView属性和方法大全 前面简单学习了一些Android UI的一些基础知识,那么接下来我们一起来详细学习Android的 ...

  7. Android RecyclerView滚动类控件修改、去掉滑动边界的阴影效果

    前言 滚动类控件,大家都用的很多,如 RecyclerView.NestedSrollView.... 下面以recyclerView为例讲解,其他滚动控件也同理. RecyclerView 滚动列表 ...

  8. Android调用相册拍照控件实现系统控件缩放切割图片

    android 下如果做处理图片的软件 可以调用系统的控件 实现缩放切割图片 非常好的效果 今天写了一个demo分享给大家 package cn.m15.test; import java.io.By ...

  9. android中的EditView控件

    android中的EditView控件 EditText继承关系:View-->TextView-->EditText ,EditText是可编辑文本框 1.EditText默认情况下,光 ...

随机推荐

  1. [原]Java修炼 之 基础篇(一)Java语言特性

    学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...

  2. Ant学习---第四节:Ant属性的介绍

    一.ant 属性设置,用 property 标签,详解如下: 特点 大小写敏感: 不可改变,先到先得,谁先设定,之后的都不能改变. 设置 1 .设置 name 和 value 属性值,比如: < ...

  3. Windows Server 2008R2配置MySQL Cluster并将管理节点和数据节点配置成windows服务

    说明:将mysql的管理节点和数据节点配置成windows服务是为了防止有人手误关闭管理节点或数据节点的dos命令窗口,管理节点或数据节点的命令窗口误关闭可能会造成mysql某台或某几台mysql不能 ...

  4. heap size eclipse 堆内存

    可以根据eclipse 或 myeclipse heapstats 使用情况调整堆内存大小,heap size 设置,-vmargs-Xms256-Xmx1024 ,其中Xms表示初始值,Xmx表示最 ...

  5. 多种方法实现H5网页图片动画效果;

    在web开发中,GIF动画效果是随处可见,比如常见的loading加载.人物奔跑的gif图片等等,那么这些都是怎么实现的呢?其实实现的原理很简单,简而言之,这些所谓的动画都是一帧一帧的图片经过一段时间 ...

  6. GB28181国检推流

    GB28181国检有一向内容是实时播放摄像机流,经过一番努力,搞定这个功能,现分享心得: 首先需要了解流程,说简答点就是视频流从哪里来到什么地方去,下图描述了视频流推流,转发的 基本过程:信令交互成功 ...

  7. Ubuntu 16.04 下卸载 lnmp/lamp 方法

    1.卸载 apache2 sudo apt-get --purge remove apache2* sudo apt-get autoremove apache2 (--purge 是完全删除并且不保 ...

  8. 双栈排序 noip2008

    首先可以看出第一个栈和第二个栈是没什么交集的,那么第一步是对这些元素分别归到两个栈里, 当存在k使i<j<k,a[k]<a[i]<a[j]时,i,j是不能放在一个栈里的,需要一 ...

  9. thinkPHP生成静态分页列表

    改造分页类Pagehtml.class.php <?php // 静态分页列表类 class Pagehtml extends Think { //分页url public $pageUrl; ...

  10. [百度空间] [原]CImageList支持32位透明位图

    32位的位图主要是包含Alpha值(0-255)可以有半透效果的.之前用FreeImage加载 的DIB, CImageList直接绘制会有黑色背景.即便用了ILC_MASK,也创建了mask map ...