Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

  前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框、DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框。这一节我们介绍几个新的API控件SwipeRefreshLayout、RecyclerView和CardView,这几个API控件都是google在Android5.0推出的。下面我们来学习一下这几个新的控件:

SwiperefreshLayout

  SwiperefreshLayout是Android提供的一个下拉刷新的布局,继承自ViewGroup,在support v4兼容包下,想要使用必须把你的support library的版本升级到19.1。相信很多Android开发者都对ActionBarPullToRefresh这个框架比较熟悉。SwiperefreshLayout的推出,对于我们实现下拉刷新就变得非常简单了。

下面是SwiperefreshLayout的常用方法:

  • setOnRefreshListener(OnRefreshListener): 为布局添加一个Listener
  • setRefreshing(boolean): 设置是否处于刷新状态
  • isRefreshing(): 检查是否处于刷新状态
  • setColorScheme(): 设置进度条的颜色主题,最多能设置四种
  • setProgressBackgroundColorSchemeResource(): 设置进度条背景颜色

使用的话就直接在XML文件中使用即可,例如:

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sl_grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
</android.support.v4.widget.SwipeRefreshLayout>

这个一个布局容器,我们可以在其上添加其他的控件。附上SwiperefreshLayout的国内镜像API

RecyclerView

  RecyclerView是Android5.0之后推出的一个新的控件,这是一个强大的滑动组件,比ListView拥有更多的功能。官方介绍RecyclerView是ListView的升级版,RecyclerView有如下的优点:

  • RecylerView封装了viewholder的回收复用,也就是说是RecyclerView是面向ViewHolder编程而不是View
  • RecyclerView高度解耦,非常灵活。RecyclerView不仅可以像ListView一样显示列表视图,还可以显示网格视图等。只要你传入不同的LayoutManager就可以控制显示不同的样式,RecyclerView提供的LayoutManager有:LinearLayoutManager横向或者纵向滑动;GridLayoutManager网格布局显示;StaggeredGridLayoutManager瀑布流显示效果。
  • RecyclerView可以通过ItemDecoration控制Item之间的间隔
  • RecyclerView可以通过ItemAnimator控制Item的增删动画

关于具体的RecyclerView的介绍推荐两篇博客,Android RecyclerView 使用完全解析 体验艺术般的控件Android开发之RecyclerView的使用全解 这里就不在做过多的描述了。后面我们会通过几个例子体会一下RecyclerView的用法。

附上RecyclerView的国内镜像API

CardView

  CardView也是Android5.0推出的一个全新控件,CardView类似于FrameLayout,但是添加了圆角和阴影效果,常用于ListView和RecyclerView中,是一种容器,可以在CardView之上添加其它控件。下面我们了解一下CardView的常用属性:

  • card_view:cardElevation:阴影的大小
  • card_view:cardMaxElevation:阴影最大高度
  • card_view:cardBackgroundColor:卡片的背景色
  • card_view:cardCornerRadius:卡片的圆角大小
  • card_view:contentPadding:卡片内容的内边距
  • card_view:contentPaddingBottom:卡片内容的底部内边距
  • card_view:contentPaddingTop:卡片内容的上内边距
  • card_view:contentPaddingLeft:卡片内容的左内边距
  • card_view:contentPaddingRight:卡片内容的右内边距
  • card_view:contentPaddingStart:卡片内容的左内边距
  • card_view:contentPaddingEnd:卡片内容的右内边距
  • card_view:cardUseCompatPadding:设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式
  • card_view:cardPreventConrerOverlap:在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠

附上CardView的国内镜像API

关于SwiperefreshLayout、RecyclerView和CardView就简单介绍到这里,下面我们用几个例子体会一下这三个控件组合的效果:

使用RecyclerView需要在Gradle中添加:

compile ‘com.android.support:recyclerview-v7:24.0.0‘

使用CardView需要在Gradle中添加:

compile ‘com.android.support:cardview-v7:24.0.0‘

SwiperefreshLayout、RecyclerView和CardView组合实现普通的列表视图,有下拉刷新功能:

首先是布局文件的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="@null"
android:scrollbars="vertical" />

</android.support.v4.widget.SwipeRefreshLayout>

