1. 程式人生 > >關於開源專案側邊欄字母搜尋列表ListViewFilter的bug解決辦法

關於開源專案側邊欄字母搜尋列表ListViewFilter的bug解決辦法

很多人用過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