Android UI控件之RecyclerView的简单应用
2016-11-05 11:11
543 查看
概述
RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好。RecyclerView是ViewGroup的子类,每一个列表项都是作为一个View子对象显示的。这些View子对象既可以是复杂的View对象,也可以是简单的View对象,这取决于我们对列表显示复杂度的需要。
假设我们有100个View对象要显示,我们并不需要准备100个视图。RecyclerView只创建刚好充满屏幕的11~12个视图,用户滑动屏幕切换视图时,上一个视图会被回收利用。RecyclerView 所做的就是回收再利用,循环往复。
创建Info类
public class Info { private UUID mId; private String mTtitle; private Date mDate; public Info(){ //为每个Info对象生成唯一标识符 this(UUID.randomUUID()); } public Info(UUID uuid) { mId = uuid; //记录当前日期 mDate = new Date(); } public UUID getmId() { return mId; } public void setmId(UUID mId) { this.mId = mId; } public String getmTtitle() { return mTtitle; } public void setmTtitle(String mTtitle) { this.mTtitle = mTtitle; } public Date getmDate() { return mDate; } public void setmDate(Date mDate) { this.mDate = mDate; } }
创建单例类InfoLab.java
public class InfoLab { private static InfoLab sInfoLab; private Context mAppContext; //创建可容纳Info对象的List private ArrayList<Info> mInfos; private InfoLab(Context appContext){ mAppContext = appContext; mInfos = new ArrayList<Info>(); //生成100个数据,并为ArrrayList填充数据 for(int i = 0;i<100;i++){ Info info = new Info(); info.setmTtitle("info #"+i); mInfos.add(info); } } //获取InfoLab对象实例 public static InfoLab get(Context c){ if(sInfoLab==null){ sInfoLab = new InfoLab(c.getApplicationContext()); } return sInfoLab; } //返回数组列表 public ArrayList<Info> getInfos(){ return mInfos; } //返回带有指定ID的Info对象 public Info getInfo(UUID uuid){ for(Info i:mInfos){ if(i.getmId().equals(uuid)){ return i; } } return null; } }
定制列表项
每个列表项的视图布局应包含三项内容:标题、创建日期,以及图片(list_item_info.xml)<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/list_item_info_image_view" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/list_item_info_title_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toLeftOf="@id/list_item_info_image_view" android:textStyle="bold" android:padding="4dp" android:text="Info Title"/> <TextView android:id="@+id/list_item_info_date_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/list_item_info_title_text_view" android:textStyle="bold" android:padding="4dp" android:text="Info Date"/> </RelativeLayout>
添加RecyclerView视图
先找到并选择recyclerview-v7支持库,完成依赖库添加。(info_list_activity.xml)<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/info_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
为InfoListActivity配置视图(InfoListActivity.java)
public class InfoListActivity extends AppCompatActivity { private RecyclerView mInfoRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.info_list_activity); mInfoRecyclerView = (RecyclerView)this.findViewById(R.id.info_recycler_view); mInfoRecyclerView.setLayoutManager(new LinearLayoutManager(this)); } ... }
实现 Adapter 和 ViewHolder
RecyclerView的任务仅限于回收和定位屏幕上的UI控件,比如这里的TextView和ImageView。 UI能够显示数据还离不开另外两个类的支持:Adapter子类和ViewHolder子类。
(1)ViewHolder
ViewHolder要做的事很少,我们首先讨论它。顾名思义,ViewHolder只做一件事:容纳View视图。
ViewHolder为itemView而生:它引用着我们传给super(view)的整个View视图。
RecyclerView自身不会创建视图,它创建的是ViewHolder,而ViewHolder引用着一个个itemView,如图所示。
如果处理的是简单视图, ViewHolder的工作也会相对简单。对于复杂视图, ViewHolder就得处理不同部分的itemView,以简单高效地展示View。
下面就是ViewHolder的基本用法:
首先在InfoListActivity类中定义ViewHolder内部类,(InfoListActivity.java)
public class InfoListActivity extends AppCompatActivity { ... private class InfoHolder extends RecyclerView.ViewHolder{ public TextView mTitleTextView; private TextView mDateTextView; private ImageView mImageView; private Info mInfo; public InfoHolder(View itemView) { super(itemView); mTitleTextView = (TextView)itemView.findViewById(R.id.list_item_info_title_text_view); mDateTextView = (TextView)itemView.findViewById(R.id.list_item_info_date_text_view); mImageView = (ImageView)itemView.findViewById(R.id.list_item_info_image_view); } //为UI控件填充数据 private void bindView(Info info){ mInfo = info; mTitleTextView.setText(info.getmTtitle()); mDateTextView.setText(info.getmDate().toString()); mImageView.setImageResource(R.mipmap.litten); } } ... }
(2)adapter
但是RecyclerView自己并不会创建ViewHolder。这个任务实际是由adapter来完成的。
adapter是个控制器对象,从模型层获取数据,然后提供给RecyclerView显示,起到了沟通的桥梁作用。
adapter负责:
创建必要的ViewHolder;
绑定ViewHolder至模型层数据。
要创建adapter,首先要定义RecyclerView.Adapter子类。然后由它封装从InfoLab获取的info。
RecyclerView需要显示视图对象时,就会去找它的adapter。下图展示了一个RecyclerView可能发起的会话。
首先,通过调用adapter的getItemCount()方法, RecyclerView询问数组列表中包含多少个对象。
接 着 , RecyclerView 调 用 adapter 的 createViewHolder(ViewGroup, int) 方 法 创 建 ViewHolder以及ViewHolder要显示的视图。
最后,RecyclerView会传入ViewHolder及其位置,调用onBindViewHolder(ViewHolder, int)方法。
adapter会找到目标位置的数据并绑定到ViewHolder的视图上。所谓绑定,就是使用 模型数据填充视图。
整个过程执行完毕, RecyclerView就能在屏幕上显示info列表项了。
注意:
相对于onBindViewHolder(ViewHolder, int)方法,createViewHolder(ViewGroup, int)方法的调用并不频繁。一旦创建了够用的ViewHolder, RecyclerView就会停止调用createViewHolder(…)方法。然后,通过回收利用旧的ViewHolder节约时间和内存。
下面就是adapter的基本创建:
定义完ViewHolder,接下来的任务是创建adapter,(InfoListActivity.java)
public class InfoListActivity extends AppCompatActivity{ ... private class InfoAdapter extends RecyclerView.Adapter<InfoHolder>{ private List<Info> mInfos; public InfoAdapter(List<Info> list){ mInfos = list; } @Override public InfoHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(InfoListActivity.this); View view = inflater.inflate(R.layout.list_item_info,parent,false); return new InfoHolder(view); } @Override public void onBindViewHolder(InfoHolder holder, int position) { Info info = mInfos.get(position); //holder.mTitleTextView.setText(info.getmTtitle()); holder.bindView(info); } @Override public int getItemCount() { return mInfos.size(); } } ... }
RecyclerView需要新的View视图来显示列表项时,会调用onCreateViewHolder方法。在这个方法内部,我们创建View视图,然后封装到ViewHolder中。此时, RecyclerView并不要求
封装视图装载数据。
onBindViewHolder方法会把ViewHolder的View视图和模型层数据*绑定起来。收到ViewHolder和列表项在数据集中的索引位置后,我们通过索引位置找到要显示的数据进行绑定*。绑定完毕,刷新显示View视图。
索引位置,实际上就是数组中info的位置。取出目标数据后,通过发送**info相关的数据给**ViewHolder的响应的视图,我们就完成了Info数据和View视图的绑定。
设置Adapter(InfoListActivity)
搞 定 了 Adapter , 最 后 要 做 的 就 是 将 它 和 RecyclerView 关 联 起 来 。 实 现 一 个 设 置InfoListActivity用 户 界 面的updateUI 方 法 ,该 方法 创建InfoAdapter , 然 后设置 给RecyclerView:public class InfoListActivity extends AppCompatActivity { private RecyclerView mInfoRecyclerView; private InfoAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.info_list_activity); mInfoRecyclerView = (RecyclerView)this.findViewById(R.id.info_recycler_view); mInfoRecyclerView.setLayoutManager(new LinearLayoutManager(this)); updateUI(); } private void updateUI() { InfoLab infoLab = InfoLab.get(this); List<Info> infos = infoLab.getInfos(); mAdapter = new InfoAdapter(infos); mInfoRecyclerView.setAdapter(mAdapter); mInfoRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST)); } ... }
响应点击
受益于RecyclerView的内置特性,列表项能够响应用户的点击。用户点击列表项时,实现弹出一个Toast消息。设置OnClickListener监听器。既然列表项视图都关联有ViewHolder,就可以让ViewHolder为它监听用户触摸事件。
修改InfoHolder类来处理用户点击事件:
private class InfoHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ public TextView mTitleTextView; private TextView mDateTextView; private ImageView mImageView; private Info mInfo; public InfoHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); mTitleTextView = (TextView)itemView.findViewById(R.id.list_item_info_title_text_view); mDateTextView = (TextView)itemView.findViewById(R.id.list_item_info_date_text_view); mImageView = (ImageView)itemView.findViewById(R.id.list_item_info_image_view); } private void bindView(Info info){ mInfo = info; mTitleTextView.setText(info.getmTtitle()); mDateTextView.setText(info.getmDate().toString()); mImageView.setImageResource(R.mipmap.litten); } @Override public void onClick(View v) { Toast.makeText(InfoListActivity.this, mInfo.getmTtitle() + " clicked!", Toast.LENGTH_SHORT) .show(); } }
在以上代码中, InfoHolder类实现了OnClickListener接口;而对于itemView来说,InfoHolder承担了接收用户点击事件的任务。
通过RecyclerView显示的列表是没有分割线的,如果想让每项View对象之间有分割线可以参考鸿洋大神
最后效果如下:
接下来,点击列表中的某一项,跳转到详细页面。
创建详细页面布局视图(info_detail_activity.xml)
,如下图所示:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textStyle="bold" style="?android:listSeparatorTextViewStyle" android:text="Title"/> <EditText android:id="@+id/info_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:hint="Enter something you want."> </EditText> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold" android:text="Date" style="?android:listSeparatorTextViewStyle"/> <Button android:id="@+id/info_date_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"/> </LinearLayout>
创建InfoDetailActivity类(InfoDetailActivity.java)
public class InfoDetailActivity extends AppCompatActivity { private EditText mTitleEdittext; private Button mDateButton; private Info mInfo; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.info_detail_activity); mInfo = new Info(); mTitleEdittext = (EditText)this.findViewById(R.id.info_edit_text); mTitleEdittext.setText(mInfo.getmTtitle()); mTitleEdittext.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mInfo.setmTtitle(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); mDateButton = (Button)this.findViewById(R.id.info_date_button); mDateButton.setText(mInfo.getmDate().toString()); mDateButton.setEnabled(false); } }
从InfoListActivity中启动InfoDetailActivity(InfoListActivity.java)
用启动InfoDetailActivity实例的代码,替换Toast消息处理代码:
public void onClick(View v) { Intent intent = new Intent(InfoListActivity.this,InfoDetailActivity.class); intent.putExtra(EXTRA_INFO_ID,mInfo.getmId()); startActivity(intent); }
启动InfoDetailActivity时,传递附加到Intent extra上的Info ID, InfoDetailActivity就能知道该显示哪个Info。
获取Extra信息(InfoDetailActivity.java)
public class InfoDetailActivity extends AppCompatActivity { ... public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.info_detail_activity); UUID uuid = (UUID) getIntent().getSerializableExtra(InfoListActivity.EXTRA_INFO_ID); mInfo = InfoLab.get(this).getInfo(uuid); //mInfo = new Info(); ... } ... }
这样便完成了所有事件。
相关文章推荐
- Android L 新增UI控件:RecyclerView CardView的简单使用
- android UI - 简单控件textView Button ImageView ImageButton
- android复习路之RecyclerView简单的应用
- Day3.4--Android简单UI控件之ImageView以及ScaleType的使用
- android之视频播放控件VideoView简单应用
- android之视频播放控件VideoView简单应用
- android之视频播放控件VideoView简单应用
- Day3.2--Android简单UI控件之TextView的高级使用--SpannableString的使用
- Android基础学习总结(二)——六步轻松搞定RecyclerView简单应用
- 说说 Android UI 的滚动控件(RecyclerView)
- android UI开发之RecyclerView(一)简单实现
- 浅谈Android RecyclerView UI的滚动控件示例
- Android之RecyclerView控件的简单运用
- Android常用控件--RecyclerView的简单使用
- UI进阶第五发:使用picker View控件完成一个简单的选餐应用
- android之视频播放控件VideoView简单应用
- Android应用开发——TextView控件属性列表
- Android基础教程(三)之-----简单的Button事件响应综合提示控件Toast的应用
- Android深入浅出系列之实例应用—简单的手指拖动图片,图片滑来滑去显示应用Gallery和BaseAdapter以及ImageView的使用
- Android UI 之TextView控件中可选择的属性列表,开发中经常用到的