Item布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cv_rvlist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardCornerRadius="5dp">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/iv_rvlist_icon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="8dp"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/tv_rvlist_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/iv_rvlist_icon"
        android:text="zheshiwenben"
        android:textColor="#000000"
        android:textSize="16sp" />

</RelativeLayout>

</android.support.v7.widget.CardView>

接着是适配器的代码:

package com.example.newapidemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.newapidemo.OnItemClickListener;
import com.example.newapidemo.R;
import com.example.newapidemo.domain.RVTest;

import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 * 自定义RecyclerView的适配器
 */
public class RVListAdapter extends RecyclerView.Adapter<RVListAdapter.RVListViewHolder> {

private Context mContext;
private List<RVTest> datas;
private OnItemClickListener mListener;

/**
 * 暴露出去的设置item点击事件
 *
 * @param mListener
 */
public void setOnItemClickListener(OnItemClickListener mListener) {
    this.mListener = mListener;
}

public RVListAdapter(Context mContext, List<RVTest> datas) {
    this.mContext = mContext;
    this.datas = datas;
}

/**
 * 为每一个Item inflate一个View,返回一个ViewHolder,将View封装在ViewHolder中,省略掉setTag和getTag的步骤
 *
 * @param parent
 * @param viewType
 * @return
 */

@Override
public RVListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.item_rvlist, parent, false);
    //给每一个item设置点击监听
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mListener != null) {
                //调用getTag取出数据
                mListener.onItemClick(view, (String) view.getTag());
            }
        }
    });
    return new RVListViewHolder(view);
}

/**
 * 将数据渲染到View中
 *
 * @param holder
 * @param position
 */
@Override
public void onBindViewHolder(RVListViewHolder holder, int position) {
    //将数据通过调用setTag方法保存在ItemView里面,然后可以调用getTag取出数据
    holder.itemView.setTag(datas.get(position).getContent());
    holder.iv_rvlist_icon.setImageResource(R.mipmap.ic_launcher);
    holder.tv_rvlist_text.setText(datas.get(position).getContent());
}

/**
 * 获取到Item的数量
 *
 * @return
 */
@Override
public int getItemCount() {
    return datas.size();
}

/**
 * 批量添加数据
 *
 * @param testList
 */
public void addItems(List<RVTest> testList) {
    if (testList != null) {
        datas.addAll(0, testList);
        notifyItemRangeChanged(0, testList.size());
    }
}

/**
 * ViewHolder,需要继承RecyclerView.ViewHolder
 */
public static class RVListViewHolder extends RecyclerView.ViewHolder {
    private ImageView iv_rvlist_icon;
    private TextView tv_rvlist_text;

    public RVListViewHolder(View itemView) {
        super(itemView);
        iv_rvlist_icon = (ImageView) itemView.findViewById(R.id.iv_rvlist_icon);
        tv_rvlist_text = (TextView) itemView.findViewById(R.id.tv_rvlist_text);
    }
}
}

由于RecyclerView不像ListView一样提供Item点击事件,所以我们需要自己去实现,Item点击和长按事件,按自己需求去实现,这里的话就实现Item点击事件。

最后是Activity代码:

package com.example.newapidemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.example.newapidemo.adapter.RVListAdapter;
import com.example.newapidemo.domain.RVTest;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 */
public class RVListActivity extends AppCompatActivity {
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
private RVListAdapter adapter;
private List<RVTest> datas;
public static String TAG = "RVListActivity";

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_rvlist);
    swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.sl);
    recyclerView = (RecyclerView) findViewById(R.id.recycler);
    linearLayoutManager = new LinearLayoutManager(this);
    //设置为垂直布局,这也是默认的
    linearLayoutManager.setOrientation(OrientationHelper.VERTICAL);
    //设置布局管理器
    recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
    //设置增加或删除条目的动画
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    datas = new ArrayList<>();
    initData();
    adapter = new RVListAdapter(this, datas);
    //设置适配器
    recyclerView.setAdapter(adapter);
    //设置Item点击监听
    adapter.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(View view, String data) {
            ToastUtils.showToast(RVListActivity.this, data);
        }
    });
    //设置刷新时动画的背景颜色
    swipeRefreshLayout.setProgressBackgroundColorSchemeResource(android.R.color.white);
    //设置下拉刷新时候动画的颜色,可以一次设置四个
    swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light,
            +android.R.color.holo_red_light, android.R.color.holo_orange_light,
            +android.R.color.holo_green_light);
    //设置刷新监听
    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            new UpdateTask().execute();
        }
    });

}

