主要是Adapter中的写法,继承RecyclerView.Adapter复写四个方法:
//创建viewholder,主要是做一些findview的操作
onCreateViewHolder
//绑定数据,把item传递给holder
onBindViewHolder
//多类型的关键,返回的是item的类型
getItemViewType
//返回列表中item的个数
getItemCount
技巧:把itemViewType跟对象绑定,并且用布局文件id来代替。要注意的是有一个足布局FooterView:
@Override
public int getItemViewType(int position)
{
//当position处于底部时,足布局显示
if (position == mData.size())
{
return TYPE_FOOTER;
}
return mData.get(position).getItemType(mTypeFactory);
}
照顾到有一个足布局:
@Override
public int getItemCount()
{
//当mData为空集合时,不展示footerView
return mData == null || mData.isEmpty() ? 0 : mData.size() + 1;
}
上面有提到将布局文件id传递给viewType:
@NonNull
@Override
public BaseMultiHoder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
//足布局单独处理
if (viewType == TYPE_FOOTER)
{
return new FooterHoder(itemView);
}
//mTypeFactory不多讲了,可以参考代码
return mTypeFactory.createViewHolder(itemView, viewType);
}
把每一个item的数据传递给holder,其中需要对足布局进行单独处理:
@Override
public void onBindViewHolder(@NonNull BaseMultiHoder holder, int position)
{
mHolder = holder;
if (position < mData.size())
{
holder.bind(mData.get(position));
} else
{
switch (currentState)
{
case LOADING:
((FooterHoder) holder).showLoad();
break;
case LOAD_COMPLETE:
((FooterHoder) holder).showComplete();
break;
case LOAD_FAILED:
((FooterHoder) holder).showFailed();
break;
default:
break;
}
}
}
亮点利用Rxjava实现上拉加载,PublishProcessor来做订阅和发布。
private PublishProcessor paginator = PublishProcessor.create();
private void subscribeForData()
{
mSwipeRefreshLayout.setRefreshing(true);
Disposable disposable = paginator
//如果消费者无法处理数据,则 onBackpressureDrop 就把该数据丢弃了。
//Read more: http://blog.chengyunfeng.com/?p=981#ixzz5Jd08zeDx
.onBackpressureDrop()
//顺序执行
.concatMap(new Function>>()
{
@Override
public Publisher> apply(Integer page) throws Exception
{
loading = true;
return dataFromNetword(page);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer>()
{
@Override
public void accept(final List multiItems) throws Exception
{
//page=1时,需要清空数据源
if (pageNumber == 1)
{
mMultiAdapter.clear();
refreshTvAnim();
}
loading = false;
mMultiAdapter.addItems(multiItems);
if (mSwipeRefreshLayout.isRefreshing())
{
mSwipeRefreshLayout.setRefreshing(false);
}
}
}, new Consumer()
{
@Override
public void accept(Throwable throwable) throws Exception
{
//注意当发生onError时,onNext就不在起作用了。这个时候需要重新subscribe
Toast.makeText(App.getAppContext(), throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
});
compositeDisposable.add(disposable);
paginator.onNext(pageNumber);
}
订阅好了之后,每次触发上拉的时候执行paginator.onNext(pageNumber);。上拉触发条件:recyclerview滑动到底部。
private void setUpLoadMoreListener()
{
mRecyvlerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
super.onScrolled(recyclerView, dx, dy);
mTotalItemCount = mManager.getItemCount();
mLastVisibleItemPosition = mManager.findLastVisibleItemPosition();
//当不在加载,且最后一个可见position+预见大于或等于总item时
if (!loading && mTotalItemCount <= (mLastVisibleItemPosition + PRE_VISIBLE))
{
//当足布局状态是loading时
if (mMultiAdapter.getCurrentState() == MultiAdapter.LOADING)
{
pageNumber++;
//加载数据,PublishProcessor发送数据。
//我们可以根据这个特性来实现RxBus。下篇博客再做记录。
paginator.onNext(pageNumber);
loading = true;
}
}
}
});
}
可以首先来看下我的布局文件xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyvler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android.support.v4.widget.SwipeRefreshLayout>
//这个就是那个刷新完成的控件,其实就是一个textview
<TextView
android:id="@+id/refresh_com_tv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="刷新完成"
android:textColor="@color/white"
android:textSize="14sp" />
FrameLayout>
动画实现方式我采用的是通过改变textview的高度来实现。有一个展开和一个收缩动画,中间有一个1s的间隔时间。
/**
* 刷新完成动画
*/
private void refreshTvAnim()
{
final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mRefreshComTv.getLayoutParams();
//展开动画
ValueAnimator animator = ValueAnimator.ofInt(0, 105).setDuration(500);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
int animatedValue = (int) animation.getAnimatedValue();
layoutParams.height = animatedValue;
mRefreshComTv.setLayoutParams(layoutParams);
}
});
animator.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationEnd(Animator animation)
{
super.onAnimationEnd(animation);
Flowable.just(1).delay(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer()
{
@Override
public void accept(Integer integer) throws Exception
{
//收缩动画
ValueAnimator shrinkAnim = ValueAnimator.ofInt(105, 0).setDuration(500);
shrinkAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
int animatedValue = (int) animation.getAnimatedValue();
layoutParams.height = animatedValue;
mRefreshComTv.setLayoutParams(layoutParams);
}
});
shrinkAnim.start();
}
});
}
});
animator.start();
}
https://medium.com/@ruut_j/a-recyclerview-with-multiple-item-types-bce7fbd1d30e
Github Demo如果对你有帮助,请star吧。
上一篇博客Android Studio一些使用技巧