Android开发学习 -- Day7 UI开发(三)
上一章讲到Android提供了一个更加强大的滚动控件 -- RecycleView。它可以说是一个增强版的ListView,不仅可以轻松的实现和ListView同样的效果,还优化了ListView中各种不足。目前Android官方更加推荐使用RecycleView。
1、RecycleView的基本用法
RecycleView属于新增的控件,为了让RecycleView在所有的版本上都能使用,Android团队采取了同样的方式,将RecycleView定义在了support库中。因此,想要使用RecycleView这个控件,首先需要在项目的Gradle中添加相应的依赖库才行。
打开app/build.gradle文件,在dependences闭包中添加'com.android.support:recyclerview-v7:26.1.0'
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:design:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:0.5'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.android.support:recyclerview-v7:26.1.0'
}
添加完成之后记得Sync进行同步。然后修改xml代码,添加RecycleView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.johnhao.listviewdemo.Activity.RecycleviewActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
布局中加入RecyclerView也很简单,指定一个id,然后将宽度和高度都设置成match_parent,这样RecyclerView就会占满整个布局空间。需要注意的是,由于RecyclerView并不是内置在系统SDK中,所以需要把完整的包路径写出来。
这里我们还是在之前的项目上进行修改,基于同样的水果用RecyclerView实现和ListView一样的效果。接下来为RecyclerView准备一个适配器。新建FruitAdapterAdv类,让这个适配器继承自RecyclerView.Adapter,并将泛型指定为FruitAdapterAdv.ViewHolder。其中ViewHolder是我们在FruitAdapterAdv当中的一个内部类,代码如下:
public class FruitAdapterAdv extends RecyclerView.Adapter<FruitAdapterAdv.ViewHolder>{
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImg;
TextView fruitName;
public ViewHolder(View itemView) {
super(itemView);
fruitView = itemView;
fruitImg = (ImageView) itemView.findViewById(R.id.fruit_image);
fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
}
}
public FruitAdapterAdv(List<Fruit> fruitList){
mFruitList = fruitList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.fruitView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(), "You clicked view: " + fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
holder.fruitImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(), "You click image: " + fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(FruitAdapterAdv.ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImg.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
}
这里我们首先定义了一个内部类ViewHolder,ViewHolder要继承自RecyclerView.ViewHolder。然后ViewHolder的构造函数中需要传一个View参数,这个参数通常就是RecyclerView子项的最外层布局,那么我们就可以通过findViewById获得布局中的ImageView和TextView的实例了。此外,我们指定了一个fruitView,表示子布局的最外层布局。
接着往下看,FruitAdapterAdv也有一个构造函数,这个方法用于把数据传递源进来,并赋值给一个全局变量mFruitList,后面的操作都是在这个数据源的基础上进行。
由于FruitAdapterAdv是继承自RecyclerView.Adapter,所以就必须的重写onCreateViewHolder()、onBindViewHolder()和getItemCount()这3个方法。
□ onCreateViewHolder():通过LayoutInflater的inflate()方法将fruits布局加载进来。然后创建一个ViewHolder实例,并把加载的出来的布局传到构造函数中,最后将ViewHolder的实例返回。另外,我们在这里添加了点击事件的监听器。RecycleView的强大之处在这里也能得到体现,它可以轻松的实现子项中任意控件或者布局的点击事件。我们设置了子项中图片和子项最外层布局的点击事件,然后先获取用户点击的position,接着通过position拿到相应的Fruit实例,最后调用Toast分别弹出不同的内容加以区分。
□ onBindViewHolder():它是用于对RecycleView子项的数据进行赋值,通过position参数获取到当前Fruit实例,然后再将数据设置到ViewHolder的ImageView和TextView中。
□ getItemCount():指明RecycleView有多少个子项,这里我们直接返回数据源的长度即可。
适配器完成后,我们就可以开始使用RecycleView了,修改Activity内代码:
public class RecycleviewActivity extends BaseActivity {
private List<Fruit> fruitList = new ArrayList<>();
private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview);
setTitle("Recycle View Demo");
rv = (RecyclerView) findViewById(R.id.recycle_view);
initFruits();
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(layoutManager);
FruitAdapterAdv fruitAdapterAdv = new FruitAdapterAdv(fruitList);
rv.setAdapter(fruitAdapterAdv);
}
private void initFruits() {
for (int i = 0; i < 20; i++) {
Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
fruitList.add(grape);
Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
fruitList.add(mango);
Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
fruitList.add(orange);
Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
fruitList.add(pear);
Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
fruitList.add(watermelon);
}
}
}
我们这里同样使用initFruits()方法来构造较多的数据。在onCreate()方法中,先渠道到RecycleView的实例,然后创建了一个LinearLayoutManager对象,并将它设置到RecycleView当中。LayoutManager用于指定RecycleView的布局方式,这里用的LinearLayoutManager是线性布局的意思,可以实现和ListView类似的效果。接下来我们创建了FruitAdapterAdv的实例,并将水果数据传到FruitAdapterAdv的构造函数中,最后调用RecycleView的setAdapter()方法来完成适配器的设置,这样RecycleView和数据之间的关联就建立完成了。
运行一下程序:
2、横向滚动
我们已经知道,ListView的扩展性不是特别优秀,如果想实现横着滚动的效果,就做不到了。但是使用RecycleView就能办得到,而且还非常简单。
首先需要修改一下fruits子项的布局,之前这个布局中的元素是水平的,这样适用于竖着滚动。但我们需要横着滚动,就应该把fruits的元素改成垂直排列。
<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/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
</LinearLayout>
这里我们除了把LinearLayout的排列方向改了,宽度也做了调整,设置为100dp。因为考虑到有的水果名字长,有的水果名字短,如果wrap_content的话就会不统一,很难看。因此统一设置宽度为100dp。ImageView和TextView都设置成了水平居中显示,并且通过。layout_marginTop来给图片和文字间增加一些间距。
接下来修改Activity中的代码:
public class RecyclehorActivity extends BaseActivity {
private List<Fruit> fruitList = new ArrayList<>();
private RecyclerView rvh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclehor);
setTitle("Recycle View Horizontal");
initFruits();
rvh = findViewById(R.id.recycle_view_hor);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
rvh.setLayoutManager(layoutManager);
FruitAdapterHor fruitAdapterHor = new FruitAdapterHor(fruitList);
rvh.setAdapter(fruitAdapterHor);
}
...
}
可以看到和刚才唯一不同的地方在于多添加了一行代码,调用了LinearLayoutManager的setOrientation()方法,我们传入了LinearLayoutManager.HORIZONTAL表示让布局横向排列,这样RecycleView就可以横向滚动了。(FruitAdapterHor是为了复习上面所学的,除了名字外其他都一样)
重新运行程序:
3、瀑布流
除了LinearLayoutManager之外,RecycleView还提供了GridLayoutManager和StaggeredLayoutManager这两种内置的布局排列方式。GridLayoutManager可以用于实现网格布局,StaggeredLayoutManager可以用于实现瀑布流布局。
修改xml布局文件:
<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/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp"/>
</LinearLayout>
将layout_width改回了match_parent,因为瀑布流的布局宽度应该根据布局的列数自动适配。另外,使用了layout_margin让子项之前有一点间距。另外,改了TextView为左对齐,因为我们要制造瀑布流就得“有长有短”。
修改Activity的代码:
public class RecycleviewStagActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
private RecyclerView rvs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview_stag);
setTitle("Recycle View Staggered");
initFruits();
rvs = findViewById(R.id.recycle_view_stag);
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
rvs.setLayoutManager(staggeredGridLayoutManager);
FruitAdapterSta fruitAdapterSta = new FruitAdapterSta(fruitList);
rvs.setAdapter(fruitAdapterSta);
}
private void initFruits() {
for (int i = 0; i < 5; i++) {
Fruit apple = new Fruit("Apple Apple Apple Apple Apple Apple Apple Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
fruitList.add(grape);
Fruit mango = new Fruit("Mango Mango Mango Mango Mango Mango", R.drawable.mango_pic);
fruitList.add(mango);
Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
fruitList.add(orange);
Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
fruitList.add(pear);
Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry Strawberry Strawberry Strawberry Strawberry Strawberry", R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
fruitList.add(watermelon);
}
}
}
首先,在onCreate()方法中,创建了一个StaggeredGridLayoutManager的实例,StaggeredGridLayoutManager的构造函数接收两个参数,第一个参数用于指定布局的列数,传入3表示会把布局分为3列;第二个参数用于指定布局的排列方向,传入StaggeredGridLayoutManager.VERTICAL表示会让布局纵向排列,最后再把创建好的实例设置到RecycleView中。后面为了能体现出瀑布流,我们把个别水果的名字加长了一下。
现在重新运行一下程序
关于RecycleView就先简单的学习到这里。
关注获取更多