RecyclerView实现瀑布流效果

在上一节,我们已经简单说过StaggeredGridLayoutManager的使用,这一节给出个具体的例子,我们利用他做一个照片墙的功能,先看下效果

RecyclerView实现瀑布流效果

首先是Item的布局item_recycler_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
    <ImageView
        android:id="@+id/iv_item_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"/>
    <TextView
        android:id="@+id/tv_item_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:text="Text数据显示..."
        android:textSize="16sp" />

</LinearLayout>

给每张照片写一个实体类
public class Photo {
    private int img;
    private String title;

    public Photo() {
        super();
    }

    public Photo(int img, String title) {
        this.img = img;
        this.title = title;
    }

    public int getImg() {
        return img;
    }

    public void setImg(int img) {
        this.img = img;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

自定义一个MyRecyclerAdapter

public class MyRecyclerAdapter extends Adapter<MyRecyclerAdapter.ViewHolder> {
    private List<Photo> photoList;

    public MyRecyclerAdapter(List<Photo> list) {
        super();
        this.photoList = list;
    }

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

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.item_tv.setText(photoList.get(position).getTitle());
        holder.item_iv.setBackgroundResource(photoList.get(position).getImg());
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.item_recycler_layout, parent, false);
        //view.setBackgroundColor(Color.RED);  
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView item_tv;
        public ImageView item_iv;

        public ViewHolder(View view) {
            super(view);
            item_tv = (TextView) view.findViewById(R.id.tv_item_text);
            item_iv = (ImageView) view.findViewById(R.id.iv_item_img);
        }
    }
}
可以看出,MyRecyclerAdapter功能很简单,只实现了组件的加载和数据绑定

看下MainActivity
public class MainActivity extends Activity {
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLayoutManager;
    private MyRecyclerAdapter mAdapter;
    private List<Photo> mPhotoList;
    private int[] indexs = new int[]{R.mipmap.a, R.mipmap.b,
            R.mipmap.c, R.mipmap.e, R.mipmap.f, R.mipmap.g};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);

        //瀑布流式布局
        StaggeredGridLayoutManager staggeredGridLayoutManager =
                new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
        initData();
        // 创建适配器,并且设置
        mAdapter = new MyRecyclerAdapter(mPhotoList);
        // 设置adapter
        mRecyclerView.setAdapter(mAdapter);
        // 设置Item增加、移除动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        // 设置间距
        mRecyclerView.addItemDecoration(new SpaceItemDecoration(5));

    }

    private void initData() {
        mPhotoList = new ArrayList<>();
        for (int i = 0; i < indexs.length; i++) {
            Photo photo = new Photo();
            photo.setImg(indexs[i]);
            photo.setTitle("图片" + i);
            mPhotoList.add(photo);
        }
    }

}

在MainActivity中进行了数据的初始化,实际应用中,我们应该是从网络获取数据了,这也只是个model而已,前面我们说过给瀑布流加分割线的方法,但是分割线可能并不是我们想要的,例如我们只想有点间距就行了,无奈,RecyclerView并没有相关方法,我们通过改造分割线来实现下

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {


    private int space;

    public SpaceItemDecoration(int space) {
        this.space = space;
    }

    private int getSpanCount(RecyclerView parent) {
        // 列数
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager)
                    .getSpanCount();
        }
        return spanCount;
    }
    private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
                                int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                {
                    return true;
                }
            } else {
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }

    private boolean isLastRow(RecyclerView parent, int pos, int spanCount,
                              int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
                return true;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            // StaggeredGridLayoutManager 且纵向滚动
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                childCount = childCount - childCount % spanCount;
                // 如果是最后一行,则不需要绘制底部
                if (pos >= childCount)
                    return true;
            } else
            // StaggeredGridLayoutManager 且横向滚动
            {
                // 如果是最后一行,则不需要绘制底部
                if ((pos + 1) % spanCount == 0) {
                    return true;
                }
            }
        }
        return false;
    }

    @Deprecated
    public void getItemOffsets(Rect outRect, int itemPosition,View view,
                               RecyclerView parent, RecyclerView.State state) {
        int spanCount = getSpanCount(parent);

        int childCount = parent.getAdapter().getItemCount();

        if (isLastRow(parent, itemPosition, spanCount, childCount)) {// 如果是最后一行,则不需要绘制底部
            outRect.set(0, 0, space, 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount)) {// 如果是最后一列,则不需要绘制右边
            outRect.set(0, 0, 0, space);
        } else {
            outRect.set(0, 0, space, space);
        }

    }
}
哈哈,其实和分割线差别不大,只是我们的分割线是透明的罢了,在这里我们要判断是否是最后一行,如果是,就不再绘制下面的分割线;判断是否是最后一列,如果是,就不再绘制右边的分割线,好了,效果实现!

参考:


上一篇:python 技术篇-时间戳的获取,记录程序处理时间


下一篇:gin框架中图形验证码的生成和验证