Android实现字母导航控件的示例代码

目录
  • 自定义属性
  • Measure测量
  • 坐标计算
  • 绘制
  • Touch事件处理
  • 数据组装
  • 显示效果

今天分享一个以前实现的通讯录字母导航控件,下面自定义一个类似通讯录的字母导航 View,可以知道需要自定义的几个要素,如绘制字母指示器、绘制文字、触摸监听、坐标计算等,自定义完成之后能够达到的功能如下:

  • 完成列表数据与字母之间的相互联动;
  • 支持布局文件属性配置;
  • 在布局文件中能够配置相关属性,如字母颜色、字母字体大小、字母指示器颜色等属性。

主要内容如下:

  • 自定义属性
  • Measure测量
  • 坐标计算
  • 绘制
  • 显示效果

自定义属性

在 value 下面创建 attr.xml ,在里面配置需要自定义的属性,具体如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LetterView">
        <!--字母颜色-->
        <attr name="letterTextColor" format="color" />
        <!--字母字体大小-->
        <attr name="letterTextSize" format="dimension" />
        <!--整体背景-->
        <attr name="letterTextBackgroundColor" format="color" />
        <!--是否启用指示器-->
        <attr name="letterEnableIndicator" format="boolean" />
        <!--指示器颜色-->
        <attr name="letterIndicatorColor" format="color" />
    </declare-styleable>
</resources>

然后在相应的构造方法中获取这些属性并进行相关属性的设置,具体如下:

public LetterView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    //获取属性
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LetterView);
    int letterTextColor = array.getColor(R.styleable.LetterView_letterTextColor, Color.RED);
    int letterTextBackgroundColor = array.getColor(R.styleable.LetterView_letterTextBackgroundColor, Color.WHITE);
    int letterIndicatorColor = array.getColor(R.styleable.LetterView_letterIndicatorColor, Color.parseColor("#333333"));
    float letterTextSize = array.getDimension(R.styleable.LetterView_letterTextSize, 12);
    enableIndicator = array.getBoolean(R.styleable.LetterView_letterEnableIndicator, true);

    //默认设置
    mContext = context;
    mLetterPaint = new Paint();
    mLetterPaint.setTextSize(letterTextSize);
    mLetterPaint.setColor(letterTextColor);
    mLetterPaint.setAntiAlias(true);

    mLetterIndicatorPaint = new Paint();
    mLetterIndicatorPaint.setStyle(Paint.Style.FILL);
    mLetterIndicatorPaint.setColor(letterIndicatorColor);
    mLetterIndicatorPaint.setAntiAlias(true);

    setBackgroundColor(letterTextBackgroundColor);

    array.recycle();
}

Measure测量

要想精确的控制自定义的尺寸以及坐标,必须要测量出当前自定义 View 的宽高,然后才可以通过测量到的尺寸计算相关坐标,具体测量过程就是继承 View 重写 omMeasure() 方法完成测量,关键代码如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //获取宽高的尺寸大小
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    //wrap_content默认宽高
    @SuppressLint("DrawAllocation") Rect mRect = new Rect();
    mLetterPaint.getTextBounds("A", 0, 1, mRect);
    mWidth = mRect.width() + dpToPx(mContext, 12);
    int mHeight = (mRect.height() + dpToPx(mContext, 5)) * letters.length;

    if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT &&
            getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(mWidth, mHeight);
    } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(mWidth, heightSize);
    } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(widthSize, mHeight);
    }

    mWidth = getMeasuredWidth();
    int averageItemHeight = getMeasuredHeight() / 28;
    int mOffset = averageItemHeight / 30; //界面调整
    mItemHeight = averageItemHeight + mOffset;
}

坐标计算

自定义 View 实际上就是在 View 上找到合适的位置,将自定义的元素有序的绘制出来即可,绘制过程最困难的就是如何根据具体需求计算合适的左边,至于绘制都是 API 的调用,只要坐标位置计算好了,自定义 View 绘制这一块应该就没有问题了,下面的图示主要是标注了字母指示器绘制的中心位置坐标的计算以及文字绘制的起点位置计算,绘制过程中要保证文字在指示器中心位置,参考如下:

绘制

自定义 View 的绘制操作都是在 onDraw() 方法中进行的,这里主要使用到圆的绘制以及文字的绘制,具体就是 drawCircle() 和 drawText() 方法的使用,为避免文字被遮挡,需绘制字母指示器,然后再绘制字母,代码参考如下:

@Override
protected void onDraw(Canvas canvas) {
    //获取字母宽高
    @SuppressLint("DrawAllocation") Rect rect = new Rect();
    mLetterPaint.getTextBounds("A", 0, 1, rect);
    int letterWidth = rect.width();
    int letterHeight = rect.height();

    //绘制指示器
    if (enableIndicator){
        for (int i = 1; i < letters.length + 1; i++) {
            if (mTouchIndex == i) {
                canvas.drawCircle(0.5f * mWidth, i * mItemHeight - 0.5f * mItemHeight, 0.5f * mItemHeight, mLetterIndicatorPaint);
            }
        }
    }
    //绘制字母
    for (int i = 1; i < letters.length + 1; i++) {
        canvas.drawText(letters[i - 1], (mWidth - letterWidth) / 2, mItemHeight * i - 0.5f * mItemHeight + letterHeight / 2, mLetterPaint);
    }
}

到此为止,可以说 View 的基本绘制结束了,现在使用自定义的 View 界面能够显示出来了,只是还没有添加相关的事件操作,下面将在 View 的触摸事件里实现相关逻辑。

Touch事件处理

为了判断手指当前所在位置对应的是哪一个字母,需要获取当前触摸的坐标位置来计算字母索引,重新 onTouchEvent() 方法,监听 MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE 来计算索引位置,监听 MotionEvent.ACTION_UP 将获得结果回调出去,具体参考如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            isTouch = true;
            int y = (int) event.getY();
            Log.i("onTouchEvent","--y->" + y + "-y-dp-->" + DensityUtil.px2dp(getContext(), y));
            int index = y / mItemHeight;

            if (index != mTouchIndex && index < 28 && index > 0) {
                mTouchIndex = index;
                Log.i("onTouchEvent","--mTouchIndex->" + mTouchIndex + "--position->" + mTouchIndex);
            }

            if (mOnLetterChangeListener != null && mTouchIndex > 0) {
                mOnLetterChangeListener.onLetterListener(letters[mTouchIndex - 1]);
            }

            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            isTouch = false;
            if (mOnLetterChangeListener != null && mTouchIndex > 0) {
                mOnLetterChangeListener.onLetterDismissListener();
            }
            break;
    }
    return true;
}

到此为止,View 的自定义关键部分基本完成。

数据组装

字母导航的基本思路是将某个需要与字母匹配的字段转换为对应的字母,然后按照该字段对数据进行排序,最终使得通过某个数据字段的首字母就可以批匹配到相同首字母的数据了,这里将汉字转化为拼音使用的是 pinyin4j-2.5.0.jar ,然后对数据项按照首字母进行排序将数据展示到出来即可,汉字装换为拼音如下:

//汉字转换为拼音
public static String getChineseToPinyin(String chinese) {
    StringBuilder builder = new StringBuilder();
    HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
    format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
    format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

    char[] charArray = chinese.toCharArray();
    for (char aCharArray : charArray) {
        if (Character.isSpaceChar(aCharArray)) {
            continue;
        }
        try {
            String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(aCharArray, format);
            if (pinyinArr != null) {
                builder.append(pinyinArr[0]);
            } else {
                builder.append(aCharArray);
            }
        } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
            badHanyuPinyinOutputFormatCombination.printStackTrace();
            builder.append(aCharArray);
        }
    }
    return builder.toString();
}

至于数据排序使用 Comparator 接口即可

显示效果

显示效果如下:

到此这篇关于Android实现字母导航控件的示例代码的文章就介绍到这了,更多相关Android字母导航控件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android自定义字母导航栏

    本文实例为大家分享了Android字母导航栏的具体代码,供大家参考,具体内容如下 效果 实现逻辑 明确需求 字母导航栏在实际开发中还是比较多见的,城市选择.名称选择等等可能需要到. 现在要做到的就是在滑动控件过程中可以有内容以及 下标的回调,方便处理其他逻辑! 整理思路 1.确定控件的尺寸,防止内容显示不全.相关的逻辑在onMeasure()方法中处理: 2.绘制显示的内容,在按下和抬起不同状态下文字.背景的颜色.相关逻辑在onDraw()方法中: 3.滑动事件的处理以及事件回调.相关逻辑在on

  • Android自定义View实现字母导航栏的代码

    思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re

  • Android仿微信实现首字母导航条

    本文介绍Android实现首字母导航条,先看张效果图,具体怎么实现看代码吧 具体的步骤 1.整体布局的显示 2. 实现A-Z的分组 3. 自定义A-Z的导航条 4. 中间显示/隐藏触摸到导航条具体的字母 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re

  • Android自定义View实现字母导航栏

    很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章. 思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <!--?xml version="1.0" encoding=&qu

  • Android实现字母导航控件的示例代码

    目录 自定义属性 Measure测量 坐标计算 绘制 Touch事件处理 数据组装 显示效果 今天分享一个以前实现的通讯录字母导航控件,下面自定义一个类似通讯录的字母导航 View,可以知道需要自定义的几个要素,如绘制字母指示器.绘制文字.触摸监听.坐标计算等,自定义完成之后能够达到的功能如下: 完成列表数据与字母之间的相互联动; 支持布局文件属性配置; 在布局文件中能够配置相关属性,如字母颜色.字母字体大小.字母指示器颜色等属性. 主要内容如下: 自定义属性 Measure测量 坐标计算 绘制

  • Android实现CoverFlow效果控件的实例代码

    最近研究了一下如何在Android上实现CoverFlow效果的控件,其实早在2010年,就有Neil Davies开发并开源出了这个控件,Neil大神的这篇博客地址.首先是阅读源码,弄明白核心思路后,自己重新写了一遍这个控件,并加入了详尽的注释以便日后查阅:而后在使用过程中,发现了有两点可以改进: (1)初始图片位于中间,左边空了一半空间,比较难看,可以改为重复滚动地展示: (2)由于图片一开始就需要加载出来,所以对内存开销较大,很容易OOM,需要对图片的内存空间进行压缩. 这个自定义控件包括

  • asp.net微软图表控件使用示例代码分享

    复制代码 代码如下: <configuration>  <system.webServer>    <handlers>      <remove name="ChartImageHandler" />      <add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST" 

  • C# WPF 父控件通过使用可视化树找到子控件的示例代码

    在我们使用WPF设计前台界面时,经常会重写数据模板,或者把控件放到数据模板里.但是一旦将控件放到数据模板中,在后台就没有办法通过控件的名字来获取它了,更没办法对它进行操作(例如,隐藏,改变控件的某个值). 如果你是比我还白的小白,对我刚刚陈述的东西不清楚,接下来我简单说一下什么是把控件放在数据模板中,怎么样的情况没法后台通过名字来获取控件,如果读者对于数据模板这些事儿已经清楚了,或者只关心如何使用可视化树可以将这部分跳过哈. 先上代码介绍一下什么是数据模板以WPF中ListBox控件为例: <L

  • C# wpf使用ListBox实现尺子控件的示例代码

    目录 前言 一.如何实现? 1.设置横向ListBox 2.Item设为刻度样式 3.绑定数据源 二.完整代码 三.效果预览 总结 前言 尺子在客户端开发中有一定的应用场景,比如厘米尺.白板的画线尺.视频剪辑的时间尺.一般可以采用用户控件通过自绘的方式实现,但今天我要讲一个不一样的方法,不使用自定义控件也不用用户控件,只需要ListBox即能实现一把尺子. 一.如何实现? 1.设置横向ListBox 我们实现一把水平的尺子,所以需要让ListBox横向显示 <ListBox.ItemsPanel

  • android水平循环滚动控件使用详解

    本文实例为大家分享了android水平循环滚动控件的具体代码,供大家参考,具体内容如下 CycleScrollView.java package com.example.test; import android.content.Context; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.view.GestureDetector;

  • Android自定义圆环倒计时控件

    本文实例为大家分享了Android自定义圆环倒计时控件的具体代码,供大家参考,具体内容如下 先来一张最终效果图: 主要思路: 在画渐变色圆环的时候,设置一个属性动画,根据属性动画的执行时长,来作为倒计时的时长.监听属性动画的进度,来达到 倒计时的目的. 二话不说,直接贴代码.具体实现思路都在注释上. 自定义属性: <declare-styleable name="CountDownProgressBar"> <attr name="countDown_cir

  • android实现圆环倒计时控件

    本文实例为大家分享了android实现圆环倒计时控件的具体代码,供大家参考,具体内容如下 1.自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> <!-- 倒计时控件属性 --> <declare-styleable name="CountDownView"> <!--颜色--> <attr name="rin

  • Android MarkTipsView文字标识控件使用方法

    本文实例为大家分享了Android MarkTipsView文字标识控件的具体代码,供大家参考,具体内容如下 效果预览 使用 使用方式跟TextView使用方式一样,背景设置直接setBackgroundColor 源码: import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; impo

  • Android自定义实现日历控件

    本文实例为大家分享了Android自定义实现日历控件的具体代码,供大家参考,具体内容如下 1. Calendar类 2. 布局 创建calendar_layout.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:padding="20sp" android:orientation="vertical" android:l

随机推荐