实现listview 的索引 中间的预览文本因为截图水平有限没有截出来。。

源代码下载地址:

实现该方法需要重写lisetview 控件。实现步骤如下
1. 新建一个数组 用于存放右侧的a-z 的26个字母 然后写自定义空间IndexLisetview
2.IndexLisetview继承Lisetview 然后重写setFastScrollEnabled 、 draw、onTouchEvent、setAdapter、onSizeChanged 等方法。
3.在IndexScroller类实现绘制索引条和绘制预览文本的方法。并实现索引条的显示和隐藏的方法。
4.因为索引匹配,所以需要一个字符串匹配的算法。

部分代码如下
1.定义IndexLisetview

public class IndexableListView extends ListView {    private boolean mIsFastScrollEnabled = false;    private IndexScroller mScroller = null;//負責繪製索引條    private GestureDetector mGestureDetector = null;    public IndexableListView(Context context) {        super(context);    }    public IndexableListView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public IndexableListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    @Override    public boolean isFastScrollEnabled() {        return mIsFastScrollEnabled;    }    @Override    public void setFastScrollEnabled(boolean enabled) {//如果允许快速滚动的话        mIsFastScrollEnabled = enabled;        if (mIsFastScrollEnabled) {            if (mScroller == null)                //创建IndexScroller对象                mScroller = new IndexScroller(getContext(), this);        } else {            if (mScroller != null) {                mScroller.hide();                mScroller = null;            }        }    }    @Override    public void draw(Canvas canvas) {   //用于绘制右侧的索引条        super.draw(canvas);//绘制listview 原来的东西        //绘制右侧的索引条        if (mScroller != null)            mScroller.draw(canvas);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        //如果mscroller自己处理触摸事件,该方法返回true        if (mScroller != null && mScroller.onTouchEvent(ev))            return true;        if (mGestureDetector == null) {            //使用手势处理触摸事件            mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {                @Override                public boolean onFling(MotionEvent e1, MotionEvent e2,                        float velocityX, float velocityY) {                    //直接显示右侧的索引条                    if (mScroller != null)                        mScroller.show();                    return super.onFling(e1, e2, velocityX, velocityY);                }            });        }        mGestureDetector.onTouchEvent(ev);        return super.onTouchEvent(ev);    }    @Override    public void setAdapter(ListAdapter adapter) {        super.setAdapter(adapter);        if (mScroller != null)            mScroller.setAdapter(adapter);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        if (mScroller != null)            mScroller.onSizeChanged(w, h, oldw, oldh);    }}

2.绘制索引条和预览文本

public class IndexScroller {    private float mIndexbarWidth;//索引條寬度    private float mIndexbarMargin;//索引條距離右邊距離    private float mPreviewPadding;//中心現實的預覽文版距離四周的長度    private float mDensity;//当前的屏幕密度和标准的屏幕密度(160)的商 dp sp会随字体变化而变化     private float mScaledDensity;//当前的屏幕密度和标准的屏幕密度(160)的商(设置字体尺寸)    private float mAlphaRate;//透明度(用于显示和隐藏索引条)0-1之间    private int mState = STATE_HIDDEN;//索引条的状态    private int mListViewWidth;    private int mListViewHeight;    private int mCurrentSection = -1;    private boolean mIsIndexing = false;    private ListView mListView = null;    private SectionIndexer mIndexer = null;    private String[] mSections = null;    private RectF mIndexbarRect;//索引的区域    //索引的四个状态    private static final int STATE_HIDDEN = 0;//隐藏    private static final int STATE_SHOWING = 1;    private static final int STATE_SHOWN = 2;    private static final int STATE_HIDING = 3;public IndexScroller(Context context, ListView lv) {          //獲得屏幕密度的比值        mDensity = context.getResources().getDisplayMetrics().density;        mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;        mListView = lv;        setAdapter(mListView.getAdapter());          //根據屏幕密度技術索引條的寬度(單位像素)索引條會跟隨屏幕密度變化        mIndexbarWidth = 20 * mDensity;        mIndexbarMargin = 10 * mDensity;        mPreviewPadding = 5 * mDensity;    }      //繪製索引條和預覽文本    public void draw(Canvas canvas) {         //绘制索引条,包括索引条的背景和文版;          //绘制预览文版和背景        if (mState == STATE_HIDDEN)            //如果索引条隐藏不进行绘制            return;        //设置索引背景的绘制属性        Paint indexbarPaint = new Paint();        indexbarPaint.setColor(Color.BLACK);        indexbarPaint.setAlpha((int) (64 * mAlphaRate));        indexbarPaint.setAntiAlias(true);          //绘制索引条(4个交都是圆角举行)        canvas.drawRoundRect(mIndexbarRect, 5 * mDensity, 5 * mDensity, indexbarPaint);        //绘制sections        if (mSections != null && mSections.length > 0) {            //绘制预览文本和背景            if (mCurrentSection >= 0) {                Paint previewPaint = new Paint();                previewPaint.setColor(Color.BLACK);                previewPaint.setAlpha(96);                previewPaint.setAntiAlias(true);                previewPaint.setShadowLayer(3, 0, 0, Color.argb(64, 0, 0, 0));                Paint previewTextPaint = new Paint();                previewTextPaint.setColor(Color.WHITE);                previewTextPaint.setAntiAlias(true);                previewTextPaint.setTextSize(50 * mScaledDensity);                float previewTextWidth = previewTextPaint.measureText(mSections[mCurrentSection]);                  // 下端descent 正值, 上端ascent 负值                float previewSize = 2 * mPreviewPadding + previewTextPaint.descent() - previewTextPaint.ascent();                 //预览文本背景区域 矩形 左 上 右 底                RectF previewRect = new RectF((mListViewWidth - previewSize) / 2                        , (mListViewHeight - previewSize) / 2                        , (mListViewWidth - previewSize) / 2 + previewSize                        , (mListViewHeight - previewSize) / 2 + previewSize);                 //绘制背景                canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint);                 //绘制预览文本                canvas.drawText(mSections[mCurrentSection], previewRect.left + (previewSize - previewTextWidth) / 2 - 1                        , previewRect.top + mPreviewPadding - previewTextPaint.ascent() + 1, previewTextPaint);            }              //绘制索引条的文本            Paint indexPaint = new Paint();            indexPaint.setColor(Color.WHITE);            indexPaint.setAlpha((int) (255 * mAlphaRate));            indexPaint.setAntiAlias(true);            indexPaint.setTextSize(12 * mScaledDensity);            float sectionHeight = (mIndexbarRect.height() - 2 * mIndexbarMargin) / mSections.length;            float paddingTop = (sectionHeight - (indexPaint.descent() - indexPaint.ascent())) / 2;            for (int i = 0; i < mSections.length; i++) {                float paddingLeft = (mIndexbarWidth - indexPaint.measureText(mSections[i])) / 2;                //绘制索引条上的文字                canvas.drawText(mSections[i], mIndexbarRect.left + paddingLeft                        , mIndexbarRect.top + mIndexbarMargin + sectionHeight * i + paddingTop - indexPaint.ascent(), indexPaint);            }        }    }    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {        case MotionEvent.ACTION_DOWN:            // If down event occurs inside index bar region, start indexing            if (mState != STATE_HIDDEN && contains(ev.getX(), ev.getY())) {                setState(STATE_SHOWN);                // It demonstrates that the motion event started from index bar                mIsIndexing = true;                // Determine which section the point is in, and move the list to that section                mCurrentSection = getSectionByPoint(ev.getY());                mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));                return true;            }            break;        case MotionEvent.ACTION_MOVE:            if (mIsIndexing) {                // If this event moves inside index bar                if (contains(ev.getX(), ev.getY())) {                    // Determine which section the point is in, and move the list to that section                    mCurrentSection = getSectionByPoint(ev.getY());                    mListView.setSelection(mIndexer.getPositionForSection(mCurrentSection));                }                return true;            }            break;        case MotionEvent.ACTION_UP:            if (mIsIndexing) {                mIsIndexing = false;                mCurrentSection = -1;            }            if (mState == STATE_SHOWN)                setState(STATE_HIDING);            break;        }        return false;    }    public void onSizeChanged(int w, int h, int oldw, int oldh) {        mListViewWidth = w;        mListViewHeight = h;        mIndexbarRect = new RectF(w - mIndexbarMargin - mIndexbarWidth                , mIndexbarMargin                , w - mIndexbarMargin                , h - mIndexbarMargin);    }    public void show() {        if (mState == STATE_HIDDEN)            setState(STATE_SHOWING);        else if (mState == STATE_HIDING)            setState(STATE_HIDING);    }    public void hide() {        if (mState == STATE_SHOWN)            setState(STATE_HIDING);    }    public void setAdapter(Adapter adapter) {        if (adapter instanceof SectionIndexer) {            mIndexer = (SectionIndexer) adapter;            mSections = (String[]) mIndexer.getSections();        }    }    private void setState(int state) {        if (state < STATE_HIDDEN || state > STATE_HIDING)            return;        mState = state;        switch (mState) {        case STATE_HIDDEN:            // Cancel any fade effect            mHandler.removeMessages(0);            break;        case STATE_SHOWING:            // Start to fade in            mAlphaRate = 0;            fade(0);            break;        case STATE_SHOWN:            // Cancel any fade effect            mHandler.removeMessages(0);            break;        case STATE_HIDING:            // Start to fade out after three seconds            mAlphaRate = 1;            fade(3000);            break;        }    }    public boolean contains(float x, float y) {        // Determine if the point is in index bar region, which includes the right margin of the bar        return (x >= mIndexbarRect.left && y >= mIndexbarRect.top && y <= mIndexbarRect.top + mIndexbarRect.height());    }    private int getSectionByPoint(float y) {        if (mSections == null || mSections.length == 0)            return 0;        if (y < mIndexbarRect.top + mIndexbarMargin)            return 0;        if (y >= mIndexbarRect.top + mIndexbarRect.height() - mIndexbarMargin)            return mSections.length - 1;        return (int) ((y - mIndexbarRect.top - mIndexbarMargin) / ((mIndexbarRect.height() - 2 * mIndexbarMargin) / mSections.length));    }    private void fade(long delay) {        mHandler.removeMessages(0);        mHandler.sendEmptyMessageAtTime(0, SystemClock.uptimeMillis() + delay);    }    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (mState) {            case STATE_SHOWING:                // Fade in effect                mAlphaRate += (1 - mAlphaRate) * 0.2;                if (mAlphaRate > 0.9) {                    mAlphaRate = 1;                    setState(STATE_SHOWN);                }                mListView.invalidate();                fade(10);                break;            case STATE_SHOWN:                // If no action, hide automatically                setState(STATE_HIDING);                break;            case STATE_HIDING:                // Fade out effect                mAlphaRate -= mAlphaRate * 0.2;                if (mAlphaRate < 0.1) {                    mAlphaRate = 0;                    setState(STATE_HIDDEN);                }                mListView.invalidate();                fade(10);                break;            }        }    };}

3.实现A-z字母数组是适配和字符串匹配算法的调用

private class ContentAdapter extends ArrayAdapter<String> implements SectionIndexer {        private String mSections = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";        public ContentAdapter(Context context, int textViewResourceId,                List<String> objects) {            super(context, textViewResourceId, objects);        }        @Override        public int getPositionForSection(int section) {            // 根据Section来获得位置Position            //Y没有对应的items就往前查X直到查到对应的为止            for (int i = section; i >= 0; i--) {                for (int j = 0; j < getCount(); j++) {                    if (i == 0) {                        //查询数字                        for (int k = 0; k <= 9; k++) {                            if (StringMatcher.match(String.valueOf(getItem(j).charAt(0)), String.valueOf(k)))                                return j;                        }                    } else {//查询字母                        if (StringMatcher.match(String.valueOf(getItem(j).charAt(0)), String.valueOf(mSections.charAt(i))))                            return j;                    }                }            }            return 0;        }        @Override        public int getSectionForPosition(int position) {            // 根据Position来获得位置Section            return 0;        }        @Override        public Object[] getSections() {            // 存储数组元素 列表右侧的ABCD            String[] sections = new String[mSections.length()];            //将每个section作为但的数组袁术放到sections中            for (int i = 0; i < mSections.length(); i++)                //从section中获得每一个字符                sections[i] = String.valueOf(mSections.charAt(i));            return sections;        }    }}

更多相关文章

  1. ColorFilter初探一
  2. Android(安卓)曲线图的绘制示例代码
  3. Android(安卓)自定义View(四) 时钟clockView
  4. Android(安卓)Path类
  5. [置顶] 一个绚丽的loading动效分析与实现!
  6. 跟着徐宜生学Android——
  7. android opengl es添加纹理,绘制立方体纹理,立方体使用不同纹理
  8. Android(安卓)Shader 颜色、图像渲染 paint.setXfermode
  9. AndroidView绘制流程一(View添加流程)

随机推荐

  1. Android控制手电筒代码,简单易用,不需要任
  2. Android(安卓)SDK Manager无法更新的解决
  3. Android记事本NotePad应用功能拓展(三)
  4. Space在Android里的应用
  5. Android(安卓)renderscript, more info'
  6. Android(安卓)layout xml总结
  7. android 自定义对话框
  8. Android开发常用的linux命令、命令行操作
  9. [python3.5][uiautomator]android uiauto
  10. android 网络编程