/**
 * 初始化数据
 */
private void initData() {
    for (int i = 0; i < 20; i++) {
        datas.add(new RVTest(i, "这是第 " + (i + 1) + " 条测试数据"));
    }
}

/**
 * 模拟加载数据
 */
private class UpdateTask extends AsyncTask<Void, Void, List<RVTest>> {
    @Override
    protected List<RVTest> doInBackground(Void... voids) {
        try {
            //休眠3秒钟
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<RVTest> data = new ArrayList<>();
        data.add(new RVTest(0, "下拉刷新出来的数据1"));
        data.add(new RVTest(1, "下拉刷新出来的数据2"));
        data.add(new RVTest(2, "下拉刷新出来的数据3"));
        return data;
    }

    @Override
    protected void onPostExecute(List<RVTest> testList) {
        adapter.addItems(testList);
        //停止刷新
        swipeRefreshLayout.setRefreshing(false);
        //RecyclerView滑动到第一个
        recyclerView.scrollToPosition(0);
        ToastUtils.showToast(RVListActivity.this, "刷新了3条数据");
    }
}
}

在这里通过用SwiperefreshLayout实现下拉刷新功能,非常简单,下拉刷新加载数据在这里只是模拟网络请求数据,然后实现的效果图如下:

这里是实现类似于ListView的效果,不过用这种组合比较符合google的MD设计效果,在实际的开发中我们可以按需求扩展。下面是SwiperefreshLayout、RecyclerView和CardView实现网格效果

SwiperefreshLayout、RecyclerView和CardView实现网格效果:

首先依然是布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_grid"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.v7.widget.RecyclerView>

</android.support.v4.widget.SwipeRefreshLayout>

Item布局代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="3dp"
android:orientation="vertical"
android:padding="5dp"
card_view:cardCornerRadius="5dp">

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:layout_gravity="center"
    android:padding="5dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/tv_rvgrid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="浏览器"
        android:textColor="#000"
        android:textSize="14sp" />
</LinearLayout>

</android.support.v7.widget.CardView>

接着是适配器代码,跟上面一个例子的适配器代码基本一样,就没有写那么多注释了:

package com.example.newapidemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.newapidemo.OnItemClickListener;
import com.example.newapidemo.R;
import com.example.newapidemo.domain.RVTest;

import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 */
public class RVGridAdapter extends RecyclerView.Adapter<RVGridAdapter.RVGridViewHolder> {

private Context mContext;
private List<RVTest> datas;
private OnItemClickListener onItemClickListener;

public void setOnItemClickListener(OnItemClickListener listener) {
    this.onItemClickListener = listener;
}

public RVGridAdapter(Context mContext, List<RVTest> datas) {
    this.mContext = mContext;
    this.datas = datas;
}

@Override
public RVGridViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.item_rvgrid, parent, false);
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (onItemClickListener != null) {
                onItemClickListener.onItemClick(view, (String) view.getTag());
            }
        }
    });
    return new RVGridViewHolder(view);
}

@Override
public void onBindViewHolder(RVGridViewHolder holder, int position) {
    holder.itemView.setTag(datas.get(position).getContent());
    holder.tv_rvgrid.setText(datas.get(position).getContent());
}

@Override
public int getItemCount() {
    return datas.size();
}
/**
 * 批量添加数据
 *
 * @param testList
 */
public void addItems(List<RVTest> testList) {
    if (testList != null) {
        datas.addAll(0, testList);
        notifyItemRangeChanged(0, testList.size());
    }
}
public static class RVGridViewHolder extends RecyclerView.ViewHolder {
    TextView tv_rvgrid;

    public RVGridViewHolder(View itemView) {
        super(itemView);
        tv_rvgrid = (TextView) itemView.findViewById(R.id.tv_rvgrid);
    }
}
}

最后是Activity代码:

