关于开源项目侧边栏字母搜索列表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

时间: 2024-08-27 22:23:17

关于开源项目侧边栏字母搜索列表ListViewFilter的bug解决办法的相关文章

vs项目,点击.sln文件时出错:“项目所需的应用程序未安装,确保已安装项目类型(.csproj)的应用程序”解决办法

关键词:VS2005程序用VS2008打开 程序无法使用 项目所需的应用程序未安装,确保已安装项目类型(.csproj)的应用程序 在要打开的项目sln文件上右键,打开方式,不要用Micrisoft visual studio version selector,用D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe打开. vs项目,点击.sln文件时出错:"项目所需的应用程序未安装,确保已安装项目类型(.cspro

linux上项目报错找不到主机名解决办法

项目报错找不到主机名解决办法 有时候我们的项目在本地运行没问题,但部署到linux服务器上就出错了. 报错:java.net.UnknownHostException: 主机名: 主机名  找不到主机名. 解决方法: 修改服务器上/etc/hosts文件 127.0.0.1  localhost  localhost.localdomain 添加所需的主机名称 或者 127.0.0.1  localhost  localhost.localdomain 127.0.0.1  添加所需的主机名称

项目适配iOS9遇到的一些问题及解决办法

1.网络请求报错.升级Xcode 7.0发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. 原因:iOS9引入了新特性App Transport Security (ATS).详情:App Transport Security (ATS)新特性要求App内访问的网络必须使用HTTPS协议

项目适配iOS9遇到的一些问题及解决办法(更新两个小问题)

本文转载至 http://www.bubuko.com/infodetail-1110714.html http://www.jianshu.com/p/631bd7f12a38 1.网络请求报错.升级Xcode 7.0发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. 原因:iOS9引

项目适配iOS9遇到的一些问题及解决办法 ,以及URL 白名单配置方法

1.网络请求报错.升级Xcode 7.0发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. 原因:iOS9引入了新特性App Transport Security (ATS).详情:App Transport Security (ATS)新特性要求App内访问的网络必须使用HTTPS协议

Linux下开源可视化工具Caravel安装(包含缺少js解决办法)

一.Caravel介绍 Caravel 是 Airbnb (知名在线房屋短租公司)开源的数据探查与可视化平台(曾用名Panoramix),该工具在可视化.易用性和交互性上非常有特色,用户可以轻松对数据进行可视化分析.最重要的是基于BS的 使用方法可以参考:http://lxw1234.com/archives/2016/06/691.htm 安装后的运行效果如下: 二.安装步骤 安装步骤分为以下几个部分: 1.安装python 由于centos自带的python是2.6.6版本的,但是carav

maven的java web项目启动找不到Spring ContextLoaderListener的解决办法

用maven搭建的java web项目,上传到git仓库后,当同事clone下来项目,部署到tomcat运行时,就报了如下错误,即启动web项目时,加载web.xml文件,找不到spring的监听器,控制台错误如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

.Net Framework项目引用.NetStandard标准库出现版本冲突解决办法

今天在工作中出现一个引用问题,害我找问题找了很久.起因是在一个Winform项目下需要引用一个.NetStandard标准库,标准库引用了System.ComponentModel.Annotations程序集,版本是4.5.0,在Winform项目运行过程中抛出了以下异常: “未能加载文件或程序集“System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3

VUE项目 启动提示 npn ERRT nissing script: dev解决办法

VUE项目 启动提示 npn ERRT nissing script: dev 提示 丢失 dev 解决办法 首先 查看项目目录里面的 package.json 文件, 文件内容如下: 发现红框这里是 server  那么就重新运行 cmd     重启命令:npm  run serve 如果上面红框是 dev   那么就重新运行 cmd           重启命令:cnpm run dev. 以上两步都是在依赖包安装的情况下就行 如果不放心依赖包是否完整 那就重新安装如下:  第一种情况se