RecyclerView使用问题

出现support.v4.xxx.ArrayMap not found 其实使用v4包错误,正确的包在下载资源中,这种是引入jar包的形式,觉得lib包太麻烦,我把v4,和 recyclerview的v7包一起传上去。


下面是使用教程,转载的:

首先,要导入support-v7 包

import android.support.v7.widget.RecyclerView;

RecyclerView和ListView的使用一样,都需要有对应的Adapter,列表项布局,数据源

1.先写主Activity布局

可以看到RecyclerView的标签

<android.support.v7.widget.RecyclerView>

 

复制代码
 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2               xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
 3               android:layout_width="match_parent"
 4               android:layout_height="match_parent"
 5               android:orientation="vertical"
 6               tools:context="com.xqx.superapp.app.Android5Activity">
 7 
 8     <Button
 9             android:text="添加一个数据"
10             android:layout_width="wrap_content"
11             android:layout_height="wrap_content"
12             android:onClick="btnAddItem"
13             />
14     <Button
15             android:text="删除第一个"
16             android:onClick="btnRemoveItem"
17             android:layout_width="wrap_content"
18             android:layout_height="wrap_content"/>
19     
20     <android.support.v7.widget.RecyclerView
21         android:id="@+id/recycle_view"
22         android:layout_width="match_parent"
23         android:layout_height="match_parent"
24         >
25     </android.support.v7.widget.RecyclerView>
26 
27 </LinearLayout>
复制代码

 

菜单项布局,标准的上面图片,下面文字

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:gravity="center"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
        <ImageView
                android:id="@+id/item_icon"
                android:src="@mipmap/machao_moqi"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:id="@+id/item_title"
                android:text="名称"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
</LinearLayout>
复制代码

 

2.接下来就看Activity代码了

首先看成员变量,与ListView,GridView一样 标准三样, 控件,数据源,适配器

private List<String> data;          
private RecyclerView recyclerView;
private MyRecycleAdapter adapter;   //自定义适配器,继承RecyclerView.Adapter

 

接着我们必须要自定义一个ViewHolder,这个ViewHolder 必须要继承 RecyclerView.ViewHolder

注意RecyclerView不再提供onItemClick事件监听,所以需要我们自己手工写监听事件的方法

复制代码
private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public ImageView imageView;
        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            // 通常ViewHolder的构造,就是用于获取控件视图的
            imageView = (ImageView) itemView.findViewById(R.id.item_icon);
            textView = (TextView) itemView.findViewById(R.id.item_title);
            // TODO 后续处理点击事件的操作
            itemView.setOnClickListener(this);

        }
        @Override
        public void onClick(View v) {
            int position = getAdapterPosition();
            Context context = imageView.getContext();
            Toast.makeText(context,"显示第"+position+"个项",Toast.LENGTH_SHORT).show();
        }
    }
复制代码

 

再让我们看自定义适配器,注意这里的参数是ViewHolder,这个ViewHodler是我们自己的,不要导入v7包下的ViewHolder,

之后要重写三个方法

复制代码
private class MyRecycleAdapter extends RecyclerView.Adapter<ViewHolder>{
  
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return null;
}

@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {

}

@Override
public int getItemCount() {
return 0;
}

}
复制代码

在自定义适配器MyRecycleAdapter中,首先要写一个构造方法,因为有数据源,所有构造方法里必然有List

private List<String> strings;
public MyRecycleAdapter(List<String> strings) {
     this.strings = strings;
}

然后就要重写三个方法了,

复制代码
 1 @Override
 2 public int getItemCount() {
 3     int ret = 0;
 4     if (strings != null) {
 5         ret = strings.size();
 6      }
 7         return ret;
 8 }
 9 
10  @Override
11         public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
12             ViewHolder ret = null;
13             // 不需要检查是否复用,因为只要进入此方法,必然没有复用
14             // 因为RecyclerView 通过Holder检查复用
15             View v = LayoutInflater.from(Android5Activity.this).inflate(R.layout.item_recycler, viewGroup, false);
16             ret = new ViewHolder(v);
17             return ret;
18         }
19 
20 @Override
21         public void onBindViewHolder(ViewHolder viewHolder, int i) {
22             // 1.这里进行图片的加载
23             viewHolder.textView.setText(strings.get(i));
24             int resId = R.mipmap.ic_launcher;
25             int index = i%5;
26             switch (index){
27                 case 0:
28                     resId = R.mipmap.a11;
29                     break;
30                 case 1:
31                     resId = R.mipmap.a33;
32                     break;
33                 case 2:
34                     resId = R.mipmap.a22;
35                     break;
36             }
37             viewHolder.imageView.setImageResource(resId);
38         }
复制代码

 

---------------------------------------------------------------------------------------------------------------

完成自定义适配器和自定义ViewHolder的代码 就要进行RecyclerView的使用了

首先 要了解  RecyclerView.LayoutManager 这个属性