package com.example.newapidemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.example.newapidemo.adapter.RVGridAdapter;
import com.example.newapidemo.domain.RVTest;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 */
public class RVGridActivity extends AppCompatActivity {
private SwipeRefreshLayout sl_grid;
private RecyclerView rv_grid;
private GridLayoutManager gridLayoutManager;
private RVGridAdapter adapter;
private List<RVTest> datas;
private String[] names = {"浏览器", "工具", "图库", "设置", "微信", "安全", "电话", "短信", "QQ",
        "联系人", "起点", "云音乐", "游戏", "爱消除", "系统",
        "笔记", "随手记", "计算器", "文件", "天气"};

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_rvgrid);
    rv_grid = (RecyclerView) findViewById(R.id.rv_grid);
    sl_grid = (SwipeRefreshLayout) findViewById(R.id.sl_grid);
    gridLayoutManager = new GridLayoutManager(this, 4);
    rv_grid.setLayoutManager(gridLayoutManager);
    rv_grid.setItemAnimator(new DefaultItemAnimator());
    //设置刷新时动画的背景颜色
    sl_grid.setProgressBackgroundColorSchemeResource(android.R.color.white);
    //设置下拉刷新时候动画的颜色,可以一次设置四个
    sl_grid.setColorSchemeResources(android.R.color.holo_blue_light,
            +android.R.color.holo_red_light, android.R.color.holo_orange_light,
            +android.R.color.holo_green_light);
    initData();
    adapter = new RVGridAdapter(this, datas);
    rv_grid.setAdapter(adapter);
    adapter.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(View view, String data) {
            ToastUtils.showToast(RVGridActivity.this, "点击的是:" + data);
        }
    });
    sl_grid.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            new UpdateTask().execute();
        }
    });
}

private void initData() {
    datas = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        datas.add(new RVTest(i, names[i]));
    }
}

/**
 * 模拟加载数据
 */
private class UpdateTask extends AsyncTask<Void, Void, List<RVTest>> {
    @Override
    protected List<RVTest> doInBackground(Void... voids) {
        try {
            //休眠3秒钟
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<RVTest> data = new ArrayList<>();
        data.add(new RVTest(0, "数据1"));
        data.add(new RVTest(1, "数据2"));
        data.add(new RVTest(2, "数据3"));
        data.add(new RVTest(2, "数据4"));
        return data;
    }

    @Override
    protected void onPostExecute(List<RVTest> testList) {
        adapter.addItems(testList);
        //停止刷新
        sl_grid.setRefreshing(false);
        //RecyclerView滑动到第一个
        rv_grid.scrollToPosition(0);
        ToastUtils.showToast(RVGridActivity.this, "刷新了4条数据");
    }
}
}

其实这个例子跟上一个比较类似,只是在RecyclerView中传入不同的布局管理器而已,这样我们在实现网格效果就比较简单了,然后是效果图:

这里简单实现类似网格视图的效果,跟上一个例子比较相似,就不再做很多介绍了,下面是实现瀑布流的效果:

首先是布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl_stagger"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_stagger"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:cacheColorHint="@null"
    android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>

Item布局代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_margin="5dp"
android:orientation="vertical"
card_view:cardBackgroundColor="#FFFF33"
android:padding="5dp"
card_view:cardCornerRadius="5dp">

<TextView
    android:id="@+id/tv_rvstagger"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:text="浏览器"

    android:textColor="#000"
    android:textSize="14sp" />

</android.support.v7.widget.CardView>

适配器代码:

package com.example.newapidemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.newapidemo.OnItemClickListener;
import com.example.newapidemo.R;
import com.example.newapidemo.domain.RVTest;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 */
public class RVStaggerAdapter extends RecyclerView.Adapter<RVStaggerAdapter.RVStaggerViewHolder> {
private Context mContext;
private List<RVTest> datas;
private OnItemClickListener onItemClickListener;
private List<Integer> heights;

public RVStaggerAdapter(Context mContext, List<RVTest> datas) {
    this.mContext = mContext;
    this.datas = datas;
    getRandomHeight(this.datas);
}

public void setOnItemClickListener(OnItemClickListener listener) {
    this.onItemClickListener = listener;
}

@Override
public RVStaggerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.item_rvstagger, parent, false);
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (onItemClickListener != null) {
                onItemClickListener.onItemClick(view, (String) view.getTag());
            }
        }
    });
    return new RVStaggerViewHolder(view);
}

@Override
public void onBindViewHolder(RVStaggerViewHolder holder, int position) {
    //得到item的LayoutParams布局参数
    ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
    //把随机的高度赋予item布局
    params.height = heights.get(position);
    //把params设置给item布局
    holder.itemView.setLayoutParams(params);
    holder.itemView.setTag(datas.get(position).getContent());
    holder.tv_rvstagger.setText(datas.get(position).getContent());
}

