Android 自定义View-字母索引表(一)

  在有些Android应用中,为了方便快速定位,经常会看到屏幕右侧有一个字母索引表,今天尝试使用自定义View的方式实现了索引表的基本布局。

  字母索引表的样式如下面的示意图所示,

  此时我们至少需要知道以下几个参数值:1.字母大小;2.单个字母所在区域的宽度;3.单个字母所在区域的高度。现在看如何实现:

    /**    * 26个英文字母以及一个#字符,#字符是为了索引非英文字母的内容,比如电话号码。     */    private String[] mAlphabetTable = {
            "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 mAlphabetSize = 0;
    /**
     * 字母表的宽度
     */
    private int mWidth = 0;
    /**
     * 字母表的高度
     */
    private int mHeight = 0;
    /**
     * 窗口高度
     */
    private int mDisplayHeight;
    /**
     * 单个字母所在区域的高度
     */
    private int mStepPixel;

    private int mFastScrollViewHeight = 0;
    private Rect[] mAlphabetRect = new Rect[27];
    private Rect mPointRectAll = new Rect();
    private static int mAlphabetLeftPadding = 0;
    private boolean[] mPoint = new boolean[27];

    public AlphabetFastScorll(Context context) {
        this(context, null);
    }

    public AlphabetFastScorll(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setAlpha(1.0f);//设置透明度1
        DisplayMetrics metric = new DisplayMetrics();
        ((WindowManager) getContext().getSystemService(getContext().WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metric);
        mDisplayHeight = metric.heightPixels;//获取窗口高度
    }

  

  在构造函数里,只设置了索引表的透明度和初始化mDisplayHeight参数。索引表的绘制工作大部分是在onDraw()里完成。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mStepPixel = getContext().getResources().getDimensionPixelOffset(R.dimen.fast_scroll_size);
        mFastScrollViewHeight = mStepPixel * 27;
             //初始化27个字母每个字母对应所在区域的大小范围
        InitAlphabetRect();

//初始化字母索引表的背景大小
        initPointRect(mFastScrollViewHeight, mStepPixel);

        //设置背景颜色
        Paint paintB = new Paint();
        paintB.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
        //paintB.setAlpha(0);
        canvas.drawRect(mPointRectAll, paintB);
     //设置字母中大小,颜色,位置等
        Paint paint = new Paint();
        float textSize = getContext().getResources().getDimensionPixelOffset(R.dimen.asus_index_size);
        paint.setColor(ContextCompat.getColor(getContext(), R.color.fast_scroll_text_color));
        paint.setTextAlign(Align.CENTER);
        paint.setTextSize(textSize);
        paint.setAntiAlias(true);

        for (int i = 0; i < mAlphabetRect.length; i++) {
            int x = (mAlphabetRect[i].left + mAlphabetRect[i].right) / 2;
            int y = mAlphabetRect[i].bottom;

            y = y - (int) (0.5 * (mStepPixel - textSize));            //字母绘制在mAlphabetRect[i]区域中间
            canvas.drawText(mAlphabetTable[i], x, y, paint);
        }
    }

    private void InitAlphabetRect() {
        for (int i = 0; i < mAlphabetRect.length; i++) {
            mAlphabetRect[i] = new Rect();
            mAlphabetRect[i].left = mAlphabetLeftPadding;
            mAlphabetRect[i].right = mAlphabetLeftPadding + this.getWidth();
            //Log.d(TAG,"InitAlphabetRect right = " + mAlphabetRect[i].right);
            if (i == 0) {
                mAlphabetRect[i].top = 0;
                mAlphabetRect[i].bottom = mStepPixel;
            } else {
                mAlphabetRect[i].top = mAlphabetRect[i-1].top + mStepPixel;
                mAlphabetRect[i].bottom = mAlphabetRect[i].top + mStepPixel;
            }
        }
    }

    private void initPointRect(int fastScrollViewHeight, int stepPixel) {
        int canvasWidth = getContext().getResources().getDimensionPixelOffset(R.dimen.asus_index_canvas_width);

        mPointRectAll = new Rect();
        mPointRectAll.left = 0;
        mPointRectAll.right = canvasWidth;
        mPointRectAll.top = 0;
        mPointRectAll.bottom = this.getHeight();
    }

  在onDraw()里做了以下几件事情:

  1,初始化索引表字母所在区域的范围:新建一个Rect对象,设置其左右和上下大小。宽度大小由布局文件中提供,高度为mStepPixel。

  2,初始化索引表背景范围:宽 = asus_index_canvas_width,高 = this.getHeight();

  3,已经知道每个字母所在区域范围以及索引背景范围,新建两个Paint在Canves上进行绘制;

  通过以上几步就可以简单实现索引表控件,光光显示一个索引表肯定没啥意义。一般都是将索引表与ListView组合,实现快速定位功能。下篇准备模仿联系人应用,实现通过索引表快速定位到联系人。

时间: 2024-10-24 13:09:14

Android 自定义View-字母索引表(一)的相关文章

浅谈android中手机联系人字母索引表的实现

实际上字母索引表的效果,可以说在现在的众多APP中使用的非常流行,比如支付宝,微信中的联系人,还有购物,买票的APP中选择全国城市,切换城市的时候,这时候的城市也就是按照一个字母索引的顺序来显示,看起来是很方便的.其实这种字母索引表的效果最开始是出现在微信的联系人中.因为觉得这种效果功能在今后的项目中可以说是非常常见,可能会用的上,所以准备来波博客讲述一下实现的原理,一来方便以后自己复习,二来如果能够帮助一些android路上奋斗小伙伴也是蛮有意义的. 下面我们先来看下效果图, 看完效果图后我们

android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的Android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体上来说,左边是一个ListView,右边是一个自定义View,但是左边的ListView和我们平常使用的ListView还有一点点不同,就是在ListView中我对所有的联系人进行了分组,那么这种效果的实现最常见的就是两种思路: 1.使用ExpandableListView来实现这种分组效果 2.使

Android自定义View(二、深入解析自定义属性)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51468648 本文出自:[openXu的博客] 目录: 为什么要自定义属性 怎样自定义属性 属性值的类型format 类中获取属性值 Attributeset和TypedArray以及declare-styleable ??在上一篇博客<Android自定义View(一.初体验)>中我们体验了自定义控件的基本流程: 继承View,覆盖构造方法 自定义属性 重写onMeasure方法测量宽

Android自定义View(CustomCalendar-定制日历控件)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/54020386 本文出自:[openXu的博客] 目录: 1分析 2自定义属性 3onMeasure 4onDraw 绘制月份 绘制星期 绘制日期及任务 5事件处理 源码下载 ??应项目需求,需要做一个日历控件,效果图如下: ???? ??接到需求后,没有立即查找是否有相关开源日历控件可用.系统日历控件是否能满足 ,第一反应就是这个控件该怎么画?谁叫咱自定义控件技术牛逼呢O(∩_∩)O哈哈~

android自定义View之NotePad出鞘记

现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个页面还是很简单的. 1.自定义View的分类 OK,那么在正文开始之前,我想先来说说自定义View的分类,自定义View我们一共分为三类 1.自绘控件 自绘控件就是我们自定义View继承自已有控件,然后扩展其功能,之前两篇自定义View的博客(android自定义View之钟表诞生记,android

Android自定义View(一)

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

【Android自定义View实战】之仿百度加载动画,一种优雅的Loading方式

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53470872 本文出自[DylanAndroid的博客] Android自定义View实战之仿百度加载动画一种优雅的Loading方式 第一个仿百度加载动画用ObjectAnimator属性动画操作ImageView的属性方法实现 第二个仿百度加载动画第二种实现方式用ValueAnimator原生的ondraw方法实现 第三个扔球动画-水平旋转动画 第四个扔球动画-垂直旋转动

Android 自定义View——自定义点击事件

每个人手机上都有通讯录,这是毫无疑问的,我们通讯录上有一个控件,在通讯录的最左边有一列从"#"到"Z"的字母,我们通过滑动或点击指定的字母来确定联系人的位置,进而找到联系人.我们这一节就通过开发这个控件,来学如何自定义控件的点击事件. 通讯录列表查找控件界面绘制 首先我们需要先将控件的基本布局绘制出来,这里我们不在做详细的解释,在<Android 自定义View--自定义View控件 >博客中,我们已经详细讲解了如何绘制自定义控件的布局.通讯录列表查找控

Android自定义View(三、深入解析控件测量onMeasure)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51490283 本文出自:[openXu的博客] 目录: onMeasure什么时候会被调用 onMeasure方法执行流程 MeasureSpec类 从ViewGroup的onMeasure到View的onMeasure ViewGroup中三个测量子控件的方法 getChildMeasureSpec方法 View的onMeasure setMeasuredDimension ??在上一篇