精华内容
下载资源
问答
  • RecyclerView使用详解

    2020-08-31 18:26:38
    本文主要对RecyclerView使用进行了详细介绍,文章结尾附上源码下载,具有一定的参考价值,下面跟着小编一起来看下吧
  • 这里我就不再过多的介绍RecyclerView,既然大家在找使用RecyclerView的demo想必大家都了解过了,如果不了解网上随便打开一篇RecyclerView的文章应该都有,已经烂大街,在此就不过多的重复了; 今天写的demo主要是...
  • 什么是RecyclerView 关于RecyclerView,是一个主要用于展示和回收View的有一个控件,在官用了一句话来概括 RecyclerView 是一种通过提供有限的数据项窗口有效显示大数据集的视图。 基提供几个基本的功能, 控制其...
  • 博文《First RecyclerView (RecyclerView使用详解)》源码,给出main文件夹下所有内容,开发者可以引入自己的项目中。
  • recyclerview使用详解

    2016-05-22 22:56:34
    mRecyclerView = findView(R.id.id_recyclerview); // 设置布局管理器 mRecyclerView.setLayoutManager(layout); // 设置 adapter mRecyclerView.setAdapter(adapter) // 设置 Item 增加、移除动画 ...

    recycler是5.0之后退出的替代listview和gridview的解决方案,可以通过导入support的V7包

    0.功能

    1layoutmanager布局管理器,设置显示方式

    2ItemDecoration 设置item间的间隔

    3ItemAnimator控制item增删的的动画

    4.(缺点)在adapter设置点击、长按事件ItemClickListenerItemLongClickListener


    1.在activity里面的配置

    mRecyclerView = findView(R.id.id_recyclerview);

    //设置布局管理器

    mRecyclerView.setLayoutManager(layout);

    //设置adapter

    mRecyclerView.setAdapter(adapter)

    //设置Item增加、移除动画

    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    //添加分割线

    mRecyclerView.addItemDecoration(new DividerItemDecoration(   getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

    2.adapter需要重写的方法

    getItemCount 这个不用说,获取总的条目数

    onCreateViewHolder 创建ViewHolder、创建setlistener的监听

    onBindViewHolder 将数据绑定至ViewHolder

    1.刷新--holder.updatePosition(position);

    2.定义视图与数据的绑定convert(holder, mDatas.get(position));
     
    

    3详细说明

    3.1布局管理器

    LinearLayoutManager 现行管理器,支持横向、纵向。

    GridLayoutManager 网格布局管理器

    StaggeredGridLayoutManager 瀑布就式布局管理器

    //mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

      mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));

    mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,        StaggeredGridLayoutManager.VERTICAL)); --可以横竖的,看你要哪个在后一个变量改

    3.2关于画分割线

    onDraw

    --drawchildren

    onDrawOver

    getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。 

    3.3动画设置

    // 设置item动画

    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    更新数据集不是用adapter.notifyDataSetChanged()而是

    notifyItemInserted(position)

    notifyItemRemoved(position)

    public void addData(int position) {

            mDatas.add(position, "Insert One");

            notifyItemInserted(position);

        }

        public void removeData(int position) {

                mDatas.remove(position);

            notifyItemRemoved(position);

    }

    4.点击事件的处理

    //...

        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;

                    }

                });

            }

        }

    //...

     

    关于activity的监听需要设置在activity里面

     

       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);

                }

            });

    viewholder里实现的方法

    get--获取viewholder

    getview--通过viewid获取控件

    getcontentview--获取重写的视图

    viewhodler的set子视图系列。。。

    设置时间点击时间---setOnClickListener等系列

    可选系列:

    updateposition---数据绑定onBindViewHolder方法至viewHolder的时候及时刷新

    getLayoutId--通过获取布局id,来变更item视图

    附加

    在定义不同布局时候的解决方法

    常见以下几类:

    简单的数据绑定(单种Item

    多种Item Type 数据绑定

    增加onItemClickListener , onItenLongClickListener

    优雅的添加分类header 

    那么解决方案是:

    设置一个多类型布局的支持接口,并定义重写布局和其中id的方法

    public interface MultiItemTypeSupport<T>
    {
       int getLayoutId(int itemType);
       int getItemViewType(int position, T t);
    }

    重写适配器2个方法

    getItemViewType
    onCreateViewHolder

    getLayoutId(需要在构造方法super里面实现)
    convert



    展开全文
  • Android RecyclerView使用详解

    万次阅读 2015-12-20 20:26:07
    上一篇介绍了RecyclerView自定义分隔图的代码绘制方式,本篇将在上篇的基础上讲解RecyclerView的header和footer的添加和设定,并且讲完header和footer,RecyclerView的基础内容就讲完了。 ok,废话少说。我们都知道...

    转载请注明:
    http://blog.csdn.net/sinat_30276961/article/details/50365513

    上一篇介绍了RecyclerView自定义分隔图的代码绘制方式,本篇将在上篇的基础上讲解RecyclerView的header和footer的添加和设定,并且讲完header和footer,RecyclerView的基础内容就讲完了。

    ok,废话少说。我们都知道,在ListView里添加header和footer是一件再简单不过的事情,秒秒钟搞定。那么在RecyclerView里添加呢?

    在前面几篇里,我已经讲过了,RecyclerView的大部分功能都分离出来了,需要我们自己去复写,然后添加进去。虽然增加了麻烦度,但是带来的是灵活和无限的创造性。所以,header和footer的添加也是需要我们自己去代码设定加进去的。

    我们再回忆一下RecyclerView创建需要的几个核心:
    LayoutManager(必须)
    ItemDecoration (非必须)
    Adapter(必须)
    ItemAnimator (非必须)

    那么,header和footer该怎么加进去呢?
    我们先来回忆一下RecyclerView.Adapter里包含的接口:

            public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
    
            public abstract void onBindViewHolder(VH holder, int position);
    
            public int getItemViewType(int position) {
                return 0;
            }
    
            public void setHasStableIds(boolean hasStableIds) {
                if (hasObservers()) {
                    throw new IllegalStateException("Cannot change whether this adapter has " +
                            "stable IDs while the adapter has registered observers.");
                }
                mHasStableIds = hasStableIds;
            }
    
            public long getItemId(int position) {
                return NO_ID;
            }
    
            public abstract int getItemCount();
    
            public void onViewRecycled(VH holder) {
            }
    
            public boolean onFailedToRecycleView(VH holder) {
                return false;
            }
    
            public void onViewAttachedToWindow(VH holder) {
            }
    
            public void onViewDetachedFromWindow(VH holder) {
            }
    
            public void registerAdapterDataObserver(AdapterDataObserver observer) {
                mObservable.registerObserver(observer);
            }
    
            public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
                mObservable.unregisterObserver(observer);
            }
    
            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            }
    
            public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
            }
    

    我把final的接口都摒弃掉了,上述接口是可以去复写的。从这些接口看,我们可以发现,一般情况,我们需要复写的接口不多,大致是如下几个:
    onCreateViewHolder
    onBindViewHolder
    getItemCount
    getItemId

    当然,如果你需要实现复杂的功能,可能还需要如下接口:
    getItemViewType(定义当前item的类型)
    onViewRecycled(当前item被回收时调用,可用来释放绑定在view上的大数据,比方说Bitmap)
    ……(太多。。)

    常用的接口,在前面几篇里已经都讲解过,这里重点讲下getItemViewType。

    为啥要说这个接口呢?其实要实现在RecyclerView里添加headerView和footerView,这个接口是必不可少的。
    getItemViewType是用来自己设定不同item的类型。既然如此,我们可以把header和footer看成是不同于一般item的类型不就行了。然后根据不同的viewType,我创建不同的view,也即是说,还需要修改
    onCreateViewHolder(创建不同view)
    onBindViewHolder(根据不同view,绑定不同数据)
    getItemCount(header和footer不应该在此数量里)
    getItemId(header占了index=0这个位置,所以需要调整)

    ok,基本思路有了,现在想下方案。根据上述理念,我们目前能很容易想到的有两套方案:
    1.在原先自己写的adapter里根据需要添加上header和footer。
    2.通过装饰模式,在新的adapter里添加header和footer。

    第一个方案,可行。
    But!
    要修改原来的代码,而且新改出来的adapter复用性差。
    第二个方案,可行。
    And!
    不需要改动原来的adapter,复用性大大的提高。

    鉴于此,我选择第二个方案(其实,你去看ListView的代码,你会发现,它添加header和footer的方式也是通过装饰模式的)。先来看看,我实现的添加headerView和footerView之后的效果:
    在这里插入图片描述
    这里添加的header和footer很简单,就是一个TextView。

    ok,接下去,就是代码部分。我先贴出Adapter的代码:

    public class HeaderRecyclerViewAdapter extends RecyclerView.Adapter{
        public static final int ITEM_VIEW_TYPE_HEADER = -2;
        public static final int ITEM_VIEW_TYPE_FOOTER = -3;
        public static final int ITEM_VIEW_TYPE_ITEM = 0;
    
        private RecyclerView.Adapter mAdapter;
    
        private View mHeaderView;
        private View mFooterView;
    
        public HeaderRecyclerViewAdapter(View headerView, View footerView, RecyclerView.Adapter adapter) {
            mHeaderView = headerView;
            mFooterView = footerView;
            mAdapter = adapter;
        }
    
        public RecyclerView.Adapter getWrappedAdapter() {
            return mAdapter;
        }
    
        public boolean hasHeaderView() {
            return mHeaderView != null;
        }
    
        public boolean hasFooterView() {
            return mFooterView != null;
        }
    
        public int headerViewHeight() {
            int height = 0;
            if (mHeaderView != null) {
                height = mHeaderView.getLayoutParams().height;
            }
            return height;
        }
    
        public int footerViewHeight() {
            int height = 0;
            if (mFooterView != null) {
                height = mFooterView.getLayoutParams().height;
            }
            return height;
        }
    
        @Override
        public int getItemViewType(int position) {
            if (mHeaderView != null) {
                if (position == 0) {
                    return ITEM_VIEW_TYPE_HEADER;
                } else {
                    final int adjPosition = position - 1;
                    int adapterCount = 0;
                    if (mAdapter != null) {
                        adapterCount = mAdapter.getItemCount();
                        if (adjPosition < adapterCount) {
                            return ITEM_VIEW_TYPE_ITEM;
                        }
                    }
                }
            } else {
                int adapterCount = 0;
                if (mAdapter != null) {
                    adapterCount = mAdapter.getItemCount();
                    if (position < adapterCount) {
                        return ITEM_VIEW_TYPE_ITEM;
                    }
                }
            }
    
            return ITEM_VIEW_TYPE_FOOTER;
        }
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == ITEM_VIEW_TYPE_HEADER) {
                return new HeaderViewHolder(mHeaderView);
            } else if (viewType == ITEM_VIEW_TYPE_FOOTER) {
                return new HeaderViewHolder(mFooterView);
            } else {
                return mAdapter.onCreateViewHolder(parent, viewType);
            }
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            final int viewType = getItemViewType(position);
            if (viewType == ITEM_VIEW_TYPE_HEADER || viewType == ITEM_VIEW_TYPE_FOOTER) {
                return;
            } else {
                int adjPosition = position;
                if (mHeaderView != null) {
                    adjPosition--;
                }
                mAdapter.onBindViewHolder(holder, adjPosition);
            }
        }
    
        @Override
        public int getItemCount() {
            if (mAdapter != null) {
                return (mHeaderView == null ? 0 : 1)
                        + (mFooterView == null ? 0 : 1)
                        + mAdapter.getItemCount();
            } else {
                return (mHeaderView == null ? 0 : 1)
                        + (mFooterView == null ? 0 : 1);
            }
        }
    
        @Override
        public long getItemId(int position) {
            final boolean hasHeader = (mHeaderView != null);
            final boolean hasFooter = (mFooterView != null);
    
            int adapterCount = 0;
            if (mAdapter != null) {
                adapterCount = mAdapter.getItemCount();
            }
            if (hasHeader) {
                if (position < adapterCount + 1) {
                    return position - 1;
                } else {
                    return ITEM_VIEW_TYPE_FOOTER;
                }
            } else {
                if (position < adapterCount) {
                    return position;
                } else {
                    return ITEM_VIEW_TYPE_FOOTER;
                }
            }
        }
    
        static class HeaderViewHolder extends RecyclerView.ViewHolder {
    
            public HeaderViewHolder(View itemView) {
                super(itemView);
            }
        }
    

    这部分代码其实不复杂,只要思路理清了,实现起来不麻烦。

    第2、3、4行,定义了几种viewType。可以看到header我是从-2开始的。这是因为-1是无效的item(INVALID_TYPE = -1)。当然,你也可以从1开始定义。
    第6行的mAdapter就是需要包装的原始adapter。
    第8、9行,我定义了一个headerView和footerView。在ListView里,可以添加多个headerView和footerView,这里,我就只实现添加一个header和footer。如果要和ListView一样,那就把View改为List< View >。
    第46-71行,复写了getItemViewType。在原始的position==0的位置,用来放置header;最后一个位置,用来放置footer。
    第74-82行,复写了onCreateViewHolder。根据不同的viewType,我创建不同的view和viewholder。
    第85-96行,复写了onBindViewHolder。如果viewType是header或者footer,就直接return。如果是一般的item,还需要调整下它的position。如果有header,原先的position还要-1。这样一来,在被装饰的原始adapter里,得到的position就已经排除了header的占位。

    后面的代码和上述差不多,就是把header和footer的情况特殊处理,这里就不讲了。

    接着,我贴下RecyclerView复写的代码:

    public class HeaderRecyclerView extends RecyclerView{
    
        private View mHeaderView;
        private View mFooterView;
    
        public HeaderRecyclerView(Context context) {
            super(context);
        }
    
        public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public void addHeaderView(View headerView) {
            mHeaderView = headerView;
        }
    
        public void addFooterView(View footerView) {
            mFooterView = footerView;
        }
    
        public void setAdapter(Adapter adapter) {
            if (mHeaderView == null && mFooterView == null) {
                super.setAdapter(adapter);
            } else {
                adapter = new HeaderRecyclerViewAdapter(mHeaderView, mFooterView, adapter);
                super.setAdapter(adapter);
            }
        }
    
        public void removeHeaderView() {
            mHeaderView = null;
        }
    
        public void removeFooterView() {
            mFooterView = null;
        }
    }
    

    上述代码就复写了setAdapter,代码很简单,不讲了。

    接着是额外的部分,我把分隔图也重新改了一下,为了适应多了个header和footer。
    先是HeaderLinearLayoutItemDecoration:

    public class HeaderLinearLayoutItemDecoration extends RecyclerView.ItemDecoration{
        final Context mContext;
        final int mOrientation;
        final Drawable mDividerDrawable;
        int mDividerHeight;
    
        private static final int[] ATTRS = new int[]{
                android.R.attr.listDivider,
                android.R.attr.dividerHeight
        };
    
        public HeaderLinearLayoutItemDecoration(Context context, int orientation) {
            mContext = context;
            mOrientation = orientation;
    
            TypedArray ta = context.obtainStyledAttributes(ATTRS);
            mDividerDrawable = ta.getDrawable(0);
            mDividerHeight = ta.getDimensionPixelSize(1, 1);
            ta.recycle();
        }
    
        public HeaderLinearLayoutItemDecoration(Context context, int orientation, int dividerHeight) {
            mOrientation = orientation;
            mContext = context;
            mDividerHeight = dividerHeight;
            TypedArray ta = context.obtainStyledAttributes(ATTRS);
            mDividerDrawable = ta.getDrawable(0);
            ta.recycle();
        }
    
        public HeaderLinearLayoutItemDecoration(Context context, int orientation, Drawable dividerDrawable, int dividerHeight) {
            mContext = context;
            mOrientation = orientation;
            mDividerDrawable = dividerDrawable;
            mDividerHeight = dividerHeight;
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            if (mOrientation == LinearLayoutManager.HORIZONTAL) {
                drawHorizontal(c, parent);
            } else {
                drawVertical(c, parent);
            }
        }
    
        private void drawHorizontal(Canvas c, RecyclerView parent) {
            final int top = parent.getPaddingTop();
            final int bottom = parent.getHeight()-parent.getPaddingBottom();
    
            final int count = parent.getChildCount();
            for (int i = 0; i < count; i++) {
                final View child = parent.getChildAt(i);
                final int position = parent.getChildAdapterPosition(child);
                final int viewType = parent.getAdapter().getItemViewType(position);
                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                    continue;
                }
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int left = child.getRight()+params.rightMargin;
                final int right = left+mDividerHeight;
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    
        private void drawVertical(Canvas c, RecyclerView parent) {
            final int left = parent.getPaddingLeft();
            final int right = parent.getWidth()-parent.getPaddingRight();
    
            final int count = parent.getChildCount();
            for (int i = 0; i < count; i++) {
                final View child = parent.getChildAt(i);
                final int position = parent.getChildAdapterPosition(child);
                final int viewType = parent.getAdapter().getItemViewType(position);
                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                    continue;
                }
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int top = child.getBottom()+params.bottomMargin;
                final int bottom = top + mDividerHeight;
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            final int position = parent.getChildAdapterPosition(view);
            final int viewType = parent.getAdapter().getItemViewType(position);
            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                return;
            }
            if (mOrientation == LinearLayoutManager.VERTICAL) {
                outRect.bottom = mDividerHeight;
            } else {
                outRect.right =  mDividerHeight;
            }
        }
    }
    

    代码其实和原先的LinearLayoutItemDecoration几乎一样,唯一的区别在于:我在drawHorizontal、drawVertical和getItemOffsets里在遍历child时,多加了个判断,如果是header或者footer,就不画不偏移。

    再贴出HeaderGridLayoutItemDecoration:

    public class HeaderGridLayoutItemDecoration extends RecyclerView.ItemDecoration{
        final Context mContext;
        final Drawable mDividerDrawable;
        int mDividerHeight;
    
        private static final int[] ATTRS = new int[] {
                android.R.attr.listDivider,
                android.R.attr.dividerHeight
        };
    
        public HeaderGridLayoutItemDecoration(Context context) {
            mContext = context;
            // 从主题去获取属性键值
            TypedArray ta = context.obtainStyledAttributes(ATTRS);
            mDividerDrawable = ta.getDrawable(0);
            mDividerHeight = ta.getDimensionPixelSize(1, 1);
            ta.recycle();
        }
    
        public HeaderGridLayoutItemDecoration(Context context, int height) {
            mContext = context;
            // 从主题去获取属性键值
            TypedArray ta = context.obtainStyledAttributes(ATTRS);
            mDividerDrawable = ta.getDrawable(0);
            mDividerHeight = height;
            ta.recycle();
        }
    
        public HeaderGridLayoutItemDecoration(Context context, Drawable drawable) {
            mContext = context;
            mDividerDrawable = drawable;
            TypedArray ta = context.obtainStyledAttributes(ATTRS);
            mDividerHeight = ta.getDimensionPixelSize(1, 1);
            ta.recycle();
        }
    
        public HeaderGridLayoutItemDecoration(Context context, Drawable drawable, int height) {
            mContext = context;
            mDividerDrawable = drawable;
            mDividerHeight = height;
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
            final int spanCount = manager.getSpanCount();
            drawHorizontal(c, parent, state, spanCount);
            drawVertical(c, parent, state, spanCount);
        }
    
        private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {
            final int count = parent.getChildCount();
            // 确定有几行
            final int rowCount = count/spanCount + (count%spanCount==0?0:1);
    
            final int left = parent.getPaddingLeft();
            final int right = parent.getWidth() - parent.getPaddingRight();
    
            for (int i = 0; i < rowCount; i++) {
                final View child = parent.getChildAt(i*spanCount);
                final int position = parent.getChildAdapterPosition(child);
                final int viewType = parent.getAdapter().getItemViewType(position);
                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                    continue;
                }
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mDividerHeight;
    
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    
        private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {
            final int count = parent.getChildCount();
            for (int i = 0; i < count; i++) {
                final View child = parent.getChildAt(i);
                final int position = parent.getChildAdapterPosition(child);
                final int viewType = parent.getAdapter().getItemViewType(position);
                if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                        || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                    continue;
                }
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mDividerHeight;
                final int top = child.getTop() - params.topMargin;
                final int bottom = child.getBottom() + params.bottomMargin + mDividerHeight;
    
                mDividerDrawable.setBounds(left, top, right, bottom);
                mDividerDrawable.draw(c);
            }
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
    
            final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
            final int spanCount = manager.getSpanCount();
            final int position = parent.getChildAdapterPosition(view);
            final int adjPosition = (int) parent.getAdapter().getItemId(position);
            final int count = parent.getAdapter().getItemCount();
            final int viewType = parent.getAdapter().getItemViewType(position);
            if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                    || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                return;
            }
            if ((adjPosition == count -1) && (adjPosition % spanCount) == (spanCount - 1)) {
                // 最后一个,如果也是最右边,那么就不需要偏移
            } else if (adjPosition >= (count - (count % spanCount))) {
                // 最下面一行,只要右边偏移就行
                outRect.right = mDividerHeight;
            } else if ((adjPosition % spanCount) == (spanCount - 1)) {
                // 最右边一列,只要下面偏移就行
                outRect.bottom = mDividerHeight;
            } else {
                // 其他的话,右边和下面都要偏移
                outRect.set(0, 0, mDividerHeight, mDividerHeight);
            }
        }
    }
    

    这里,思路和HeaderLinearLayoutItemDecoration一样,就是在画和设置偏移的地方多加个header和footer的判断。
    唯一不同的是,drawVertical和GridLayoutItemDecoration里的drawVertical不一样了。因为原先的实现方式是遍历span数量,并画spanCount数量的垂直drawable,并且是从屏幕最上方到屏幕最下方(parent.getPaddingTop和parent.getHeight() - parent.getPaddingBottom())。但是如果添加了header和footer,原先的方案就会使垂直drawable覆盖在header和footer上。并且如果是通过设置header和footer高度的偏移值来去掉header和footer那里的垂直drawable,也不好判断当前滑动位置是否包含header和footer,包含多少。所以,最好的方案是一个个item遍历画。

    ok,到目前为止,所有需要的角色都已经讲完了。接着就是测试代码了:

    public class AddHeaderViewTest extends ActionBarActivity {
    
        HeaderRecyclerView mHeaderRecyclerView;
        RecyclerViewAdapter mLinearLayoutAdapter;
        HeaderLinearLayoutItemDecoration mLinearLayoutItemDecoration;
        LinearLayoutManager mLinearLayoutManager;
    
        GridRecyclerViewAdapter mGridLayoutAdapter;
        HeaderGridLayoutItemDecoration mGridLayoutItemDecoration;
        GridLayoutManager mGridLayoutManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_add_header_view_test);
            mHeaderRecyclerView = (HeaderRecyclerView) findViewById(R.id.headerRecyclerView);
    
            mLinearLayoutManager = new LinearLayoutManager(this);
            mGridLayoutManager = new GridLayoutManager(this, 4);
            // grid类型,需要复写这个方法
            // 确定每个item的横跨span数
            mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);
                    if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                            || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                        return mGridLayoutManager.getSpanCount();
                    } else {
                        return 1;
                    }
                }
            });
            mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);
    
            mLinearLayoutItemDecoration = new HeaderLinearLayoutItemDecoration(this, LinearLayoutManager.VERTICAL, 4);
            mGridLayoutItemDecoration = new HeaderGridLayoutItemDecoration(this, 18);
            mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);
    
            // 添加header
            TextView headerView = new TextView(this);
            headerView.setText("Header");
            headerView.setTextColor(Color.GRAY);
            headerView.setTextSize(18);
            headerView.setGravity(Gravity.CENTER);
    
            ViewGroup.LayoutParams headerParams = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    DensityUtil.dpToPx(60, getResources())
            );
            headerView.setLayoutParams(headerParams);
            mHeaderRecyclerView.addHeaderView(headerView);
    
            // 添加footer
            TextView footerView = new TextView(this);
            footerView.setText("Footer");
            footerView.setTextColor(Color.GRAY);
            footerView.setTextSize(18);
            footerView.setGravity(Gravity.CENTER);
    
            ViewGroup.LayoutParams footerParams = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    DensityUtil.dpToPx(60, getResources())
            );
            footerView.setLayoutParams(footerParams);
            mHeaderRecyclerView.addFooterView(footerView);
    
            mLinearLayoutAdapter = new RecyclerViewAdapter(this, R.layout.item_normal_recycler_view, 50);
            mGridLayoutAdapter = new GridRecyclerViewAdapter(this, R.layout.item_recycler_view_grid, 100);
            mLinearLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();
                }
            });
            mGridLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();
                }
            });
            mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_add_header_view_test, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
    
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_switch) {
                if (mHeaderRecyclerView.getLayoutManager() == mLinearLayoutManager) {
                    mHeaderRecyclerView.setLayoutManager(mGridLayoutManager);
                    mHeaderRecyclerView.removeItemDecoration(mLinearLayoutItemDecoration);
                    mHeaderRecyclerView.addItemDecoration(mGridLayoutItemDecoration);
                    mHeaderRecyclerView.setAdapter(mGridLayoutAdapter);
                } else {
                    mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);
                    mHeaderRecyclerView.removeItemDecoration(mGridLayoutItemDecoration);
                    mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);
                    mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);
                }
                return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    }
    

    这部分代码和原先的差不多,唯一不同点在于布局文件里的RecyclerView要使用自定义的HeaderRecyclerView。

    还有一个地方是:

            // grid类型,需要复写这个方法
            // 确定每个item的横跨span数
            mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);
                    if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
                            || viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
                        return mGridLayoutManager.getSpanCount();
                    } else {
                        return 1;
                    }
                }
            });
    

    对于GridLayoutManager,你需要通过setSpanSizeLookup复写getSpanSize这个接口。这个是用来确定每个item占据的span数量。默认情况下,返回的是1,也就是每个item占据1个span。

    对于header和footer这两个item,每个都需要占据spanCount数量的span。

    好了,关于RecyclerView添加headerView和footerView部分讲解完了。并且,RecyclerView的基础部分都讲解完了。

    Have a good night!

    展开全文
  • RecyclerView是谷歌V7包下新增的控件,用来替代ListView的使用,在RecyclerView标准化了ViewHolder类似于ListView中convertView用来做视图缓. 先来说说RecyclerView的有点就是,他可以通过设置LayoutManager来快速实现...

    一、前言

    RecyclerView是谷歌V7包下新增的控件,用来替代ListView的使用,在RecyclerView标准化了ViewHolder类似于ListView中convertView用来做视图缓.

    先来说说RecyclerView的有点就是,他可以通过设置LayoutManager来快速实现listview、gridview、瀑布流的效果,而且还可以设置横向和纵向显示,添加动画效果也非常简单(自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果),也是官方推荐使用的.以下是官方的说明:

    RecyclerView is a more advanced and flexible version of ListView. This widget is a container for large sets of views that can be recycled and scrolled very efficiently. Use the RecyclerView widget when you have lists with elements that change dynamically. 简单说就是当你需要动态展示一组数据的时候就会需要用到它。

    讲了这么多虚的,接下来我们看看在代码中怎么来实现.

    二、实现

    首先要用这个控件,你需要在gradle文件中添加包的引用(配合官方CardView使用)

    compile 'com.android.support:cardview-v7:21.0.3'
    compile 'com.android.support:recyclerview-v7:21.0.3'

    然后是在XML文件用使用它

    <android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/recycler_view"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"/>
    

    接着在Activity中设置它

    public class MainActivity extends ActionBarActivity {
    @InjectView(R.id.recycler_view)
    RecyclerView mRecyclerView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.inject(this);
    
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));//这里用线性显示 类似于listview
    //        mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));//这里用线性宫格显示 类似于grid view
    //        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//这里用线性宫格显示 类似于瀑布流
    mRecyclerView.setAdapter(new NormalRecyclerViewAdapter(this));
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    
    if (id == R.id.action_settings) {
    return true;
    }
    
    return super.onOptionsItemSelected(item);
    }
    }

    然后是适配器代码:

    public class NormalRecyclerViewAdapter extends RecyclerView.Adapter<NormalRecyclerViewAdapter.NormalTextViewHolder> {
    private final LayoutInflater mLayoutInflater;
    private final Context mContext;
    private String[] mTitles;
    
    public NormalRecyclerViewAdapter(Context context) {
    mTitles = context.getResources().getStringArray(R.array.titles);
    mContext = context;
    mLayoutInflater = LayoutInflater.from(context);
    }
    
    @Override
    public NormalTextViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new NormalTextViewHolder(mLayoutInflater.inflate(R.layout.item_text, parent, false));
    }
    
    @Override
    public void onBindViewHolder(NormalTextViewHolder holder, int position) {
    holder.mTextView.setText(mTitles[position]);
    }
    
    @Override
    public int getItemCount() {
    return mTitles == null ? 0 : mTitles.length;
    }
    
    public static class NormalTextViewHolder extends RecyclerView.ViewHolder {
    @InjectView(R.id.text_view)
    TextView mTextView;
    
    NormalTextViewHolder(View view) {
    super(view);
    ButterKnife.inject(this, view);
    view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    Log.d("NormalTextViewHolder", "onClick--> position = " + getPosition());
    }
    });
    }
    }
    }

    三、效果图

    LinearLayoutManager样式

    GridLayoutManager样式

    最后给出代码下载地址–>Demo Code

    RecyclerView使用详解(二)

    RecyclerView使用详解(三)

    展开全文
  • RecyclerView使用详解(三)

    千次阅读 2016-03-03 15:23:42
    在上一篇(RecyclerView使用详解(二))文章中介绍了RecyclerView的多Item布局实现,接下来要来讲讲RecyclerView的Cursor实现,相较于之前的实现,Cursor有更多的使用场景,也更加的常用,特别是配合LoaderManager...

    在上一篇(RecyclerView使用详解(二))文章中介绍了RecyclerView的多Item布局实现,接下来要来讲讲RecyclerView的Cursor实现,相较于之前的实现,Cursor有更多的使用场景,也更加的常用,特别是配合LoaderManager和CursorLoader进行数据的缓存及加载显示,基于此我们来重点看看RecyclerView的CursorAdapter具体要怎么实现。

    一、CursorAdapter实现(配合LoaderManager和CursorLoader)

    如果之前你用过ListView实现过此功能(CursorAdapter),那么你一定对下面这两个方法并不陌生

    @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return null;
        }
    
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
    
        }

    其中newView方法是用来创建Item布局的,bindView 方法是用来绑定当前View数据的,就相当于之前的getView方法拆成了两个方法实现。

    如果你用RecyclerView,你会发现CursorAdapter这个类没有了,既然没有了,那我们就自己仿照着ListView的CursorAdapter类来实现,具体的代码没什么大的出入,无非就是注册两个观察者去监听数据库数据的变化,但是有两个地方需要注意一下,一个就是hasStableIds() 这个方法RecyclerView.Adapter中不能复写父类的方法,需要在初始化的时候调用setHasStableIds(true); 来完成相同功能,第二个就是notifyDataSetInvalidated() 这个方法没有,统一修改成notifyDataSetChanged() 方法即可。

    void init(Context context, Cursor c, int flags) {
            boolean cursorPresent = c != null;
            mCursor = c;
            mDataValid = cursorPresent;
            mContext = context;
            mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
            if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
                mChangeObserver = new ChangeObserver();
                mDataSetObserver = new MyDataSetObserver();
            } else {
                mChangeObserver = null;
                mDataSetObserver = null;
            }
    
            if (cursorPresent) {
                if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver);
            }
    
            setHasStableIds(true);//这个地方要注意一下,需要将表关联ID设置为true
        }
    
        //************//
        public Cursor swapCursor(Cursor newCursor) {
            if (newCursor == mCursor) {
                return null;
            }
            Cursor oldCursor = mCursor;
            if (oldCursor != null) {
                if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
                if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
            }
            mCursor = newCursor;
            if (newCursor != null) {
                if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
                mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
                mDataValid = true;
                // notify the observers about the new cursor
                notifyDataSetChanged();
            } else {
                mRowIDColumn = -1;
                mDataValid = false;
                // notify the observers about the lack of a data set
                //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
                notifyDataSetChanged();//注意此处
            }
            return oldCursor;
        }
        //************//
        private class MyDataSetObserver extends DataSetObserver {
            @Override
            public void onChanged() {
                mDataValid = true;
                notifyDataSetChanged();
            }
    
            @Override
            public void onInvalidated() {
                mDataValid = false;
                //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
                notifyDataSetChanged();//注意此处
            }
        }

    怎么样,是不是很简单,没错,就是这么简单,这里是完整的BaseAbstractRecycleCursorAdapter代码,用法和ListView的CursorAdapter用法一致,具体的可以看看我的Recyclerview LoaderManager Provider

    二、Item的动画实现

    RecyclerView本身就已经实现了ITEM的动画,只需要调用以下几个函数来增删Item即可出现默认动画。

    notifyItemChanged(int)
         notifyItemInserted(int)
         notifyItemRemoved(int)
         notifyItemRangeChanged(int, int)
         notifyItemRangeInserted(int, int)
         notifyItemRangeRemoved(int, int)

    怎么样,是不是很轻松,如果你不满足系统默认动画,那么你可以自定义实现RecyclerView.ItemAnimator的接口方法,实现代码可以参考DefaultItemAnimator.当然,如果你不想自己实现,那么也没关系,这里有人已经写了开源库,你可以去看看recyclerview-animators,这里给出默认动画实现方式代码AnimFragment

    三、嵌套RecycleView

    一般是不推荐使用嵌套RecycleView的,和ListView是类似的,遇到这种需要嵌套的View一般都是想别的办法来规避,比如动态AddView,或者通过RecycleView的MultipleItemAdapter来实现,通过设置不同的ItemType布局不同的View,但是有时候会闲麻烦,想直接就用嵌套的方式来做,那么和ListView实现方式不同的是,ListView的实现一般都是继承ListView然后复写onMeasure方法,如下所示:

    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }

    但是RecycleView的实现方式不再是继承RecycleView来做,而是通过修改LayoutManager的方式,即通过继承LinearLayoutManager GridLayoutManager StaggeredGridLayoutManager来修改子控件的测量,下面给出主要代码:

    FullyLinearLayoutManager

    private int[] mMeasuredDimension = new int[2];
    
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                              int widthSpec, int heightSpec) {
    
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            Log.i(TAG, "onMeasure called. \nwidthMode " + widthMode
                    + " \nheightMode " + heightSpec
                    + " \nwidthSize " + widthSize
                    + " \nheightSize " + heightSize
                    + " \ngetItemCount() " + getItemCount());
    
            int width = 0;
            int height = 0;
            for (int i = 0; i < getItemCount(); i++) {
                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
    
                if (getOrientation() == HORIZONTAL) {
                    width = width + mMeasuredDimension[0];
                    if (i == 0) {
                        height = mMeasuredDimension[1];
                    }
                } else {
                    height = height + mMeasuredDimension[1];
                    if (i == 0) {
                        width = mMeasuredDimension[0];
                    }
                }
            }
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                       int heightSpec, int[] measuredDimension) {
            try {
                View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
    
                if (view != null) {
                    RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
    
                    int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                            getPaddingLeft() + getPaddingRight(), p.width);
    
                    int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                            getPaddingTop() + getPaddingBottom(), p.height);
    
                    view.measure(childWidthSpec, childHeightSpec);
                    measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
                    measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
                    recycler.recycleView(view);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }

    FullyGridLayoutManager

    private int[] mMeasuredDimension = new int[2];
    
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            int width = 0;
            int height = 0;
            int count = getItemCount();
            int span = getSpanCount();
            for (int i = 0; i < count; i++) {
                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
    
                if (getOrientation() == HORIZONTAL) {
                    if (i % span == 0) {
                        width = width + mMeasuredDimension[0];
                    }
                    if (i == 0) {
                        height = mMeasuredDimension[1];
                    }
                } else {
                    if (i % span == 0) {
                        height = height + mMeasuredDimension[1];
                    }
                    if (i == 0) {
                        width = mMeasuredDimension[0];
                    }
                }
            }
    
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                       int heightSpec, int[] measuredDimension) {
            if (position < getItemCount()) {
                try {
                    View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
                    if (view != null) {
                        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
                        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                                getPaddingLeft() + getPaddingRight(), p.width);
                        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                                getPaddingTop() + getPaddingBottom(), p.height);
                        view.measure(childWidthSpec, childHeightSpec);
                        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
                        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
                        recycler.recycleView(view);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    四、效果图如下:

    Item默认动画效果

    嵌套ScrollView效果

    最后给出代码下载地址-->Demo Code

    RecyclerView使用详解(一)

    RecyclerView使用详解(二)

    展开全文
  • 转自:...在上一篇(RecyclerView使用详解(一))文章中简单的介绍了RecyclerView的基本用法,接下来要来讲讲RecyclerView的更多用法,要实现不同的功能效果,大部分都还是在于RecyclerView的Adapter写
  • 在上一篇(RecyclerView使用详解(一))文章中简单的介绍了RecyclerView的基本用法,接下来要来讲讲RecyclerView的更多用法,要实现不同的功能效果,大部分都还是在于RecyclerView的Adapter写法,所以我们着重来看...
  • Android RecyclerView最全使用详解

    万次阅读 多人点赞 2020-04-27 00:57:05
    本文目录RecyclerView概述RecyclerView使用-基础篇第一步:添加RecyclerView第二步:添加布局文件第三步:添加逻辑代码运行效果RecyclerView使用-进阶篇布局管理器线性布局管理器网格布局管理器ItemDecorationItem ...
  • RecyclerView使用详解 各种布局

    千次阅读 2018-07-11 15:47:22
    RecyclerView是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本。 官方介绍RecyclerView为在有限的窗口展现大量数据的控件。拥有类似功能的控件有ListView、GridView以及被Google遗弃的Gallery等...
  • 话说RecyclerView已经面市很久,也在很多应用中得到广泛的使用,在整个开发者圈子里面也拥有很不错的口碑,那说明RecyclerView拥有比ListView,GridView之类控件有很多的优点,例如:数据绑定,Item View创建,View的...
  • RecyclerView是Android 5.0推出的,是support-v7包中的新组件,它可以用来代替ListView和GridView,并且能够实现瀑布流的布局,更加高级并且更加灵活,提供更为高效的回收复用机制,同时实现管理与视图的解耦合。...
  • 1. RecyclerView是什么?根据Google官方给出的说明: A flexible view for providing a...所以我们能够理解为,RecyclerView的一个恰当的使用场景是:由于尺寸限制,用户的设备不能一次性展现所有条目,用户需要上下滚

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,298
精华内容 1,719
关键字:

recyclerview使用详解