很多人用过ListViewFilter这个开源列表,做得确实相当不错,但是在使用的过程中好像有点bug,当点击右侧的字母时,总是会触发列表中的某一项的点击事件,这里就给出这个bug的解决办法,主要是IndexBarView.java和PinnedHeaderListView.java这两个文件:
1. PinnedHeaderListView.java
public class PinnedHeaderListView extends ListView implements IIndexBarFilter { // interface object that configure pinned header view position in list view IPinnedHeader mAdapter; // view objects View mHeaderView,mIndexBarView,mPreviewTextView; // flags that decide view visibility boolean mHeaderVisibility=false; boolean mPreviewVisibility=false; // initially show index bar view with it's content boolean mIndexBarVisibility=true; // context object Context mContext; // view height and width int mHeaderViewWidth, mHeaderViewHeight, mIndexBarViewWidth, mIndexBarViewHeight, mIndexBarViewMargin, mPreviewTextViewWidth, mPreviewTextViewHeight; // touched index bar Y axis position used to decide preview text view position float mIndexBarY; public PinnedHeaderListView(Context context) { super(context); this.mContext = context; } public PinnedHeaderListView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; } public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.mContext = context; } @Override public void setAdapter(ListAdapter adapter) { this.mAdapter = (PinnedHeaderAdapter)adapter; super.setAdapter(adapter); } public void setPinnedHeaderView(View headerView) { this.mHeaderView = headerView; // Disable vertical fading when the pinned header is present // TODO change ListView to allow separate measures for top and bottom fading edge; // in this particular case we would like to disable the top, but not the bottom edge. if (mHeaderView != null) { setFadingEdgeLength(0); } } public void setIndexBarView(View indexBarView) { mIndexBarViewMargin = (int)mContext.getResources().getDimension(R.dimen.index_bar_view_margin); this.mIndexBarView = indexBarView; } public void setPreviewView(View previewTextView) { this.mPreviewTextView=previewTextView; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mHeaderView != null) { measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec); mHeaderViewWidth = mHeaderView.getMeasuredWidth(); mHeaderViewHeight = mHeaderView.getMeasuredHeight(); } if (mIndexBarView != null && mIndexBarVisibility) { measureChild(mIndexBarView, widthMeasureSpec, heightMeasureSpec); mIndexBarViewWidth = mIndexBarView.getMeasuredWidth(); mIndexBarViewHeight = mIndexBarView.getMeasuredHeight(); } if (mPreviewTextView != null && mPreviewVisibility) { measureChild(mPreviewTextView, widthMeasureSpec, heightMeasureSpec); mPreviewTextViewWidth = mPreviewTextView.getMeasuredWidth(); mPreviewTextViewHeight = mPreviewTextView.getMeasuredHeight(); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (mHeaderView != null) { mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); configureHeaderView(getFirstVisiblePosition()); } if (mIndexBarView != null && mIndexBarVisibility) { mIndexBarView.layout(getMeasuredWidth()- mIndexBarViewMargin - mIndexBarViewWidth, mIndexBarViewMargin , getMeasuredWidth()- mIndexBarViewMargin, getMeasuredHeight()- mIndexBarViewMargin); } if (mPreviewTextView != null && mPreviewVisibility) { mPreviewTextView.layout(mIndexBarView.getLeft()-mPreviewTextViewWidth, (int)mIndexBarY-(mPreviewTextViewHeight/2) , mIndexBarView.getLeft(), (int)(mIndexBarY-(mPreviewTextViewHeight/2))+mPreviewTextViewHeight); } } public void setIndexBarVisibility(Boolean isVisible) { if(isVisible) { mIndexBarVisibility=true; } else { mIndexBarVisibility=false; } } private void setPreviewTextVisibility(Boolean isVisible) { if(isVisible) { mPreviewVisibility=true; } else { mPreviewVisibility=false; } } public void configureHeaderView(int position) { if (mHeaderView == null) { return; } int state = mAdapter.getPinnedHeaderState(position); switch (state) { case IPinnedHeader.PINNED_HEADER_GONE: mHeaderVisibility = false; break; case IPinnedHeader.PINNED_HEADER_VISIBLE: if (mHeaderView.getTop() != 0) { mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); } mAdapter.configurePinnedHeader(mHeaderView, position); mHeaderVisibility = true; break; case IPinnedHeader.PINNED_HEADER_PUSHED_UP: View firstView = getChildAt(0); int bottom = firstView.getBottom(); // int itemHeight = firstView.getHeight(); int headerHeight = mHeaderView.getHeight(); int y; if (bottom < headerHeight) { y = (bottom - headerHeight); } else { y = 0; } if (mHeaderView.getTop() != y) { mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y); } mAdapter.configurePinnedHeader(mHeaderView, position); mHeaderVisibility = true; break; } } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas);// draw list view elements (zIndex == 1) if (mHeaderView != null && mHeaderVisibility) { drawChild(canvas, mHeaderView, getDrawingTime()); // draw pinned header view (zIndex == 2) } if (mIndexBarView != null && mIndexBarVisibility) { drawChild(canvas, mIndexBarView, getDrawingTime()); // draw index bar view (zIndex == 3) } if (mPreviewTextView != null && mPreviewVisibility) { drawChild(canvas, mPreviewTextView, getDrawingTime()); // draw preview text view (zIndex == 4) } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mIndexBarView != null && ((IndexBarView)mIndexBarView).onTouchEvent(ev)) { setPreviewTextVisibility(true); return true; } <span style="color:#ff0000;">else { if(ev.getAction() == MotionEvent.ACTION_UP) { setPreviewTextVisibility(false);//隐藏提示的textview invalidate(); } if(((IndexBarView)mIndexBarView).isTouchSide(ev)) return true;//如果点击的是侧边栏,就消化当前事件 return super.onTouchEvent(ev); }</span> } @Override public void filterList(float indexBarY, int position,String previewText) { this.mIndexBarY=indexBarY; if(mPreviewTextView instanceof TextView) ((TextView)mPreviewTextView).setText(previewText); setSelection(position); } }
2.IndexBarView.java
public class IndexBarView extends View { // index bar margin float mIndexbarMargin; // user touched Y axis coordinate value float mSideIndexY; // flag used in touch events manipulations boolean mIsIndexing = false; // holds current section position selected by user int mCurrentSectionPosition = -1; // array list to store section positions public ArrayList<Integer> mListSections; // array list to store listView data ArrayList<MusicInfor> mListItems; // paint object Paint mIndexPaint; // context object Context mContext; // interface object used as bridge between list view and index bar view for // filtering list view content on touch event IIndexBarFilter mIndexBarFilter; public IndexBarView(Context context) { super(context); this.mContext = context; } public IndexBarView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; } public IndexBarView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.mContext = context; } public void setData(PinnedHeaderListView listView, ArrayList<MusicInfor> listItems,ArrayList<Integer> listSections) { this.mListItems = listItems; this.mListSections = listSections; // list view implements mIndexBarFilter interface mIndexBarFilter = listView; // set index bar margin from resources mIndexbarMargin = mContext.getResources().getDimension(R.dimen.index_bar_view_margin); // index bar item color and text size mIndexPaint = new Paint(); mIndexPaint.setColor(mContext.getResources().getColor(R.color.text_black_off)); mIndexPaint.setAntiAlias(true); mIndexPaint.setTextSize(mContext.getResources().getDimension(R.dimen.index_bar_view_text_size)); } // draw view content on canvas using paint @Override protected void onDraw(Canvas canvas) { if (mListSections != null && mListSections.size() > 1) { float sectionHeight = (getMeasuredHeight() - 2 * mIndexbarMargin)/ mListSections.size(); float paddingTop = (sectionHeight - (mIndexPaint.descent() - mIndexPaint.ascent())) / 2; for (int i = 0; i < mListSections.size(); i++) { float paddingLeft = (getMeasuredWidth() - mIndexPaint.measureText(getSectionText(mListSections.get(i)))) / 2; canvas.drawText(getSectionText(mListSections.get(i)), paddingLeft, mIndexbarMargin + (sectionHeight * i) + paddingTop + mIndexPaint.descent(), mIndexPaint); } } super.onDraw(canvas); } public String getSectionText(int sectionPosition) { return mListItems.get(sectionPosition).getSortLetters(); } private 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 >= getLeft() && y >= getTop() && y <= getTop() + getMeasuredHeight()); } <span style="color:#ff0000;">public boolean isTouchSide(MotionEvent ev) { return contains(ev.getX(), ev.getY()); }</span> void filterListItem(float sideIndexY) { mSideIndexY = sideIndexY; // filter list items and get touched section position with in index bar mCurrentSectionPosition = (int) (((mSideIndexY) - getTop() - mIndexbarMargin) / ((getMeasuredHeight() - (2 * mIndexbarMargin)) / mListSections.size())); if (mCurrentSectionPosition >= 0 && mCurrentSectionPosition < mListSections.size()) { int position = mListSections.get(mCurrentSectionPosition); String previewText = mListItems.get(position).getSortLetters(); mIndexBarFilter.filterList(mSideIndexY, position, previewText); } } public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // If down event occurs inside index bar region, start indexing if (contains(ev.getX(), ev.getY())) { // 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 filterListItem(ev.getY()); return true; } else { mCurrentSectionPosition = -1; return false; } 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 filterListItem(ev.getY()); return true; } else { mCurrentSectionPosition = -1; return false; } } break; case MotionEvent.ACTION_UP: if (mIsIndexing) { mIsIndexing = false; mCurrentSectionPosition = -1; } break; } return false; } }
完整工程下载: http://download.csdn.net/detail/yuyan19850204/8619085
时间: 2024-11-07 22:52:49