回顧ListView
概述
一句話:在有限的空間中顯示大量的列表集合的控件ListView的使用步驟(question)
1.數據集2.適配器Adapter備注:其實ListView是一個MVC的模式,
M--Model 數據集V--View ListViewC--Controller 適配器RecyclerView的介紹
概述
官方的介紹,該控件用于在有限的窗口中展示大量數據集。正如我們剛才介紹ListView和之前所學過的ListView
Google在2014年I/O大會上提出新的用于取代ListView的組件,相比ListView而言,它更加強大,而且非常靈活
原理以及結構圖
官方結構圖RecyclerView描述
與其它的View不一樣的地方是RecyclerView不負責子view的展現和布局工作。即子view的位置、大小等都不由RecyclerView自己負責。它所關注的是子view的回收與復用,專注于性能的提升。而其它的工作如布局、子view的布局、子view的裝飾、子view的動畫都交給了其內部類來負責,下表展示了幾個關鍵的內部類和它們的用途。RecyclerView的相關類
RecyclerView的初體驗
3.設置適配器
(1) 準備適配器繼承RecyclerView.Adapter(2)RecyclerView.Adapter中默認必須有ViewHolder,需要在Adapter中寫一個內部類繼承RecyclerView.ViewHolder示例代碼如下:
* step: * 1. 繼承RecyclerView.Adapter<VH extends ViewHolder> * 2. 在這個Adapter中寫一個類繼承RecyclerView.ViewHolder,并且傳入Adapter的泛型 * 3. 實現 三個抽象方法 * getItemCount * onCreateViewHolder * onBindViewHolder * 4. 重寫構造方法,參數傳入 上下文Context 數據集 * ************************************************************* */public class LikeListAdapter extends RecyclerView.Adapter<LikeListAdapter.MyViewHolder> { PRivate List<String> mDatas = new ArrayList<>(); private Context mContext; private LayoutInflater mInflater; public LikeListAdapter(Context context, List<String> datas) { this.mInflater = LayoutInflater.from(context); mDatas = datas; this.mContext = context; } //返回RecyclerView總共有多少條 @Override public int getItemCount() { return mDatas == null ? 0 : mDatas.size(); } //初始化布局,創建ViewHolder @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //1. 初始化item的布局 View view = mInflater.inflate(R.layout.item_likelist, parent, false); //2. 創建出來ViewHolder對象 MyViewHolder myViewHolder = new MyViewHolder(view); return myViewHolder; } //綁定ViewHolder中的控件的數據 @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { String str = mDatas.get(position); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {// Toast.makeText(mContext, "pos:" + position, Toast.LENGTH_SHORT).show(); if (mListener != null) { mListener.onItemClick(position, holder.itemView); } } }); //瀑布流展示// Random random = new Random();// int height = random.nextInt(100) + 100;// LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);// ViewGroup.LayoutParams layoutParams = holder.tv_test.getLayoutParams();// layoutParams.height = height;// holder.tv_test.setLayoutParams(layoutParams); holder.tv_test.setText(str); } public class MyViewHolder extends RecyclerView.ViewHolder { private TextView tv_test; public MyViewHolder(View itemView) { super(itemView); tv_test = (TextView) itemView.findViewById(R.id.tv_test); } } //增加一條數據 public void insertData(int pos, String data) { mDatas.add(pos, data); notifyItemInserted(pos); } //刪除一條數據 public void removeData(int pos) { mDatas.remove(pos); notifyItemRemoved(pos); } public interface OnItemClickListener { void onItemClick(int pos, View view); } private OnItemClickListener mListener; public void setOnItemClickListener(OnItemClickListener listener) { this.mListener = listener; }}(4)設置布局管理器LayoutManager
LinearLayoutManager線性布局GridLayoutManager網格布局StaggeredGridLayoutManager瀑布流布局public class LikeListActivity extends AppCompatActivity { private List<String> mDatas = new ArrayList<>(); private RecyclerView mRecyclerView; private Button btn_add; private Button btn_remove; private LikeListAdapter mAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_likelist); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); btn_add = (Button) findViewById(R.id.btn_add); btn_remove = (Button) findViewById(R.id.btn_remove); //1.準備數據集 for (int i = 0; i < 50; i++) { mDatas.add("data:" + i); } //2.初始化Adapter mAdapter = new LikeListAdapter(this, mDatas); mRecyclerView.setAdapter(mAdapter); //3.創建出來LayoutManager //3.1 線性布局: 第二個參數是 列表展現的方向,有豎直的LinearLayoutManager.VERTICAL 和 水平的LinearLayoutManager.HORIZONTAL // 第三個參數: 是否 從最后展示 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); //3.2 網格布局: 參數2是 表示這個網格布局的列數 或者行數 GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false); //3.3 瀑布流布局 StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(linearLayoutManager); //給RecyclerView增加一些動畫效果// mRecyclerView.setItemAnimator(new DefaultItemAnimator()); //1. build.gradle中引入 : compile 'jp.wasabeef:recyclerview-animators:2.2.5' //2. 添加動畫效果 : setItemAnimator(動畫效果的類例如: SlideInLeftAnimator, SlideInRightAnimator); mRecyclerView.setItemAnimator(new LandingAnimator()); //3. 改變動畫的時長: 有四個: // recyclerView.getItemAnimator().setAddDuration(1000); //recyclerView.getItemAnimator().setRemoveDuration(1000); //recyclerView.getItemAnimator().setMoveDuration(1000); //recyclerView.getItemAnimator().setChangeDuration(1000); mRecyclerView.getItemAnimator().setAddDuration(3000); //增加一條數據 btn_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mAdapter.insertData(1, "新增加的數據"); } }); //刪除一條數據 btn_remove.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mAdapter.removeData(1); } });// mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); mAdapter.setOnItemClickListener(new LikeListAdapter.OnItemClickListener() { @Override public void onItemClick(int pos, View view) { Toast.makeText(LikeListActivity.this, "pos::" + pos, Toast.LENGTH_SHORT).show(); } }); }}三方地址
https://github.com/gabrielemariotti/RecyclerViewItemAnimators
具體操作如下:
//給RecyclerView增加一些動畫效果// mRecyclerView.setItemAnimator(new DefaultItemAnimator()); //1. build.gradle中引入 : compile 'jp.wasabeef:recyclerview-animators:2.2.5' //2. 添加動畫效果 : setItemAnimator(動畫效果的類例如: SlideInLeftAnimator, SlideInRightAnimator); mRecyclerView.setItemAnimator(new LandingAnimator()); //3. 改變動畫的時長: 有四個: // recyclerView.getItemAnimator().setAddDuration(1000); //recyclerView.getItemAnimator().setRemoveDuration(1000); //recyclerView.getItemAnimator().setMoveDuration(1000); //recyclerView.getItemAnimator().setChangeDuration(1000);具體操作如下:
public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } }}MultiAdapter寫法如下
* step: * 1. 有幾種類型,就寫幾個ViewHolder, Adapter中的泛型傳入RecyclerView.ViewHolder * 2. 有幾種類型,就寫幾種int 類型常量, 一般從0開始 * 3. 覆寫方法getItemViewType(int pos) , 返回當前位置到底是那種類型 * 4. 通過onCreateViewHolder(ViewGroup parent, int viewType) 中的 第二個參數 viewType 去創建不同的ViewHolder對象 * ************************************************************* */public class MultiAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public Context mContext; public LayoutInflater mInflater; public List<HouseBean.DataBean> mDatas; //有幾種類型 就寫一個常量去標記 private static final int TYPE_SPECIAL = 0; private static final int TYPE_NORMAL = 1; private static final int TYPE_BIG = 2; public MultiAdapter(Context context, List<HouseBean.DataBean> datas) { this.mContext = context; this.mInflater = LayoutInflater.from(context); this.mDatas = datas; } @Override public int getItemCount() { return mDatas == null ? 0 : mDatas.size(); } //返回當前位置的類型 @Override public int getItemViewType(int position) { String type = mDatas.get(position).type; if ("100".equals(type)) { return TYPE_SPECIAL; } else if ("0".equals(type)) { return TYPE_NORMAL; } else { return TYPE_BIG; } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_SPECIAL:// View view = mInflater.inflate(R.layout.item_multi_special, parent, false);// return new SpecialHolder(view); return new SpecialHolder(mInflater.inflate(R.layout.item_multi_special, parent, false)); case TYPE_NORMAL: return new NormalHolder(mInflater.inflate(R.layout.item_multi_normal, parent, false)); case TYPE_BIG: return new BigImgHolder(mInflater.inflate(R.layout.item_multi_big, parent, false)); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int itemViewType = getItemViewType(position); HouseBean.DataBean bean = mDatas.get(position); switch (itemViewType) { case TYPE_SPECIAL: SpecialHolder specialHolder = (SpecialHolder) holder; specialHolder.tv_title.setText(bean.title); specialHolder.tv_desc.setText(bean.summary); Picasso.with(mContext) .load(bean.groupthumbnail) .placeholder(R.mipmap.ic_launcher) .error(R.mipmap.ic_launcher) .into(specialHolder.iv_special); break; case TYPE_NORMAL: NormalHolder normalHolder = (NormalHolder) holder; normalHolder.tv_title.setText(bean.title); normalHolder.tv_desc.setText(bean.summary); Picasso.with(mContext) .load(bean.groupthumbnail) .placeholder(R.mipmap.ic_launcher) .error(R.mipmap.ic_launcher) .into(normalHolder.iv_normal); break; case TYPE_BIG: BigImgHolder bigImgHolder = (BigImgHolder) holder; bigImgHolder.tv_title.setText(bean.title); Picasso.with(mContext) .load(bean.groupthumbnail) .placeholder(R.mipmap.ic_launcher) .error(R.mipmap.ic_launcher) .into(bigImgHolder.iv_big); break; } } class SpecialHolder extends RecyclerView.ViewHolder { private ImageView iv_special; private TextView tv_title; private TextView tv_desc; public SpecialHolder(View itemView) { super(itemView); iv_special = (ImageView) itemView.findViewById(R.id.iv_show); tv_title = (TextView) itemView.findViewById(R.id.tv_title); tv_desc = (TextView) itemView.findViewById(R.id.tv_desc); } } class NormalHolder extends RecyclerView.ViewHolder { private ImageView iv_normal; private TextView tv_title; private TextView tv_desc; public NormalHolder(View itemView) { super(itemView); iv_normal = (ImageView) itemView.findViewById(R.id.iv_show); tv_title = (TextView) itemView.findViewById(R.id.tv_title); tv_desc = (TextView) itemView.findViewById(R.id.tv_desc); } } class BigImgHolder extends RecyclerView.ViewHolder { private ImageView iv_big; private TextView tv_title; public BigImgHolder(View itemView) { super(itemView); iv_big = (ImageView) itemView.findViewById(R.id.iv_big); tv_title = (TextView) itemView.findViewById(R.id.tv_title); } }}MultiActivity寫法如下:
* step: * 1. 從網絡獲得到數據源 * <p> * 2. 準備適配器 * <p> * 3. 布局管理器 * ************************************************************* */public class MultiActivity extends AppCompatActivity { private RecyclerView mRecyclerView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_multi); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); RequestQueue requestQueue = Volley.newRequestQueue(this); StringRequest request = new StringRequest(Request.Method.GET, UrlString.URL_SEEHOUSE, new Response.Listener<String>() { @Override public void onResponse(String response) { //TODO 得到數據 解析 顯示到RecyclerView HouseBean houseBean = new Gson().fromJson(response, HouseBean.class); mRecyclerView.setAdapter(new MultiAdapter(MultiActivity.this, houseBean.data)); mRecyclerView.setLayoutManager(new LinearLayoutManager(MultiActivity.this)); } }, null); requestQueue.add(request); }}新聞熱點
疑難解答