您的位置:首页 > 移动开发 > Android开发

RecyclerView添加头脚布局,使用SwipeRefreshLayout的实现

2016-05-13 12:25 671 查看
上篇文章记录了将viewpager抽取出来,那么这篇文章我们继续来实现,将viewpager做为头布局添加给RecyclerView。这使用到了一种设计模式 - 包装类设计模式,大家可以先了解下这个模式更有利于理解,我也会把本篇实现的思路给出个思维导图的。

看下效果图吧:



首先来个bean对象,等下封装数据使用:

public class Item {

private String maintitle;
private String subtitle;

public Item(String maintitle, String subtitle){
this.maintitle = maintitle;
this.subtitle = subtitle;
}

public String getMaintitle() {
return maintitle;
}

public String getSubtitle() {
return subtitle;
}
}


然后我们创建一个类WrapRecyclerView继承自RecyclerView:

// 将recycle进行封装
public class WrapRecyclerView extends RecyclerView {

private ArrayList<View> mHeadViewList = new ArrayList<View>();
private ArrayList<View> mFootViewList = new ArrayList<View>();
private Adapter mAdapter;

public WrapRecyclerView(Context context) {
super(context);
}

public WrapRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public WrapRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public void addHeaderView(View view){
mHeadViewList.clear();
mHeadViewList.add(view);
if (mAdapter != null){
if (!(mAdapter instanceof RecylerWrapAdapter)){
mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
}
}
}

public void addFootView(View view){
mFootViewList.clear();
mFootViewList.add(view);
if (mAdapter != null){
if (!(mAdapter instanceof RecylerWrapAdapter)){
mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
}
}
}

@Override
public void setAdapter(Adapter adapter) {
if (mHeadViewList.isEmpty() && mFootViewList.isEmpty()){
super.setAdapter(adapter);
}else{
adapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,adapter);
super.setAdapter(adapter);
}
mAdapter = adapter;
}
}


//在布局使用,使用系统的SwipeRefreshLayout包裹下
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.wb.head.widget.WrapRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</android.support.v4.widget.SwipeRefreshLayout>
//然后在MainActivity的onCreate中获取实例,进行初始化。还是我们上篇的那个MainActivity
recycler = (WrapRecyclerView) findViewById(R.id.recycler);
refresh = (SwipeRefreshLayout) findViewById(R.id.srl_refresh);
initRecycler();
initRefresh();


private void initRecycler(){
ll_headparent.removeView(rl_head);
recycler.addHeaderView(rl_head);

TextView textView = new TextView(this);
textView.setText("我是脚布局");
textView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,50);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(params);
recycler.addFootView(textView);

mRecylerAdpater = new RecylerAdpater(loadData(0,6));
recycler.setAdapter(mRecylerAdpater);
recycler.setLayoutManager(new LinearLayoutManager(this));
recycler.setHasFixedSize(true);
onRecyclerClick();
}
// 如果连续快速点击,条目的动画会有一个bug,所以使用了一个标记来禁止点击连续点击
boolean isClick = false;
private void onRecyclerClick(){
mRecylerAdpater.setOnItemClickLitener(new RecylerAdpater.OnItemClickLitener() {
@Override
public void onItemClick(View view, int position) {
if (!isClick){
isClick = true;
Toast.makeText(MainActivity.this, "点了我position" + position, Toast.LENGTH_SHORT).show();
ViewCompat.animate(view).setDuration(200).scaleX(0.9f).scaleY(0.9f).setInterpolator(new CycleInterpolator())
.setListener(new ViewPropertyAnimatorListener() {

@Override
public void onAnimationStart(View view) {}

@Override
public void onAnimationEnd(View view) {
isClick = false;
}

@Override
public void onAnimationCancel(View view) {}
}).withLayer().start();
}
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this, "长按了我position" + position, Toast.LENGTH_SHORT).show();
}
});
}

private class CycleInterpolator implements android.view.animation.Interpolator {

private final float mCycles = 0.5f;

@Override
public float getInterpolation(final float input) {
return (float) Math.sin(2.0f * mCycles * Math.PI * input);
}
}

ArrayList<Item> items = new ArrayList<Item>();
private ArrayList loadData(int start,int end){
items.clear();
for (int i = start; i < end; i++) {
items.add(new Item("Item title :" + i,"This is the Item number :" + i));
}
return items;
}
// 模仿访问网络,进行刷新数据
private void initRefresh(){
refresh.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);
refresh.setProgressBackgroundColorSchemeColor(getResources().getColor(android.R.color.white));
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
items.clear();
mRecylerAdpater = new RecylerAdpater(loadData(10, 16));
recycler.setAdapter(mRecylerAdpater);
mRecylerAdpater.notifyDataSetChanged();
onRecyclerClick();
refresh.setRefreshing(false);
}
}, 4000);
}
});
}


然后我们在创建个类RecylerWrapAdapter继承自RecyclerView.Adapter对adapter进行包装:

public class RecylerWrapAdapter extends RecyclerView.Adapter{

private RecyclerView.Adapter mAdapter;
private ArrayList<View> mHeaderViews;
private ArrayList<View> mFootViews;
private final ArrayList<View> EMPTY_INFO_LIST = new ArrayList<View>();
private int mCurrentPosition;

public RecylerWrapAdapter(ArrayList<View> mHeaderViews,ArrayList<View> mFootViews,RecyclerView.Adapter mAdapter){
this.mAdapter = mAdapter;
if (mHeaderViews == null){
this.mHeaderViews = EMPTY_INFO_LIST;
}else{
this.mHeaderViews = mHeaderViews;
}

if (mFootViews == null){
this.mFootViews = EMPTY_INFO_LIST;
}else{
this.mFootViews = mFootViews;
}
}

public int getHeaderCount(){
return mHeaderViews.size();
}

public int getFootCount(){
return mFootViews.size();
}

/**
* 返回该position对应的item的id
* @param position
* @return
*/
@Override
public long getItemId(int position) {
int heads = getHeaderCount();
if (mAdapter != null && position >= heads){
int adjposition = position - heads; //减去头布局的当前位置
int adapterCount = mAdapter.getItemCount(); //总共有多少条目
if (adjposition < adapterCount){ // 当前位置如果是在条目中的
return mAdapter.getItemId(adjposition);
}
}
return -1;
}

@Override
public int getItemCount() {
if (mAdapter != null){
return getHeaderCount() + getFootCount() + mAdapter.getItemCount();
}else{
return getHeaderCount() +getFootCount();
}
}

/**
* 判断应该返回的是头布局还是正常子布局还是脚布局 在onCreateViewHolder中使用
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
mCurrentPosition = position;
int heads = getHeaderCount();
// 也就是说recycle的第一个条目位置为头布局
if (position < heads){
// 返回类型为头布局
return RecyclerView.INVALID_TYPE;
}
int adjposition = position - heads; //减去头布局后当前布局的位置
int adapterCount = 0;
if (mAdapter != null){
adapterCount = mAdapter.getItemCount();
if (adjposition < adapterCount){
//返回类型为正常布局
return mAdapter.getItemViewType(adjposition);
}
}
// 返回类型为脚布局
return RecyclerView.INVALID_TYPE - 1;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == RecyclerView.INVALID_TYPE){
// 返回头布局
return new HeaderViewHolder(mHeaderViews.get(0));
}else if (viewType == RecyclerView.INVALID_TYPE - 1){
// 返回脚布局
return new HeaderViewHolder(mFootViews.get(0));
}
// 返回正常布局
return mAdapter.onCreateViewHolder(parent,viewType);
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int heads = getHeaderCount();
if (position < heads) return;
int adjPosition = position - heads;
int adapterCount = 0;
if (mAdapter != null){
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount){
// 绑定正常条目数据
mAdapter.onBindViewHolder(holder,adjPosition);
return;
}
}
}

private class HeaderViewHolder extends RecyclerView.ViewHolder{

public HeaderViewHolder(View itemView) {
super(itemView);
}
}
}


现在包装类写完了,但我们的RecyclerView还没有Adapter的,那我们就创建吧,和使用普通RecyclerView的Adapter一样:

public class RecylerAdpater extends RecyclerView.Adapter<RecylerAdpater.MyViewHolder> {

private List items;

public RecylerAdpater(List list){
super();
items = list;
}

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

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new MyViewHolder(v);
}

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Item item = (Item)items.get(position);
holder.mTitle.setText(item.getMaintitle());
holder.mSubtitle.setText(item.getSubtitle());

if (mOnItemClickLitener != null){
// 设置点击事件  通过系统view类的回调设置我们的回调
holder.ll_item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.ll_item,pos);
}
});

// 设置长按事件 通过系统view类的回调设置我们的回调
holder.ll_item.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.ll_item,pos);
return true;
}
});
}
}

class MyViewHolder extends RecyclerView.ViewHolder{

TextView mTitle;
TextView mSubtitle;
LinearLayout ll_item;

public MyViewHolder(View itemView) {
super(itemView);
mTitle = (TextView) itemView.findViewById(R.id.maintitle);
mSubtitle = (TextView) itemView.findViewById(R.id.subtitle);
ll_item = (LinearLayout) itemView.findViewById(R.id.ll_item);
}
}

//回调接口用于点击事件
public interface OnItemClickLitener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}

private OnItemClickLitener mOnItemClickLitener;

public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener){
this.mOnItemClickLitener = mOnItemClickLitener;
}
}


OK,现在大功告成,我们已经在MainActivity的initRecycler()方法中使用了,运行就可以看到效果了。

对包装类设计模式不熟悉的朋友可能会有些疑问,下面给大家贴出我做的思维导图:



最好的方法还是自己写出来,断点下就清楚这个设计模式和执行流程了。如有哪里不足,欢迎指教。

Reference:

http://www.it165.net/pro/html/201507/48065.html

http://blog.csdn.net/lmj623565791/article/details/45059587

https://github.com/DevLight-Mobile-Agency/NavigationTabBar

项目代码已经发布到github,地址:https://github.com/viewpager/HeadApplication
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息