android实现底部上拉,Android RecyclerView实现瀑布流、下拉刷新和上拉加载

d1465bcba0f1

这是一个使用RecyclerView实现瀑布流,并带上下拉刷新和上拉加载功能的Demo。做Demo之前看了很多网友们实现瀑布流踩的坑,所以这个Demo把那些常见的坑都填上了,目前没发现有什么问题。

关于下拉刷新和上拉加载,说实话我每次做这个功能都很头疼,因为一直没有找到一个好的方式或者说好的库,能让我只拿着一个框架就去适配所有需要下拉刷新和上拉加载功能的ViewGroup,并且可以自己实现Header和Footer。今天自己鼓捣了很久瀑布流的Header和Footer,然而光是Footer我就花费了不少功夫,最后在寻找好的Header实现方式的过程中发现了一个能满足我全部需求的库——#

先贴完整代码

首先是Activity文件

package com.adminstrator.guaguakaapplication;

import android.os.Handler;

import android.support.annotation.NonNull;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.support.v7.widget.RecyclerView;

import android.support.v7.widget.StaggeredGridLayoutManager;

import com.adminstrator.guaguakaapplication.widget.StaggeredDividerItemDecoration;

import com.scwang.smartrefresh.layout.SmartRefreshLayout;

import com.scwang.smartrefresh.layout.api.RefreshLayout;

import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener;

import com.scwang.smartrefresh.layout.listener.OnRefreshListener;

import java.util.ArrayList;

public class WaterFallActivity extends AppCompatActivity {

private ArrayList imageIds = new ArrayList<>();

private int[] ids = {R.drawable.p1,R.drawable.p2,R.drawable.p3,R.drawable.p4,R.drawable.p5,R.drawable.p6,R.drawable.p7,

R.drawable.p8,R.drawable.p9,R.drawable.p10,R.drawable.p11,R.drawable.p12,R.drawable.p13,R.drawable.p14,};

private RecyclerView rv_waterfall;

private DemoAdapter adapter;

private SmartRefreshLayout refreshlayout;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_water_fall);

refreshlayout = findViewById(R.id.refreshlayout);

rv_waterfall = findViewById(R.id.rv_waterfall);

rv_waterfall.setHasFixedSize(true);

rv_waterfall.setItemAnimator(null);

//垂直方向的2列

final StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);

//防止Item切换

layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);

rv_waterfall.setLayoutManager(layoutManager);

final int spanCount = 2;

rv_waterfall.addItemDecoration(new StaggeredDividerItemDecoration(this,10,spanCount));

//解决底部滚动到顶部时,顶部item上方偶尔会出现一大片间隔的问题

rv_waterfall.addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

int[] first = new int[spanCount];

layoutManager.findFirstCompletelyVisibleItemPositions(first);

if (newState == RecyclerView.SCROLL_STATE_IDLE && (first[0] == 1 || first[1] == 1)) {

layoutManager.invalidateSpanAssignments();

}

}

});

//设置Adapter

for(int i = 0 ; i < ids.length;i++){

imageIds.add(ids[i]);

}

adapter = new DemoAdapter();

rv_waterfall.setAdapter(adapter);

adapter.replaceAll(imageIds);

//设置下拉刷新和上拉加载监听

refreshlayout.setOnRefreshListener(new OnRefreshListener() {

@Override

public void onRefresh(@NonNull final RefreshLayout refreshLayout) {

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

adapter.replaceAll(getData());

refreshLayout.finishRefresh();

}

},2000);

}

});

refreshlayout.setOnLoadMoreListener(new OnLoadMoreListener() {

@Override

public void onLoadMore(@NonNull final RefreshLayout refreshLayout) {

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

adapter.addData(adapter.getItemCount(),getData());

refreshLayout.finishLoadMore();

}

},2000);

}

});

}

private ArrayList getData() {

ArrayList list = new ArrayList<>();

for(int i = 0 ; i < 6;i++){

list.add(ids[i]);

}

return list;

}

}

Activity的布局文件,使用了SmartRefreshLayout。Header和Footer我都是用了一个360度旋转的Loading图片。这种Header和Footer的添加方式可以让你随意定制自己想要的任何样式,及其方便。SmartRefreshLayout有更丰富的功能,建议没了解过的童鞋去看看。

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context="com.adminstrator.guaguakaapplication.WaterFallActivity">

android:id="@+id/refreshlayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/rl_header_refresh"

android:layout_width="match_parent"

android:layout_height="60dp"

>

android:id="@+id/progress_loading_dialog"

android:layout_width="30dp"

android:layout_height="30dp"

android:background="@null"

android:indeterminateDrawable="@drawable/loading_anim"

android:indeterminateBehavior="repeat"

android:layout_centerInParent="true"

