Android开发入门教程

Android开发学习 -- Day7 UI开发(三)

2018-03-21  本文已影响18人  h080294

上一章讲到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就先简单的学习到这里。

关注获取更多
上一篇 下一篇

猜你喜欢

热点阅读