RecyclerView 的使用以及多佈局的實例java
RecyclerView 是在Android5.0以後推出的,是一個比ListView更加靈活更加高效的適配器類型控件。可是RecyclerView不一樣於其餘類型的適配器,它還須要一個LayoutManager進行頁面控制展現。RecyclerView提供了三種佈局管理器:
一、LinearLayoutManager:線性佈局管理器,支持水平和垂直效果。
二、GridLayoutManager:網格佈局管理器,支持水平和垂直效果。
三、StaggeredGridLayoutManager:分佈型管理器,瀑布流效果
RecyclerView的使用:
一、引入RecyclerView依賴包,V7下的,兼容到API17.
二、在xml佈局中聲明,在Java代碼中初始化。
三、設置佈局管理器
四、建立適配器,設置數據源,綁定適配器
具體建立適配器:①建立一個類,繼承RecyclerView.Adapter<ViewHolder>.
②建立一個類ViewHolder,繼承RecyclerView。VIewHolder,該類須要建立一個匹配父類的構造。
③重寫適配器中的方法:getItemCount():獲取數據源的個數(item的數量);onCreateViewHolder():該方法中導入佈局,實例化VIewHolder;onBindViewHolder():綁定VIewHolder,加載數據。
注意一點:RecyclerView的LinearLayoutManager不一樣於通常的適配器的佈局,RecyclerView的item最外層的佈局參數是有效的,如高度寬度等,因此在使用的時候,第一種方法是在導入View的時候指定沒有parent(不推薦使用),第二種方法是在item佈局的最外層指定具體的參數。
RecyclerView 爲開發者提供了強大的複用機制,可是全部的點擊事件都丟了,沒有提供默認的點擊事件,因此須要咱們本身爲RecyclerView手動實現點擊。
看一個簡單的例子,後面講解下多佈局的RecyclerView。效果圖以下(不要吐槽,我知道很醜,能達到效果就好^_^):
第一步:建立佈局,須要導入依賴包:android.support.v7.widget.RecyclerViewandroid
activity_main.xmlgit
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.zcl.day40_recyleview01.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/teach_recycler" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
item.xmlgithub
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:background="@drawable/backgroud_shap" android:layout_height="match_parent"> <ImageView android:src="@mipmap/ic_launcher" android:layout_width="80dp" android:layout_height="80dp" /> <TextView android:id="@+id/teach_item_name" android:gravity="center" android:layout_width="match_parent" android:layout_height="80dp" /> </LinearLayout>
Model.java網絡
public class Model { private String name; private int height; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
MainActivity.javaapp
public class MainActivity extends AppCompatActivity implements RecyclerAdapter.OnItemClickListener { private static final String TAG = MainActivity.class.getSimpleName(); private RecyclerView mRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { mRecyclerView = (RecyclerView) findViewById(R.id.teach_recycler); //設置佈局管理器 //一、第一種LinearLayoutManager // LinearLayoutManager layoutManager = new LinearLayoutManager(this); //二、第二種 GridLayoutManager // GridLayoutManager layoutManager=new GridLayoutManager(this,3); //三、第三種 StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); // //設置佈局的排版方向 // layoutManager.setOrientation(GridLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(layoutManager); //綁定適配器 RecyclerAdapter adapter = new RecyclerAdapter(this, getData()); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(this);//將接口傳遞到數據產生的地方 } /** * 獲取數據源 * * @return */ public List<Model> getData() { List<Model> data = new ArrayList<>(); for (int i = 0; i < 30; i++) { Model model = new Model(); model.setName("猴子請來的都比---" + i); model.setHeight(((int) (Math.random() * 100 + 200))); data.add(model); } return data; } @Override public void onItemClick(int position, Model model) { Log.e(TAG, "onItemClick: " + position); } }
適配器dom
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> implements View.OnClickListener { private static final String TAG = RecyclerAdapter.class.getSimpleName(); private List<Model> data; private LayoutInflater inflater; private RecyclerView mRecyclerView;//用來計算Child位置 private OnItemClickListener onItemClickListener; //對外提供接口初始化方法 public void setOnItemClickListener(OnItemClickListener onItemClickListener){ this.onItemClickListener=onItemClickListener; } public RecyclerAdapter(Context context,List<Model> data) { this.data = data; inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public static class ViewHolder extends RecyclerView.ViewHolder{ TextView name; public ViewHolder(View itemView) { super(itemView); name= (TextView) itemView.findViewById(R.id.teach_item_name); } } /** * 建立VIewHolder,導入佈局,實例化itemView * @param parent * @param viewType * @return */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = inflater.inflate(R.layout.item, parent, false); //導入itemView,爲itemView設置點擊事件 itemView.setOnClickListener(this); return new ViewHolder(itemView); } /** * 綁定VIewHolder,加載數據 * @param holder * @param position */ @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.name.setText(data.get(position).getName());//加載數據 ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); layoutParams.height=data.get(position).getHeight(); holder.itemView.setLayoutParams(layoutParams); } /** * 數據源的數量,item的個數 * @return */ @Override public int getItemCount() { return data!=null?data.size():0; } /** * 適配器綁定到RecyclerView 的時候,回將綁定適配器的RecyclerView 傳遞過來 * @param recyclerView */ @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView=recyclerView; } /** * * @param v 點擊的View */ @Override public void onClick(View v) { //RecyclerView能夠計算出這是第幾個Child int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v); Log.e(TAG, "onClick: "+childAdapterPosition ); if (onItemClickListener!=null) { onItemClickListener.onItemClick(childAdapterPosition,data.get(childAdapterPosition)); } } /** * 接口回調 * 一、定義接口,定義接口中的方法 * 二、在數據產生的地方持有接口,並提供初始化方法,在數據產生的時候調用接口的方法 * 三、在須要處理數據的地方實現接口,實現接口中的方法,並將接口傳遞到數據產生的地方 */ public interface OnItemClickListener{ void onItemClick(int position,Model model); } }
多佈局的RecyclerView ---------------------------------------------------------------ide
先看下效果圖:佈局
這是this
分析下該頁面佈局,三種佈局,第一種是標題文字+內容簡介文字佔一個item,第二種是圖片+標題佔一個item,第三種是標題+內容,而且一個item中有兩個這樣的佈局。那麼能夠用網格佈局,分爲兩列,第一種跟第二種佈局各自佔兩列,第三種佈局佔一列。那麼怎麼設置item能夠橫跨兩列呢,就要用到gridLayoutManager.setSpanSizeLookup來設置,具體看代碼:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.zcl.day40_task2.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
item1.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="200dp"> <ImageView android:id="@+id/iv_item1" android:src="@mipmap/ic_launcher" android:layout_width="match_parent" android:layout_height="200dp" /> <TextView android:id="@+id/tv_item1" android:text="title" android:textColor="#e5ffffff" android:textSize="20sp" android:textStyle="bold" android:layout_marginLeft="15dp" android:layout_marginTop="20dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
item2.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:id="@+id/tv_item2_title" android:textSize="20sp" android:textStyle="bold" android:text="title" android:layout_marginLeft="15dp" android:layout_marginTop="20dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_item2_content" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:text="content" android:layout_marginBottom="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
item3.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:id="@+id/tv_item3_title" android:textSize="20sp" android:lines="2" android:ellipsize="end" android:text="title" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="60dp" /> <TextView android:id="@+id/tv_item3_content" android:lines="2" android:ellipsize="end" android:text="content" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="60dp" /> </LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyAdapter.OnItemClickLietener{ private static final String TAG = MainActivity.class.getSimpleName(); private RecyclerView mRecyclerView; private MyAdapter adapter; private List<Model> data; public static final String URL_PATH="http://dxy.com/app/i/feed/index/list?hardName=Google%20Nexus%205%20-%205.1.0%20-%20API%2022%20-%201080x1920&u=&bv=2015&ac=d5424fa6-adff-4b0a-8917-4264daf4a348&vc=5.1.9&vs=5.1&mc=00000000600ba4e6ffffffff99d603a9"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { ImageLoader.init(this); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); //設置佈局管理器 GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2); Log.e(TAG, "initView:----1 " ); gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { int spansize=1; switch (adapter.getItemViewType(position)) { case 1: spansize=2; break; case 2: spansize=2; break; } return spansize; } }); Log.e(TAG, "initView: -----2" ); mRecyclerView.setLayoutManager(gridLayoutManager); adapter = new MyAdapter(this, getData()); mRecyclerView.setAdapter(adapter); adapter.setClickLietener(this); Log.e(TAG, "initView: 4" ); } public List<Model> getData() { Log.e(TAG, "getData: 3" ); HttpUtil.getStringAsync(URL_PATH, new HttpUtil.RequestCallBack() { @Override public void onFailure() { Log.e(TAG, "onFailure: " ); } @Override public void onSuccess(String result) { Gson gson = new Gson(); ModelData modelData = gson.fromJson(result, ModelData.class); List<Model> data =modelData.getData().getItems(); Log.e(TAG, "onSuccess: "+data ); adapter.addRes(data); } @Override public void onFinish() { Log.e(TAG, "onFinish: " ); } }); return data; } @Override public void setItemClickListener(int position) { Log.e(TAG, "setItemClickListener: "+position ); } }
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener { private List<Model> data; private LayoutInflater inflater; private RecyclerView mRecyclerView; private OnItemClickLietener clickLietener; public void setClickLietener(OnItemClickLietener clickLietener){ this.clickLietener=clickLietener; } public MyAdapter(Context context, List<Model> data) { this.data = data; inflater = LayoutInflater.from(context); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = null; switch (viewType) { case 1: itemView = inflater.inflate(R.layout.item1, parent, false); break; case 2: itemView = inflater.inflate(R.layout.item2, parent, false); break; case 8: itemView = inflater.inflate(R.layout.item3, parent, false); break; //設置監聽 } itemView.setOnClickListener(this); return new ViewHolder(itemView); } @Override public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case 1: ImageView imageView = (ImageView) holder.getView(R.id.iv_item1); TextView textView = (TextView) holder.getView(R.id.tv_item1); textView.setText(data.get(position).getTitle()); String picPath = data.get(position).getCover(); ImageLoader.display(imageView, picPath); break; case 2: TextView item2Title = (TextView) holder.getView(R.id.tv_item2_title); TextView item2Content = (TextView) holder.getView(R.id.tv_item2_content); item2Title.setText(data.get(position).getTitle()); item2Content.setText(data.get(position).getContent()); break; case 8: TextView item3Title = (TextView) holder.getView(R.id.tv_item3_title); TextView item3Content = (TextView) holder.getView(R.id.tv_item3_content); item3Title.setText(data.get(position).getTitle()); item3Content.setText(data.get(position).getContent()); break; } } @Override public int getItemCount() { return data != null ? data.size() : 0; } @Override public int getItemViewType(int position) { return data.get(position).getShow_type(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView=recyclerView; } public void addRes(List<Model> data) { if (data != null) { this.data = data; notifyDataSetChanged(); } } @Override public void onClick(View v) { int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v); if (clickLietener!=null) { clickLietener.setItemClickListener(childAdapterPosition); } } public static class ViewHolder extends RecyclerView.ViewHolder { private Map<Integer, View> mCacheView; public ViewHolder(View itemView) { super(itemView); mCacheView = new HashMap<>(); } public View getView(int resId) { View view; if (mCacheView.containsKey(resId)) { view = mCacheView.get(resId); } else { view = itemView.findViewById(resId); mCacheView.put(resId, view); } return view; } } public interface OnItemClickLietener{ void setItemClickListener(int position); } }
代碼中使用的網絡數據的請求以及圖片的加載是本身封裝的類庫,你們能夠忽略,用本身的代碼填充,能理解RecyclerView就好,另外數據的實體類太簡單,也沒有貼上代碼。最後不要忘了配置網絡權限哦。
個人github:https://github.com/SiberiaDante