用于进行一个布局的设置,可以设置显示模式,ListView或者GridView或者瀑布流

1.ListView显示模式

1 // 1.线性布局
2         LinearLayoutManager layoutManager =
3                 new LinearLayoutManager(this,   // 上下文
4                                         LinearLayout.VERTICAL,  //垂直布局,
5                                         false);

                                    

2.GridView显示模式

复制代码
1 // 2.Grid布局
2         RecyclerView.LayoutManager layoutManager =
3                 new GridLayoutManager(this,
4                                       2,  // 每行显示item项数目
5                                       GridLayoutManager.HORIZONTAL, //水平排列
6                                       false
7                                       );
复制代码

                                    

3.瀑布流显示模式

1 // 3.瀑布流
2         RecyclerView.LayoutManager layoutManager =
3                 new StaggeredGridLayoutManager(3,  // 每行显示的item项数目
4                         StaggeredGridLayoutManager.VERTICAL);  // 垂直排列

 

以上三种显示模式任意设置一种 就可以继续下面的代码

recyclerView.setLayoutManager(layoutManager);
        // 设置 RecyclerView的Adapter
        // 注意一定在设置了布局管理器之后调用
        adapter = new MyRecycleAdapter(data);
        recyclerView.setAdapter(adapter);

 

最后记得加上“添加一个数据”,“删除第一个数据”的按钮响应事件。

首先看一下以往我们对listview,gridview等等的删除某一项的操作

先在数据源中删除该位置的数据,然后刷新整个适配器,那么就可能会造成列表闪屏的问题,还有为了删除添加一个数据项而操作整个数据源的问题

public void btnAddItem(View view) {
        data.add(0,"Time:"+System.currentTimeMillis());
        adapter.notifyDataSetChanged();
    }
复制代码
    public void btnRemoveItem(View view) {
        if (!data.isEmpty()) {
            data.remove(0);
        }
        adapter.notifyItemRemoved(0);
    }
复制代码

 而RecyclerView为我们提供了一些新的实用的方法:

复制代码
public void add(ViewModel item, int position) {
    items.add(position, item);    //数据源先添加该数据
    notifyItemInserted(position); //在某个位置刷新即可
}
 
public void remove(ViewModel item) {
    int position = items.indexOf(item);
    items.remove(position);      //数据源先删除该数据
    notifyItemRemoved(position); //在某个位置删除即可
}
复制代码

 

完整代码:

复制代码
  1 package com.xqx.superapp.app;
  2 
  3 import android.app.Activity;
  4 import android.content.Context;
  5 import android.support.v7.app.ActionBarActivity;
  6 import android.os.Bundle;
  7 import android.support.v7.widget.GridLayoutManager;
  8 import android.support.v7.widget.LinearLayoutManager;
  9 import android.support.v7.widget.RecyclerView;
 10 import android.support.v7.widget.StaggeredGridLayoutManager;
 11 import android.util.Log;
 12 import android.view.*;
 13 import android.widget.*;
 14 
 15 import java.util.LinkedList;
 16 import java.util.List;
 17 
 18 
 19 public class Android5Activity extends Activity {
 20 
 21     private List<String> data;
 22     private RecyclerView recyclerView;
 23     private MyRecycleAdapter adapter;
 24 
 25     @Override
 26     protected void onCreate(Bundle savedInstanceState) {
 27         super.onCreate(savedInstanceState);
 28         setContentView(R.layout.activity_android5);
 29         data = new LinkedList<String>();
 30         recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
 31         // 设置布局管理器
 32         // 支持 单列线性排列,支持GridView模式,瀑布流模式
 33         // 1.线性布局
 34         LinearLayoutManager layoutManager =
 35                 new LinearLayoutManager(this,   // 上下文
 36                                         LinearLayout.VERTICAL,  //垂直布局,
 37                                         false);
 38 
 39 //        // 2.Grid布局
 40 //        RecyclerView.LayoutManager layoutManager =
 41 //                new GridLayoutManager(this,
 42 //                                      2,
 43 //                                      GridLayoutManager.HORIZONTAL,
 44 //                                      false
 45 //                                      );
 46 //
 47 //         // 3.瀑布流
 48 //        RecyclerView.LayoutManager layoutManager =
 49 //                new StaggeredGridLayoutManager(3,
 50 //                        StaggeredGridLayoutManager.VERTICAL);
 51         recyclerView.setLayoutManager(layoutManager);
 52         // 设置 RecyclerView的Adapter
 53         // 注意一定在设置了布局管理器之后调用
 54         adapter = new MyRecycleAdapter(data);
 55         recyclerView.setAdapter(adapter);
 56     }
 57 
 58     public void btnAddItem(View view) {
 59         data.add(0,"Time:"+System.currentTimeMillis());
 60         adapter.notifyDataSetChanged();
 61     }
 62 
 63     public void btnRemoveItem(View view) {
 64         if (!data.isEmpty()) {
 65             data.remove(0);
 66         }
 67         adapter.notifyItemRemoved(0);
 68     }
 69 
 70     /**
 71      * 继承RecyclerView.Adapter,用于显示数据
 72      * 需要定义并且使用 ViewHolder ,必须要使用
 73      */
 74     private class MyRecycleAdapter extends RecyclerView.Adapter<ViewHolder>{
 75         private List<String> strings;
 76         public MyRecycleAdapter(List<String> strings) {
 77             this.strings = strings;
 78         }
 79 
 80         @Override
 81         public int getItemCount() {
 82             int ret = 0;
 83             if (strings != null) {
 84                 ret = strings.size();
 85             }
 86             return ret;
 87         }
 88 
 89         @Override
 90         public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
 91             ViewHolder ret = null;
 92             // 不需要检查是否复用,因为只要进入此方法,必然没有复用
 93             // 因为RecyclerView 通过Holder检查复用
 94             View v = LayoutInflater.from(Android5Activity.this).inflate(R.layout.item_recycler, viewGroup, false);
 95             ret = new ViewHolder(v);
 96             return ret;
 97         }
 98 
 99         @Override
100         public void onBindViewHolder(ViewHolder viewHolder, int i) {
101             viewHolder.textView.setText(strings.get(i));
102             int resId = R.mipmap.ic_launcher;
103             int index = i%5;
104             switch (index){
105                 case 0:
106                     resId = R.mipmap.a11;
107                     break;
108                 case 1:
109                     resId = R.mipmap.a33;
110                     break;
111                 case 2:
112                     resId = R.mipmap.a22;
113                     break;
114             }
115             viewHolder.imageView.setImageResource(resId);
116         }
117     }
118 
119     /**
120      * 创建自己的ViewHolder ,必须要继承RecyclerView.ViewHolder
121      */
122     private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
123         public ImageView imageView;
124         public TextView textView;
125 
126         public ViewHolder(View itemView) {
127             super(itemView);
128             // 通常ViewHolder的构造,就是用于获取控件视图的
129             imageView = (ImageView) itemView.findViewById(R.id.item_icon);
130             textView = (TextView) itemView.findViewById(R.id.item_title);
131             // TODO 后续处理点击事件的操作
132             itemView.setOnClickListener(this);
133 
134         }
135         @Override
136         public void onClick(View v) {
137             int position = getAdapterPosition();
138             Context context = imageView.getContext();
139             Toast.makeText(context,"显示第"+position+"个项",Toast.LENGTH_SHORT).show();
140         }
141     }
142 }
 
  
特别要注意的是 使用RecyclerView时 要将setLayoutManager()放在初始化过程或者程序执行过程中,不要放在回调函数,触发事件里,因为RecyclerView在释放时没有对mLayout做非空判断,报错信息为:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 
'void android.support.v7.widget.RecyclerView$LayoutManager.stopSmoothScroller()
源码如下:
 protected void onDetachedFromWindow()
  {
    super.onDetachedFromWindow();
    if (this.mItemAnimator != null) {
      this.mItemAnimator.endAnimations();
    }
    this.mFirstLayoutComplete = false;


    stopScroll();
    this.mIsAttached = false;
    if (this.mLayout != null) {
      this.mLayout.onDetachedFromWindow(this, this.mRecycler);
    }
    removeCallbacks(this.mItemAnimatorRunner);
  }
 
  
public void stopScroll()
  {
    setScrollState(0);
    stopScrollersInternal();
  }
 
  
  private void stopScrollersInternal()
  {
    this.mViewFlinger.stop();
    this.mLayout.stopSmoothScroller();
  }
 
  
最后就是 mLayout is null.
 
  
 
  
当使用到嵌套的recyclerView的时候 如果recyclerView 控件显示不出来,一定要检查recyclerView的高度是否设置了值,设定值仅限于某些部分需求,比如对高度不需要自适应的,如果需要自适应,还是得用warp_content修饰,接着 写一个子类LayoutManager 继承你需要实现的LayoutManager
下面是网上找的一些例子:
 
  
public class FullyLinearLayoutManager extends LinearLayoutManager {

    private static final String TAG = FullyLinearLayoutManager.class.getSimpleName();

    public FullyLinearLayoutManager(Context context) {
        super(context);
    }

    public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    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 {
        }
    }
}

 
  
public class FullyGridLayoutManager extends GridLayoutManager {

    private int mwidth = 0;
    private int mheight = 0;

    public FullyGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }

    private int[] mMeasuredDimension = new int[2];

    public int getMwidth() {
        return mwidth;
    }

    public void setMwidth(int mwidth) {
        this.mwidth = mwidth;
    }

    public int getMheight() {
        return mheight;
    }

    public void setMheight(int mheight) {
        this.mheight = mheight;
    }

    @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:
        }
        setMheight(height);
        setMwidth(width);
        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();
            }
        }
    }
}
选择你需要的代码测试吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值