<Android基础>(三) UI开发 Part 3 RecyclerView
RecyclerView
1)RecyclerView的基本用法
2)横向滚动和瀑布流滚动
3)注册点击事件
3.6 强大的滚动控件 RecyclerView
ListView缺点:
1.不使用技巧优化,ListView效率很差。
2.扩展性能不够好,只能实现数据纵向滚动。
3.6.1 RecyclerView的基本用法
1.RecylerView定义在了support库当中。
首先需要在build.gradle中添加相应的依赖库,在dependencies闭包中添加内容。
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:recyclerview-v7:24.2.1'
testCompile 'junit:junit:4.12'
2.修改main_layout.xml中的代码
在布局中加入RecylerView。由于RecyclerView并不是内置在系统SDK中的,所以需要把完整的路径写出来。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </LinearLayout>
3.创建Hero类和hero_item.xml(同ListView)
public class Hero {
private String name;
private int imageId;
public Hero(String name, int imageId){
this.name = name;
this.imageId = imageId;
} public String getName() {
return name;
} public int getImageId() {
return imageId;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ImageView
android:id="@+id/hero_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> <TextView
android:id="@+id/hero_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"/>
</LinearLayout>
4.新建HeroAdapter类,让这个适配器继承自RecyclerView.Adapter,并将泛型指定为HeroAdapter.ViewHolder,ViewHolder是在HeroAdapter中定义的一个内部类。
public class HeroAdapter extends RecyclerView.Adapter<HeroAdapter.ViewHolder>{ private List<Hero> mHeroList; static class ViewHolder extends RecyclerView.ViewHolder{
ImageView heroImage;
TextView heroName; public ViewHolder(View view){
super(view);
heroImage = (ImageView)view.findViewById(R.id.hero_image);
heroName = (TextView)view.findViewById(R.id.hero_name);
}
} public HeroAdapter(List<Hero> heroList){
mHeroList = heroList;
} @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hero_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
} @Override
public void onBindViewHolder(ViewHolder holder, int position) {
Hero hero = mHeroList.get(position);
holder.heroImage.setImageResource(hero.getImageId());
holder.heroName.setText(hero.getName());
} @Override
public int getItemCount() {
return mHeroList.size();
}
}
首先定义一个内部类ViewHolder,ViewHolder要继承自RecylcerView.ViewHolder。ViewHolder的构造函数中传入的View参数,通常为RecylclerView子项的最外层布局。可以通过findVIewById()方法来获取到布局中的ImageView和TextView的实例。
HeroAdapter中的构造函数,将要展示的数据源传进来,并赋值给一个全局变量mHeroList,后续操作都在该数据源的基础上进行。
由于HeroAdapter继承了RecyclerView.Adapter,那么就必须重写onCreatViewHolder(),onBindViewHolder()和getItemCount()三个方法。
onCreatViewHolder()方法用于创建ViewHolder实例,在这个方法中将hero_item布局传进来,然后创建一个VIewHolder实例,将加载出来的布局传入到构造函数中,最后将ViewHolder实例返回。
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hero_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
onBindViewHolder()方法是用于对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行,通过position参数得到当前项的Hero实例,然后再将数据置入ViewHolder的ImageView和TextView。
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Hero hero = mHeroList.get(position);
holder.heroImage.setImageResource(hero.getImageId());
holder.heroName.setText(hero.getName());
}
getItemCount()方法用于告诉RecycleView一共有多少子项,直接返回数据源的长度。
@Override
public int getItemCount() {
return mHeroList.size();
}
5.修改MainActivity中的代码
public class MainActivity extends AppCompatActivity { private List<Hero> heroList = new ArrayList<Hero>(); @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
initHeros();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
HeroAdapter adapter = new HeroAdapter(heroList);
recyclerView.setAdapter(adapter);
} private void initHeros(){
for(int i = 0 ; i < 2 ; i ++){
Hero gareen = new Hero("gareen", R.drawable.gareen);
heroList.add(gareen);
Hero annie = new Hero("annie", R.drawable.annie);
heroList.add(annie);
Hero shana = new Hero("shana", R.drawable.shana);
heroList.add(shana);
Hero teemo = new Hero("teemo", R.drawable.teemo);
heroList.add(teemo);
}
}
}
用同样的initHeros()方法,初始化所有英雄数据。
在onCreat()方法中先获取到RecyclerView的实例,然后创建一个LinearLayoutManager对象,并设置到RecyclerView当中。LayoutManager用于指定RecyclerView的布局方式,这里使用LinearLayoutManager为线性布局。然后创建HeroAdapter的实例,并将英雄数据传入HeroAdapter的构造函数中,最后调用RecycleView的setAdapter()方法来完成适配器设置,完成RecyclerView和数据之间的关联。
3.6.2 实现横向滚动和瀑布流滚动
1.横向滚动
a.首先对hero_item的布局进行修改,目前布局里的元素水平放置的,即为horizontal,把元素改为垂直放置,宽度设为100dp
ImageView和TextView都设置为在布局中水平居中,并使用layout_marginTop让文字和图片之间保持一定距离
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content"> <ImageView
android:id="@+id/hero_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/> <TextView
android:id="@+id/hero_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"/>
</LinearLayout>
b.修改MainActivity中的代码
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
initHeros();
RecyclerView recyclerView = (RecyclerView) f
indViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
HeroAdapter adapter = new HeroAdapter(heroList);
recyclerView.setAdapter(adapter);
}
加一句
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
调用LinearLayoutManager的setOri()方法来设置布局的排列方向,默认为纵向,传入LinearLayoutManger.HORIZEONTAL表示让布局横向排列。
运行程序:
原因:ListView的布局排列是由自身去管理的,而RecylerView则由LayoutManager管理,LayoutManager中制定了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出各种不同的排列方式的布局。
2.瀑布流布局
a.修改hero_item.xml中的布局,宽度由列数自动匹配而不是一个固定值,用layout_margin来让子项之间互留一点间距,TextView的对齐属性改为了左对齐,因为待会会将文字的长度边长,居中显示很奇怪
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"> <ImageView
android:id="@+id/hero_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/> <TextView
android:id="@+id/hero_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginLeft="10dp"/>
</LinearLayout>
b.修改MainActivit.java中的代码
在onCreat()方法中创建了一个StaggeredGridLayoutManager的实例,构造函数接受两个参数,第一个参数用于指定布局的列数,第二个参数用于制定布局的排列方向,传入StaggeredGridLayoutManager.VERTICAL表示会让布局纵向排列。
在getRandomLengthName()方法中得到每个英雄名字都长短不一,显示出来的效果更明显
public class MainActivity extends AppCompatActivity { private List<Hero> heroList = new ArrayList<Hero>(); @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
initHeros();
RecyclerView recyclerView = (RecyclerView)
findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
HeroAdapter adapter = new HeroAdapter(heroList);
recyclerView.setAdapter(adapter);
} private void initHeros(){
for(int i = 0 ; i < 3 ; i ++){
Hero gareen = new Hero(getRandomLengthName("gareen"), R.drawable.gareen);
heroList.add(gareen);
Hero annie = new Hero(getRandomLengthName("annie"), R.drawable.annie);
heroList.add(annie);
Hero shana = new Hero(getRandomLengthName("shana"), R.drawable.shana);
heroList.add(shana);
Hero teemo = new Hero(getRandomLengthName("teemo"), R.drawable.teemo);
heroList.add(teemo);
}
} private String getRandomLengthName(String name){
Random random = new Random();
int length = random.nextInt(20) + 1 ;
StringBuilder res = new StringBuilder();
for(int i = 0 ; i < length ; i ++){
res.append(name);
}
return res.toString();
}
}
运行程序
3.6.3 RecycleView的点击事件
ListView中的setOnClickListener()方法注册的是子项的点击事件,如果是点击子项里的按钮,则实现起来很麻烦。
RecyclerView摒弃了子项点击事件的监听器,所有监听事件都由具体的View来注册。
在RecyclerView中注册点击事件,修改MainActivity中的代码
public class HeroAdapter extends RecyclerView.Adapter<HeroAdapter.ViewHolder>{ private List<Hero> mHeroList; static class ViewHolder extends RecyclerView.ViewHolder{
View heroView;
ImageView heroImage;
TextView heroName; public ViewHolder(View view){
super(view);
heroView = view;
heroImage = (ImageView)view.findViewById(R.id.hero_image);
heroName = (TextView)view.findViewById(R.id.hero_name);
}
} public HeroAdapter(List<Hero> heroList){
mHeroList = heroList;
} @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hero_item, parent, false); final ViewHolder holder = new ViewHolder(view);
holder.heroView.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Hero hero = mHeroList.get(position);
Toast.makeText(v.getContext() , "You clicked view " + hero.getName(), Toast.LENGTH_SHORT ).show();
}
});
holder.heroImage.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Hero hero = mHeroList.get(position);
Toast.makeText(v.getContext() , "You clicked image " + hero.getName(), Toast.LENGTH_SHORT).show();
}
}); return holder;
} @Override
public void onBindViewHolder(ViewHolder holder, int position) {
Hero hero = mHeroList.get(position);
holder.heroImage.setImageResource(hero.getImageId());
holder.heroName.setText(hero.getName());
} @Override
public int getItemCount() {
return mHeroList.size();
}
}
在ViewHolder中添加了heroView变量用来保存子项最外层布局的实例,然后在onCreatViewHolder()方法中注册事件。
运行程序:
点击图片部分:
显示点击了图片
点击图片下的TextView部分:由于TextView并没有注册时间,所以该事件会被子项最外层布局捕捉到。
最后一点小小的总结:
1.线性布局中orientation属性默认为horizontal(水平方向)
2.android:gravity用于指定文字在控件中的对齐方式,android:layout_gravity用于指定控件在布局中的对齐方式。
3.将控件宽度指定为0dp,用android:layout_weight来决定控件在屏幕的比例宽度
<EditText
android:id="@+id/input_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button"/>
表示EditText和Button以1:1的比例平分屏幕,以此类推。
4.动态加载布局的LayoutInflater方法,LayoutInflater的from()方法可以构建出一个LayouInflater对象,然后调用inflate()方法就可以加载一个布局文件。
inflate()方法接受两个参数,第一个参数要加载的布局文件的id,第二个参数是给加载好的布局再添加一个父布局。
接收三个参数,第三个为boolean型,false表示只让在父布局中声明的layout属性生效,但不会为View添加父布局。
ListView中的标准写法为:
View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
<Android基础>(三) UI开发 Part 3 RecyclerView的更多相关文章
- <Android基础>(三) UI开发 Part 2 ListView
ListView 1)ListView的简单用法 2)定制ListView界面 3)提升ListView的运行效率 4)ListView的点击事件 3.5 ListView 3.5.1 ListVie ...
- <Android基础>(三) UI开发 Part 1
1.常用控件 1)TextView 2)Button 3)EditText 4)ImageView 5)ProgressBar 6)AlertDialog 7)ProgressDialog 2.四种布 ...
- android 基础项目及开发出现:error opening trace file: No such file or directory错误解决
本身这个错误不影响运行,但是看着烦啊.解决方案几种如下: 1.xml标签不完整或者未关闭,常有的事.Eclipse并不是所有的xml标记都检查,单双标记什么的. 2.有人说,据说是 android a ...
- UI开发模式对比:JSP、Android、Flex
前一篇文章分析了Java平台下不同类型WEB框架对开发模式的影响,多数Java领域的WEB框架都是聚焦于服务端MVC的实现,这些框架对View的支持,通常是基于标准的JSP或类似JSP的模板技术如Fr ...
- Android与Swift iOS开发:语言与框架对比
Swift是现在Apple主推的语言,2014年新推出的语言,比Scala等“新”语言还要年轻10岁.2015年秋已经开源.目前在linux上可用,最近已经支持Android NDK:在树莓派上有Sw ...
- Android UI开发第三十一篇——Android的Holo Theme
好长时间没写Android UI方面的文章了,今天就闲扯一下Android的Holo主题.一直做android开发的可能都知道,Android 系统的UI有过两次大的变化,一次是android 3.0 ...
- 【转】Android UI开发第三十一篇——Android的Holo Theme
好长时间没写Android UI方面的文章了,今天就闲扯一下Android的Holo主题.一直做android开发的可能都知道,Android 系统的UI有过两次大的变化,一次是android 3.0 ...
- Android UI开发第三十九篇——Tab界面实现汇总及比较
Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...
- Android UI开发第三十篇——使用Fragment构建灵活的桌面
http://www.lupaworld.com/article-222973-1.html 当我们设计应用程序时,希望能够尽最大限度的适配各种设备,包括4寸屏.7寸屏. 10寸屏等等,Android ...
随机推荐
- 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
EvoSuite是由Sheffield等大学联合开发的一种开源工具,用于自动生成测试用例集,生成的测试用例均符合Junit的标准,可直接在Junit中运行.得到了Google和Yourkit的支持. ...
- spring学习总结——高级装配学习四(运行时:值注入、spring表达式)
前言: 当讨论依赖注入的时候,我们通常所讨论的是将一个bean引用注入到另一个bean的属性或构造器参数中.bean装配的另外一个方面指的是将一个值注入到bean的属性或者构造器参数中.在没有学习使用 ...
- Asp.net mvc 项目返回Json
因mvc控制器返回类型JsonResult 在处理对象转JSON的时候,对日期的格式化处理并不太符合要求,所以重新继承抽象类ActionResult使用Newtonsoft.Json来系列化 usin ...
- AngularJS学习之旅—AngularJS 控制器(六)
1.AngularJS 控制器 AngularJS 应用程序被控制器控制. ng-controller 指令定义了应用程序控制器. 控制器是 JavaScript 对象,由标准的 JavaScript ...
- centos7搭建ftp
1.检查安装vsftpd软件 rpm –qa |grep vsftpd 这里显示已经安装了,我们来卸载它重新安装 卸载vsftpd命令 rpm –e 文件名 显示卸载完成 安装vsftpd命令 Yum ...
- 英语口语练习系列-C11-了解
词汇 actor [ˈæktə(r)] n. 男演员 He is a good actor. 他是一个好演员. afternoon [ˌɑ:ftəˈnu:n] n. 下午 a boring after ...
- Enterprise Architect 时序图
添加时序图 1,在类图下面新建包 添加sequence时序图 点击流程控制,可以打开流程控制设计界面 我选择的是Lifeline线,你可以选择都差不多. 点击其中一条liftline连到其他上面 双击 ...
- day 10函数二
今日内容 '''实参:调用函数,在括号内传入的实际值,值可以为常量.变量.表达式或三者的组合*****形参:定义函数,在括号内声明的变量名,用来接受外界传来的值''''''注:形参随着函数的调用 ...
- C++笔记--std::相关
std::packaged_task https://www.cnblogs.com/haippy/p/3279565.html https://en.cppreference.com/w/cpp/t ...
- Java面试准备之JVM
介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明 程序计数器:看做当前线程所执行的字节码行号指示器.是线程私有的内存,且唯一一块不报OutOfMemoryError异常. Java虚拟 ...