@Override
public int getItemCount() {
    return datas.size();
}

/**
 * 批量添加数据
 *
 * @param testList
 */
public void addItems(List<RVTest> testList) {
    if (testList != null) {
        datas.addAll(0, testList);
        notifyItemRangeChanged(0, testList.size());
    }
}

/**
 * 随机得到Item的高度
 *
 * @param lists
 */
private void getRandomHeight(List<RVTest> lists) {
    heights = new ArrayList<>();
    for (int i = 0; i < lists.size(); i++) {
        heights.add((int) (200 + Math.random() * 400));
    }
}

public static class RVStaggerViewHolder extends RecyclerView.ViewHolder {
    TextView tv_rvstagger;

    public RVStaggerViewHolder(View itemView) {
        super(itemView);
        tv_rvstagger = (TextView) itemView.findViewById(R.id.tv_rvstagger);
    }
}

}

最后是Activity代码:

package com.example.newapidemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

import com.example.newapidemo.adapter.RVStaggerAdapter;
import com.example.newapidemo.domain.RVTest;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Devin on 2016/7/14.
 */
public class RVStaggeredActivity extends AppCompatActivity {
private SwipeRefreshLayout sl_stagger;
private RecyclerView rv_stagger;
private StaggeredGridLayoutManager layoutManager;
private List<RVTest> datas;
private String[] names = {"浏览器", "工具", "图库", "设置", "微信", "安全", "电话", "短信", "QQ", "汽车"};
private int[] icons = {R.drawable.icon0, R.drawable.icon1,
        R.drawable.icon2, R.drawable.icon3,
        R.drawable.icon4, R.drawable.icon5,
        R.drawable.icon6, R.drawable.icon7,
        R.drawable.icon8, R.drawable.icon9};
private RVStaggerAdapter adapter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_rvstagger);
    sl_stagger = (SwipeRefreshLayout) findViewById(R.id.sl_stagger);
    rv_stagger = (RecyclerView) findViewById(R.id.rv_stagger);
    layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    rv_stagger.setLayoutManager(layoutManager);
    initData();
    adapter = new RVStaggerAdapter(this, datas);
    rv_stagger.setAdapter(adapter);
    //设置刷新时动画的背景颜色
    sl_stagger.setProgressBackgroundColorSchemeResource(android.R.color.white);
    //设置下拉刷新时候动画的颜色,可以一次设置四个
    sl_stagger.setColorSchemeResources(android.R.color.holo_blue_light,
            +android.R.color.holo_red_light, android.R.color.holo_orange_light,
            +android.R.color.holo_green_light);
    adapter.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(View view, String data) {
            ToastUtils.showToast(RVStaggeredActivity.this, "点击的是:" + data);
        }
    });
    sl_stagger.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            new UpdateTask().execute();
        }
    });

}

private void initData() {
    datas = new ArrayList<>();
    for (int i = 0; i < 30; i++) {
        datas.add(new RVTest(i, "原始数据" + i));
    }
}

/**
 * 模拟加载数据
 */
private class UpdateTask extends AsyncTask<Void, Void, List<RVTest>> {
    @Override
    protected List<RVTest> doInBackground(Void... voids) {
        try {
            //休眠3秒钟
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<RVTest> data = new ArrayList<>();
        data.add(new RVTest(0, "数据1"));
        data.add(new RVTest(0, "数据2"));
        data.add(new RVTest(0, "数据3"));
        data.add(new RVTest(0, "数据4"));
        return data;
    }

    @Override
    protected void onPostExecute(List<RVTest> testList) {
        adapter.addItems(testList);
        //停止刷新
        sl_stagger.setRefreshing(false);
        //RecyclerView滑动到第一个
        rv_stagger.scrollToPosition(0);
        ToastUtils.showToast(RVStaggeredActivity.this, "刷新了4条数据");
    }
}
}

实现效果图如下:

这样就可以实现瀑布流效果了,关于这三个控件的组合就简单介绍到这里,下一节,我们继续用这三个控件实现拖拽和滑动效果。

时间: 07-15

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView的相关文章

Android学习笔记(十九):建立自己的ListView

