Android 自定义控件实现ListView索引
来源:互联网 发布:linux下怎么看java目录 编辑:程序博客网 时间:2024/04/30 02:32
实现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; } }}
0 0
- Android 自定义控件实现ListView索引
- 使用自定义控件和ListView实现快速索引功能
- android自定义控件索引
- Android 自定义ListView控件
- Android ListView侧边字母索引栏SideBar控件的实现
- Android开发--自定义控件实现listview的滑动删除item
- android tv 焦点居中自定义listview控件的实现
- Android自定义头部悬浮,快速索引ListView
- android自定义控件实现
- Android自定义控件实现
- Android自定义控件实现
- 自定义控件实现快速索引,字典排序
- 自定义View 实现字母快速索引控件
- 自定义ListView适配器并实现监听控件
- 自定义ListView控件实现下拉加载更多
- 自定义控件-实现ListView Item进入动画
- Android复杂自定义Listview实现
- android ListView自定义适配器实现
- 转载,写的不错的一个关于dshow的文章
- angularjs基础—$scope.$apply的应用
- C# 调用CMD
- 基于Arm板linux嵌入式系统RS485串口读写通讯
- linux中用命令mail发送邮件
- Android 自定义控件实现ListView索引
- 如何从国内镜像获取android源代码
- C# 获取文件名及扩展名
- ASP.NET MVC 如何解决“上下文的模型已在数据库创建后发生更改”问题
- java例子3:计算阶乘
- B树、B-树、B+树、B*树
- 查看sql server系统表信息
- request.getinputstream只能读取一次
- eWave: Leveraging Energy-Awareness for In-line Deduplication Clusters