/>

android:id="@+id/rv_waterfall"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_marginBottom="10dp"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:layout_marginTop="10dp" />

android:id="@+id/rl_footer_refresh"

android:layout_width="match_parent"

android:layout_height="60dp"

>

android:id="@+id/progress_loading_dialog2"

android:layout_width="30dp"

android:layout_height="30dp"

android:background="@null"

android:indeterminateDrawable="@drawable/loading_anim"

android:indeterminateBehavior="repeat"

android:layout_centerInParent="true"

/>

loading_anim也贴出来

android:drawable="@drawable/loading"

android:fromDegrees="0.0"

android:pivotX="50.0%"

android:pivotY="50.0%"

android:toDegrees="360.0"

/>

接下来是DemoAdapter,实现瀑布流高低错落效果的关键就在里边,需要在onBindViewHolder的时候去为item设定高度。

package com.adminstrator.guaguakaapplication;

import android.app.Activity;

import android.support.v7.widget.RecyclerView;

import android.support.v7.widget.StaggeredGridLayoutManager;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ImageView;

import android.widget.RelativeLayout;

import com.nostra13.universalimageloader.core.ImageLoader;

import java.util.ArrayList;

import java.util.Random;

/**

* Created by Administrator on 2019/7/31.

*/

public class DemoAdapter extends RecyclerView.Adapter {

private ArrayList dataList = new ArrayList<>();

public void replaceAll(ArrayList list) {

dataList.clear();

if (list != null && list.size() > 0) {

dataList.addAll(list);

}

notifyDataSetChanged();

}

/**

* 插入数据使用notifyItemInserted,如果要使用插入动画,必须使用notifyItemInserted

* 才会有效果。即便不需要使用插入动画,也建议使用notifyItemInserted方式添加数据,

* 不然容易出现闪动和间距错乱的问题

* */

public void addData(int position,ArrayList list) {

dataList.addAll(position,list);

notifyItemInserted(position);

}

//移除数据使用notifyItemRemoved

public void removeData(int position) {

dataList.remove(position);

notifyItemRemoved(position);

}

@Override

public DemoAdapter.BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

return new OneViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_water_fall, parent, false));

}

@Override

public void onBindViewHolder(DemoAdapter.BaseViewHolder holder, int position) {

holder.setData(dataList.get(position),position);

}

@Override

public int getItemCount() {

return dataList != null ? dataList.size() : 0;

}

public class BaseViewHolder extends RecyclerView.ViewHolder {

public BaseViewHolder(View itemView) {

super(itemView);

}

void setData(Object data,int position) {

}

}

private class OneViewHolder extends BaseViewHolder {

private ImageView ivImage;

public OneViewHolder(View view) {

super(view);

ivImage = (ImageView) view.findViewById(R.id.iv_item_water_fall);

}

@Override

void setData(Object data,int position) {

if (data != null) {

int id = (int) data;

ivImage.setImageResource(id);

//需要Item高度不同才能出现瀑布流的效果,此处简单粗暴地设置一下高度

if (position % 2 == 0) {

ivImage.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 250));

} else {

ivImage.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 350));

}

}

}

}

}

以上已经实现了瀑布流效果,为了美观一般情况下还需要在Item间设置间隔。也就上边Activity里用到的StaggeredDividerItemDecoration。

package com.adminstrator.guaguakaapplication.widget;

import android.content.Context;

import android.graphics.Rect;

import android.support.v7.widget.RecyclerView;

import android.support.v7.widget.StaggeredGridLayoutManager;

import android.util.TypedValue;

import android.view.View;

public class StaggeredDividerItemDecoration extends RecyclerView.ItemDecoration {

private Context context;

private float interval;

private int spanCount;

/**

* @param interval item的间距

* @param spanCount 列数

* */

public StaggeredDividerItemDecoration(Context context, float interval, int spanCount) {

this.context = context;

this.interval = interval;

this.spanCount = spanCount;

}

@Override

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();

// 获取item在span中的下标

int spanIndex = params.getSpanIndex();

int interval = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

this.interval, context.getResources().getDisplayMetrics());

// 中间间隔

/**

* 这个判断适用于瀑布流只有两列的情况,如果有多列,那么再增加spanIndex % spanCount == 的判断并做处理就好了

* 此处的left和right都为interval / 2的原因是为了让左边item和右边item同宽

* */

if (spanIndex % spanCount == 0) {

outRect.right = interval / 2;

} else {

outRect.left = interval / 2;

}

// 下方间隔

outRect.bottom = interval;

}

}

我效果图里的圆角图片使用了SWImageView,如果有需要,在Gradle中引入

implementation 'com.angel:SWImageView:1.0.0'

我使用的SmartRefreshLayout版本

implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-32'

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值