在之前的例子中,我们通过设置adapter的getView()来编写我们所希望的UI,然而在面向对编程中,我们希望能够创建自己的ListView,例如类的名字为com.wei.android.learning.RatingView,只要在XML中用我们自己的RatingView对ListView来替代,就可以实现我们的风格,并前在源代码中向使用ListView一样简单调用就可以了. 实现的目标 在Android XML文件中,可以如下调用我们的RatingView: <com.wei.andro

Android学习笔记二十.使用ContentProvider实现数据共享(二).URI...工具类

一.UriMatcher与ContentUris工具类 UriMatcher 1.功能概述 开发ContentProvider时所实现的query().insert().delete().update()方法的第一个参数为Uri参数,该参数由ContentResolver调用这些方法时传入.在上一篇博文中的实例,并没有真正对数据进行操作,因此ContentProvider并未对Uri参数进行任何判断.所以为了确定该ContentProvider实际能处理的Uri,以确定每个方法中Uri参数所操作

[傅里叶变换及其应用学习笔记] 二十九. 高维Ш函数修改版

一维Ш函数复习 我们前面(十六课,十七课)已经学习过一维的Ш函数,标准的Ш函数表现为无数个脉冲函数分布在整数点上, 我们定义Ш为 $Ш(x) = \displaystyle{ \sum_{k=-\infty}^{\infty}\delta(x-k) }$ 而Ш函数最为深刻的一个性质就是:Ш的傅里叶变换是它自身 $\mathcal{F}Ш=Ш$ 进一步推广到脉冲间隔为$p$的函数$Ш_p$ $\displaystyle{ Ш_p(x)=\sum_{k=-\infty}^{\infty}\delta

Android学习笔记二十二.使用ContentProvider实现数据共享(五).监听ContentProvider的数据改变

一.使用ContentProvider管理多媒体内容 Android提供了Camera程序来支持拍照.拍摄视频,用户拍摄的相片.视频都将存放在固定的位置.Android同样为这些多媒体内容提供了ContentProvider,所以我们可以通过使用ContentProvider实现其他应用直接访问Camera所拍摄的照片.视频等. 1.多媒体ContentProvider的Uri (1)MediaStore.Audio.Media.EXTERNAL_CONTENT_URI:存储在外部存储器(SD卡

PHP学习笔记二十九【接口】

<?php //定义接口 //接口可以定义属性,但必须是常量而且是public //接口的所有方法必须是public interface Iusb{ public function start(); public function stop(); } //手机类实现接口关键字implements,必须实现这个所有方法 //类可以同时实现多个接口 //一个类可以实现多个接口 implements 接口1,接口2,接口 class Phone implements Iusb{ public func

Linux学习笔记&lt;二十九&gt;——http服务

基础概念: HTTP:Hyper Text Transfer Protocol 超文本传输协议 versions: HTTP/0.9:只接收GET一种请求方法,只支持纯文本 HTTP/1.0:支持PUT.POST.DELETE和HEAD,支持MINE HTTP/1.1:在HTTP/1.0的基础上,增加了缓存功能,支持长连接,支持管道方式同时                  发送多个请求 HTTP请求方法:获取资源的方法 HTTP/0.9:GET HTTP/1.0:PUT(修改服务器上的内容),

《Javascript权威指南》学习笔记之十九--HTML5 DOM新标准---处理文档元信息和管理交互能力

一.了解DOM 1.DOM是Document Object Model的缩写,即文档对象类型,是文档在内存中的表示形式,是一个应用程序接口,定义了文档的逻辑结构以及一套访问和处理文档的方法. 2.HTML DOM与Core DOM的区别:前者提供了大量的方法和属性,与现有的程序模型一致,更便于脚本的编写者控制. 二.document对象 使用window.document属性返回一个document对象,代表当前window内加载的文档.window可以省略.winName.document返回

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意

【Unity 3D】学习笔记二十八:unity工具类

unity为开发者提供了很多方便开发的工具,他们都是由系统封装的一些功能和方法.比如说:实现时间的time类,获取随机数的Random.Range( )方法等等. 时间类 time类,主要用来获取当前的系统时间. using UnityEngine; using System.Collections; public class Script_04_13 : MonoBehaviour { void OnGUI() { GUILayout.Label("当前游戏时间:" + Time.t