XRecyclerView的使用&ListView|XRecyclerView有header时Position不对问题

来源:互联网 发布:mac读取不了移动硬盘 编辑:程序博客网 时间:2024/05/22 05:58

XRecyclerView

https://github.com/jianghejie/XRecyclerView

1.重点说一下ReclyclerView的Item事件    

Click and LongClick

不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。 
不过我们也可以自己去添加,只是会多了些代码而已。 
实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 
当然你也可以通过adapter中自己去提供回调,这里我们选择后者,前者的方式,大家有兴趣自己去实现。

那么代码也比较简单:

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{//...    public interface OnItemClickLitener    {        void onItemClick(View view, int position);        void onItemLongClick(View view , int position);    }    private OnItemClickLitener mOnItemClickLitener;    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)    {        this.mOnItemClickLitener = mOnItemClickLitener;    }    @Override    public void onBindViewHolder(final MyViewHolder holder, final int position)    {        holder.tv.setText(mDatas.get(position));        // 如果设置了回调,则设置点击事件        if (mOnItemClickLitener != null)        {            holder.itemView.setOnClickListener(new OnClickListener()            {                @Override                public void onClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemClick(holder.itemView, pos);                }            });            holder.itemView.setOnLongClickListener(new OnLongClickListener()            {                @Override                public boolean onLongClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);                    return false;                }            });        }    }//...}

adapter中自己定义了个接口,然后在onBindViewHolder中去为holder.itemView去设置相应 

的监听最后回调我们设置的监听。

最后别忘了给item添加一个drawable:

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" >    <item android:state_pressed="true" android:drawable="@color/color_item_press"></item>    <item android:drawable="@color/color_item_normal"></item></selector>


Activity中去设置监听:

<span style="font-size:14px;"> mAdapter.setOnItemClickLitener(new OnItemClickLitener()        {            @Override            public void onItemClick(View view, int position)            {                Toast.makeText(HomeActivity.this, position + " click",                        Toast.LENGTH_SHORT).show();            }            @Override            public void onItemLongClick(View view, int position)            {                Toast.makeText(HomeActivity.this, position + " long click",                        Toast.LENGTH_SHORT).show();                        mAdapter.removeData(position);            }        });</span>


2.ListView 

Google了下,发现有个老外issue过一个bug,和我遇到的问题一样,不过这个bug被RomainGuy reject掉了,理由是,你用错了,请用getAdapter。回答的太简洁了,完全没法理解,只好又去仔细研究ListView的代码,终于领会他的意思了。把其中addHeaderViewsetAdapter方法贴下来

复制代码
/** * Add a fixed view to appear at the top of the list. If addHeaderView is * called more than once, the views will appear in the order they were * added. Views added using this call can take focus if they want. * <p> * NOTE: Call this before calling setAdapter. This is so ListView can wrap * the supplied cursor with one that that will also account for header * views. * * @param v The view to add. * @param data Data to associate with this view * @param isSelectable whether the item is selectable */public void addHeaderView(View v, Object data, boolean isSelectable) {    if (mAdapter != null) {        throw new IllegalStateException(                "Cannot add header view to list -- setAdapter has already been called.");    }     FixedViewInfo info = new FixedViewInfo();    info.view = v;    info.data = data;    info.isSelectable = isSelectable;    mHeaderViewInfos.add(info);} /** * Sets the data behind this ListView. * * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, * depending on the ListView features currently in use. For instance, adding * headers and/or footers will cause the adapter to be wrapped. * * @param adapter The ListAdapter which is responsible for maintaining the *        data backing this list and for producing a view to represent an *        item in that data set. * * @see #getAdapter() */@Overridepublic void setAdapter(ListAdapter adapter) {    if (null != mAdapter) {        mAdapter.unregisterDataSetObserver(mDataSetObserver);    }     resetList();    mRecycler.clear();     if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {        mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);    } else {        mAdapter = adapter;    }     //其它的一些代码这里省略之...}
复制代码

从代码和注释里都可以很清楚的得知,addHeaderView一定要在setAdapter之前调用,如果不是,addHeaderView会抛出一个异常。Android为什么要这样做?因为,在setAdapter的时候,会针对我遇到的这种情况(也就是说,position不正确)做些特殊的处理。setAdapter在内部判断了当前ListView是否有Header或者Footer,如果没有,就直接使用参数传进来的adapter;如果有,则用一个decorated的HeaderViewListAdapter来替换参数。这个HeaderViewListAdapter的使命,就是排除Header和Footer,让position(当然也包括getItem, getItemId等)正确返回。

分析到这里,解决方案就出来了:不要直接使用我们声明的adapter,而是用ListView里的那个decorated adapter。获取它的方法就是调用getAdapter。当然,如果ListView没有Header和Footer,直接使用声明的adapter也没有问题,不过为了方便、避免以后出错,还是统一使用decorated adapter比较好。

把onItemClick改成下面这样,就可以了

@Overridepublic void onItemClick(AdapterView<?> parent, View v, int position, long id) {    doSomething(parent.getAdapter().getItem(position));}
3.recycle 没有实现点击事件但是 viewholder有 getPosition方法可以获得item的点击事件,

区别 getPosition() ,getLayoutPosition(),getAdapterPosition()

getPosition已经过时了

 那么比较 后面两者可以看getlayoutposition-vs-getadapterposition

0 0
原创粉丝点击