`

给RecyclerView(GridLayoutManager)添加Header和Footer

阅读更多

问题的提出:

我在使用RecyclerView的时候就想到了既然ListView可以通过addHeaderView来添加HeaderView,那么RecyclerView既然能够实现ListView的功能,那么肯定也可以添加HeaderView。

 

然后就开始在网上寻找相关的解决办法,最终找到了下面的解决途径:

 

1、首先,新建一个继承自RecyclerView的子类(WrapRecyclerView),并且在布局文件中将系统的android.support.v7.widget.RecyclerView替换成继承RecyclerView的子类(WrapRecyclerView)。

 

2、在WrapRecyclerView中添加addHeaderView和addFooterView的方法

 

    /**
     * 添加头布局
     *
     * @param view
     */
    public void addHeaderView(View view) {
        mHeaderViews.clear();
        mHeaderViews.add(view);
        if (mAdapter != null) {
            if (!(mAdapter instanceof RecyclerWrapAdapter)) {
                mAdapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, mAdapter);
                mAdapter.notifyDataSetChanged();
            }
        }
    }

 

 /**
     * 添加尾布局
     * @param view
     */
    public void addFooterView(View view){
        mFooterViews.clear();
        mFooterViews.add(view);
        if(mAdapter != null){
            if(!(mAdapter instanceof RecyclerWrapAdapter)){
                mAdapter = new RecyclerWrapAdapter(mHeaderViews,mFooterViews,mAdapter);
                mAdapter.notifyDataSetChanged();
            }
        }
    }

 3、在setAdapter方法中将原有的Adapter通过RecyclerWrapAdapter这个包装类重新包装一次,这里就使用到了设计模式中的装饰模式(在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。)

 

 @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);
        if (mHeaderViews.isEmpty() && mFooterViews.isEmpty()) {
            super.setAdapter(adapter);
        } else {
            adapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, adapter);
            super.setAdapter(adapter);
        }
        mAdapter = adapter;
    }

 

 

*所以我们要重点关注的就是RecyclerWrapAdatper的实现*

1、对Adapter的count进行了重新计算

 

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

 

 

2、onBindViewHolder、onCreateViewHolder、getItemViewType方法是重点

 

 其中,onBindViewHolder的作用主要用于适配渲染数据到View中。

 

 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return;
        }
        int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(holder, adjPosition);
                return;
            }
        }
    }

 

 

 

 onCreateViewHolder的作用主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。方法是把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。

 

 @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(mFooterViews.get(0));
        }
        return mAdapter.onCreateViewHolder(parent, viewType);
    }

  getItemViewType的作用就是确认是哪个View占用

 

@Override
    public int getItemViewType(int position) {
        mCurrentPosition = position;
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return RecyclerView.INVALID_TYPE;   // 说明是Header所占用的空间
        }
        int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }
        return RecyclerView.INVALID_TYPE - 1;   // 说明是Footer的所占用的空间
    }

 

 

 

 下面就是在MainActivity中的使用了 

mAdapter = new HomeAdapter(IntegralMallActivity.this, mDatas);
        layoutManager = new GridLayoutManager(this, 2);
        mRecycleView.setLayoutManager(layoutManager);
        mRecycleView.setLayoutManagerForWrapRecyclerView(layoutManager);

        textView = new TextView(this);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams
                .MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        textView.setLayoutParams(params);
        textView.setText("我是头部TextView");
        mRecycleView.addHeaderView(textView);
        mRecycleView.setAdapter(mAdapter);

        mRecycleView.addItemDecoration(new DividerGridItemDecoration(this));

  

  就有了下面的效果:



 
很明显,这不是我们想要的效果

所以就有了下面的改进:

在RecyclerWrapAdapter中的onAttachedToRecyclerView中进行相关的操作,让Header和Footer都能够占据一行

 

@Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof GridLayoutManager){   // 布局是GridLayoutManager所管理
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 如果是Header、Footer的对象则占据spanCount的位置,否则就只占用1个位置
                    return (isHeader(position) || isFooter(position)) ? gridLayoutManager.getSpanCount() : 1;
                }
            });
        }
    }

 

/**
     * 判断是否是Header的位置
     * 如果是Header的则返回true否则返回false
     * @param position
     * @return
     */
    public boolean isHeader(int position){
        return position >= 0 && position < mHeaderViews.size();
    }

    

 

/**
     * 判断是否是Footer的位置
     * 如果是Footer的位置则返回true否则返回false
     * @param position
     * @return
     */
    public boolean isFooter(int position){
        return position < getItemCount() && position >= getItemCount() - mFooterViews.size();
    }

  其中值得我们去解释的是下面这段代码:

 

 

return (isHeader(position) || isFooter(position)) ? gridLayoutManager.getSpanCount() : 1;

  大家可能会想不应该是Header、Footer就使用1行来显示吗?那为什么会是gridLayoutManger.getSpanCount()? 

 

   需要指出的是setSpanSizeLookup的意思是View需要用多少空间来显示,如果不是Header、Footer则只用一个空间,如果是Header、Footer则占据的是一行的空间。

 
这样就有了以下效果:

 

  

 

 

 

  就这样,成功添加HeaderView,如法炮制,添加FooterView也是一样可以的

 

  下面就将源码贴出:

 

  

 

package com.deltalab.urecommend.adapter.friend_pager;

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import com.deltalab.urecommend.adapter.base.WrapperAdapter;

import java.util.ArrayList;

/**
 * Created by asus on 2016/10/14.
 * 添加了headerView和footerView的布局适配器
 *
 * @author Administrator
 * @time 2016/10/14 16:54
 */
public class RecyclerWrapAdapter extends RecyclerView.Adapter implements WrapperAdapter {

    private RecyclerView.Adapter mAdapter;
    private ArrayList<View> mHeaderViews;
    private ArrayList<View> mFooterViews;
    private int mCurrentPosition;

    static final ArrayList<View> EMPTY_INFO_LIST = new ArrayList<View>();


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

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

    /**
     * 获取头布局的数量
     *
     * @return
     */
    public int getHeadersCount() {
        return mHeaderViews.size();
    }

    public int getFootersCount() {
        return mFooterViews.size();
    }

    /**
     * 把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例
     * 如果是Header、Footer则使用HeaderViewHolder封装
     * 如果是其他的就不变
     * @param parent
     * @param viewType
     * @return
     */
        @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(mFooterViews.get(0));
            }
            return mAdapter.onCreateViewHolder(parent, viewType);
        }

    /**
     * 用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return;
        }
        int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(holder, adjPosition);
                return;
            }
        }
    }

    /**
     * 将Header、Footer挂靠到RecyclerView
     * @param recyclerView
     */
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof GridLayoutManager){   // 布局是GridLayoutManager所管理
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 如果是Header、Footer的对象则占据spanCount的位置,否则就只占用1个位置
                    return (isHeader(position) || isFooter(position)) ? gridLayoutManager.getSpanCount() : 1;
                }
            });
        }
    }

        /**
         * 判断是否是Header的位置
         * 如果是Header的则返回true否则返回false
         * @param position
         * @return
         */
        public boolean isHeader(int position){
            return position >= 0 && position < mHeaderViews.size();
        }

        /**
         * 判断是否是Footer的位置
         * 如果是Footer的位置则返回true否则返回false
         * @param position
         * @return
         */
        public boolean isFooter(int position){
            return position < getItemCount() && position >= getItemCount() - mFooterViews.size();
        }

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

    @Override
    public int getItemViewType(int position) {
        mCurrentPosition = position;
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return RecyclerView.INVALID_TYPE;   // 说明是Header所占用的空间
        }
        int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }
        return RecyclerView.INVALID_TYPE - 1;   // 说明是Footer的所占用的空间
    }

    @Override
    public long getItemId(int position) {
        int numHeaders = getHeadersCount();
        if (mAdapter != null && position >= numHeaders) {
            int adjPosition = position - numHeaders;
            int adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemId(adjPosition);     // 不是Header和Footer则返回其itemId
            }
        }
        return -1;
    }

    @Override
    public RecyclerView.Adapter getWrapperAdapter() {
        return mAdapter;
    }

    private static class HeaderViewHolder extends RecyclerView.ViewHolder {
        public HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }
}

 

package com.deltalab.urecommend.adapter.friend_pager;

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.RelativeLayout;
import android.widget.TextView;

import com.deltalab.urecommend.BmobIMbase.ImageLoaderFactory;
import com.deltalab.urecommend.R;
import com.deltalab.urecommend.domin.IntegralMall;

import java.util.List;

import cn.bmob.v3.datatype.BmobFile;

/**
 * Created by asus on 2016/10/9.
 * 基本布局的适配器
 *
 * @author Administrator
 * @time 2016/10/9 17:30
 */
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> {

    private List<IntegralMall> mDatas;
    private LayoutInflater mInflater;

    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mOnItemClickListener;

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

    public HomeAdapter(Context context, List<IntegralMall> datas) {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder holder = new MyViewHolder(mInflater.inflate(R.layout.item_home, parent,
                false));
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
//            holder.tv.setText(mDatas.get(position));
        String name = mDatas.get(position).getName();
        String type = mDatas.get(position).getType();
        BmobFile pic = mDatas.get(position).getPic();
        if (pic != null) {
            String url = pic.getUrl();
            if (url != null) {  // 第三个参数是在url == "" 才会调用
                ImageLoaderFactory.getLoader().loadAvator(holder.mIvPicture, url, R.mipmap
                        .ic_launche);
            } else {
                holder.mIvPicture.setImageResource(R.mipmap.ic_launche);
            }
        } else {
            holder.mIvPicture.setImageResource(R.mipmap.ic_launche);
        }
        int num = mDatas.get(position).getNum();
        double size = num;
        String finalNum = num + "积分";
        if (num >= 10000) {
            size = num / 10000.0;
            finalNum = size + "万积分";
        }

        if (type.equals("竞猜")) {
            holder.mIvSign.setImageResource(R.mipmap.word_guess);
        } else if (type.equals("免费")) {
            holder.mIvSign.setImageResource(R.mipmap.word_free);
        } else if (type.equals("抽奖")) {
            holder.mIvSign.setImageResource(R.mipmap.word_luck_draw);
        }

        holder.mTvIntegral.setText(finalNum);
        holder.mTvName.setText(name);

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickListener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickListener.onItemLongClick(holder.itemView, pos);
                    // 返回true表示自己处理了,不需要交到onClick中去了
                    // 返回false表示自己没有处理,交到onClick中去
                    return true;
                }
            });
        }

    }

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

    class MyViewHolder extends RecyclerView.ViewHolder {

        RelativeLayout tv;
        ImageView mIvPicture;
        TextView mTvName;
        TextView mTvIntegral;
        ImageView mIvSign;

        public MyViewHolder(View view) {
            super(view);
            tv = (RelativeLayout) view.findViewById(R.id.rl_num);
            mIvPicture = (ImageView) view.findViewById(R.id.iv_picture);
            mTvName = (TextView) view.findViewById(R.id.tv_name);
            mTvIntegral = (TextView) view.findViewById(R.id.tv_integral);
            mIvSign = (ImageView) view.findViewById(R.id.iv_sign);
        }
    }
}

 

package com.deltalab.urecommend.view;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.bartoszlipinski.recyclerviewheader.RecyclerViewHeader;
import com.deltalab.urecommend.R;
import com.deltalab.urecommend.adapter.friend_pager.RecyclerWrapAdapter;

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by asus on 2016/10/13.
 * 能够任意添加Header和Footer的自定义的RecyclerView
 *
 * @author Administrator
 * @time 2016/10/13 21:16
 */
public class WrapRecyclerView extends RecyclerView {

    private static final int STATE_PULL_REFRESH = 0;    // 下拉刷新
    private static final int STATE_RELEASE_REFRESH = 1; // 松开刷新
    private static final int STATE_REFRESHING = 2;      // 正在刷新

    private int mCurrentState = STATE_PULL_REFRESH;     // 当前状态

    private ArrayList<View> mHeaderViews = new ArrayList<>();
    private ArrayList<View> mFooterViews = new ArrayList<>();

    private Adapter mAdapter;
    private RecyclerViewHeader header;
    private int headerHeight;
    private TextView tvTitle;
    private TextView tvTime;
    private ImageView ivArrow;
    private ProgressBar pbProgress;

    private int startY = -1;
    private int endY;
    private RotateAnimation animUp;
    private RotateAnimation animDown;

    WrapRecyclerView.OnRefreshListener mListener;
    private GridLayoutManager layoutManager;


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

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

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


    /**
     * 添加头布局
     * 只能添加一个头布局
     * @param view
     */
    public void addHeaderView(View view) {
        mHeaderViews.clear();
        mHeaderViews.add(view);
        if (mAdapter != null) {
            if (!(mAdapter instanceof RecyclerWrapAdapter)) {
                mAdapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, mAdapter);
                mAdapter.notifyDataSetChanged();
            }
        }
    }

    /**
     * 添加尾布局
     * 只能添加一个尾布局
     * @param view
     */
    public void addFooterView(View view){
        mFooterViews.clear();
        mFooterViews.add(view);
        if(mAdapter != null){
            if(!(mAdapter instanceof RecyclerWrapAdapter)){
                mAdapter = new RecyclerWrapAdapter(mHeaderViews,mFooterViews,mAdapter);
                mAdapter.notifyDataSetChanged();
            }
        }
    }

    /**
     * 初始化头布局
     */
    private void initHeaderView() {
        header = RecyclerViewHeader.fromXml(getContext(), R.layout.refresh_header);

        tvTitle = (TextView) header.findViewById(R.id.tv_title);
        tvTime = (TextView) header.findViewById(R.id.tv_time);
        ivArrow = (ImageView) header.findViewById(R.id.iv_arr);
        pbProgress = (ProgressBar) header.findViewById(R.id.pb_progress);

        header.measure(0, 0);
        headerHeight = header.getMeasuredHeight();

        // 隐藏头布局
        header.setPadding(0, -headerHeight, 0, 0);    //  负的值就能够让控件向上移动了
        initArrowAnim();        // 初始化箭头动画
        // 更新最后刷新的时间
        tvTime.setText("最后刷新时间" + getCurrentTime());
    }

    /**
     * 获取头布局用户
     *
     * @return
     */
    public RecyclerViewHeader getHeaderview() {
        return header;
    }


    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);
        if (mHeaderViews.isEmpty() && mFooterViews.isEmpty()) {
            super.setAdapter(adapter);
        } else {
            adapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, adapter);
            super.setAdapter(adapter);
        }
        mAdapter = adapter;
    }

    @Override
    public void onScrollStateChanged(int state) {
        super.onScrollStateChanged(state);

    }

    /**
     * 监听用户的触摸操作
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (startY == -1) {   // 确保startY有效
                    startY = (int) event.getRawY();
                }

                if (mCurrentState == STATE_REFRESHING) {  // 正在刷新时,不做处理
                    break;
                }

                endY = (int) event.getRawY();

                int dy = endY - startY;   // 移动偏移量
                if (dy > 0 && layoutManager.findFirstVisibleItemPosition() == 0) {   // 只有下拉并且当前是第一个item才允许下拉
                    int padding = dy - headerHeight;    //  计算padding
                    header.setPadding(0, padding, 0, 0);   // 设置当前的padding

                    if (padding > 0 && mCurrentState != STATE_RELEASE_REFRESH) {  // 状态改为松开刷新
                        mCurrentState = STATE_RELEASE_REFRESH;
                        refreshState();
                    } else if (padding < 0 && mCurrentState != STATE_PULL_REFRESH) {    // 改为下拉刷新状态
                        mCurrentState = STATE_PULL_REFRESH;
                        refreshState();
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                startY = -1;    // 重置

                if (mCurrentState == STATE_PULL_REFRESH) {    // 如果是松开刷新状态就变成正在刷新状态
                    mCurrentState = STATE_REFRESHING;   // 正在刷新
                    // 将状态的padding变成0
                    header.setPadding(0, 0, 0, 0);     // 显示
                    refreshState();
                } else if (mCurrentState == STATE_PULL_REFRESH) {
                    // 将隐藏标题
                    header.setPadding(0, -headerHeight, 0, 0);
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    public void setOnRefreshListener(WrapRecyclerView.OnRefreshListener listener) {
        mListener = listener;
    }

    /**
     * 设置布局的LayoutManager
     *
     * @param layoutManager
     */
    public void setLayoutManagerForWrapRecyclerView(GridLayoutManager layoutManager) {
        this.layoutManager = layoutManager;
    }

    /**
     * 刷新下拉控件的布局
     */
    private void refreshState() {
        switch (mCurrentState) {
            case STATE_PULL_REFRESH:
                tvTitle.setText("下拉刷新");
                ivArrow.setVisibility(View.VISIBLE);
                pbProgress.setVisibility(View.VISIBLE);

                ivArrow.startAnimation(animDown);       // 箭头向下
                break;
            case STATE_RELEASE_REFRESH:
                tvTitle.setText("松开刷新");
                ivArrow.setVisibility(View.VISIBLE);
                pbProgress.setVisibility(View.INVISIBLE);

                ivArrow.startAnimation(animUp);
                break;
            case STATE_REFRESHING:
                tvTitle.setText("正在刷新");
                // 必须要先清除动画以后才能去把那个箭头给隐藏
                ivArrow.clearAnimation();
                ivArrow.setVisibility(View.INVISIBLE);
                pbProgress.setVisibility(View.VISIBLE);

                if (mListener != null) {
                    mListener.onRefresh();
                }
                break;
        }
    }

    /**
     * 初始化箭头方向
     */
    private void initArrowAnim() {
        // 箭头向上的动画
        animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation
                .RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(200);
        animUp.setFillAfter(true);

        // 箭头向下的动画
        animDown = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation
                .RELATIVE_TO_SELF, 0.5f);
        animDown.setDuration(200);
        animDown.setFillAfter(true);

    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public String getCurrentTime() {
        // 设置时间的输出格式
        // 需要注意的是:HH表示的是24小时制,hh表示的是12小时制
        // 需要注意的是:月的MM表示的是1月份从1开始,mm表示的1月份从0开始
        java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        return format.format(new Date());
    }

    public interface OnRefreshListener {

        public void onRefresh();

        public void onLoadMore();   // 加载更多数据
    }
}

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <com.deltalab.urecommend.view.WrapRecyclerView
        android:id="@+id/id_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


</RelativeLayout>

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 78.1 KB
  • 大小: 85.8 KB
1
0
分享到:
评论

相关推荐

    RecyclerView添加header ,添加footer同理

    本教程将详细讲解如何在RecyclerView中添加Header和Footer,这对于构建复杂布局,如添加广告条或者底部操作按钮是非常实用的。 首先,我们需要理解RecyclerView的基本架构。RecyclerView由Adapter和LayoutManager两...

    使用RecyclerView实现带Header和Footer的GridView

    - 创建对应的ViewHolder类,例如HeaderViewHolder、FooterViewHolder和ItemViewHolder,分别处理Header、Footer和列表项的视图绑定。 3. **添加Header和Footer** - 在Adapter的`onCreateViewHolder`方法中,根据`...

    Android-RecyclerView封装加载更多添加Header和Footer

    以上就是对RecyclerView进行封装,实现加载更多和添加Header、Footer的主要步骤。在LoadMoreRecyclerView-master项目中,你将会看到具体实现这些功能的代码,包括Adapter的实现、滚动监听、UI反馈以及错误处理。通过...

    使用RecyclerView添加Header和Footer的方法

    - `getItemViewType(int position)`:根据位置返回viewType,这里需要添加逻辑来区分Header、Footer和数据项。 - `onCreateViewHolder(ViewGroup parent, int viewType)`:根据viewType创建ViewHolder实例,如果...

    RecyclerViewHeaderAndFooter

    本项目"RecyclerViewHeaderAndFooter"着重讲解如何在RecyclerView中添加头部(Header)和尾部(Footer)。 首先,我们来理解RecyclerView的基本结构。RecyclerView由Adapter、LayoutManager和ItemDecoration三大...

    recyclerView复用添加头尾及上下刷新源码

    本资源提供了一个实现RecyclerView的全面功能的源码示例,包括添加Header和Footer视图,以及集成下拉刷新和上拉加载更多的功能。 一、RecyclerView基础 RecyclerView的核心在于其适配器(RecyclerView.Adapter)和...

    Android RecyclerView 使用全解

    本篇文章将深入探讨RecyclerView的使用,包括如何添加Header和Footer,以及如何处理子项点击事件等核心知识点。 首先,RecyclerView的核心组件包括Adapter和LayoutManager。Adapter是数据和视图之间的桥梁,负责...

    recylerview 添加头部 尾部

    标题"recylerview 添加头部 尾部"和描述"android RecyclerView 支持添加header头部、footer尾部"正是针对这个功能的讨论。 实现RecyclerView添加头部和尾部主要有以下步骤: 1. **创建Header和Footer视图** 首先...

    SectionedRecyclerView可以添加页眉和页脚RecyclerView.rar

    然而,原生的RecyclerView仅提供基本的列表展示功能,无法直接实现页眉(Header)和页脚(Footer)的添加。为了解决这个问题,开发者们通常会采用自定义适配器或者第三方库,如`SectionedRecyclerView`。本篇文章将...

    recyclerView实现树状结构

    标题提到的"recyclerView实现树状结构",就是将`RecyclerView`与树形数据结构相结合,实现一种可以展开/折叠节点,带有header(头部)和footer(底部)的功能。下面将详细介绍如何实现这样的功能。 首先,理解`...

    recyclerView 官方示例

    RecyclerView支持添加Header和Footer,这在实现如下拉刷新、上拉加载更多等功能时非常有用。可以通过在Adapter的构造函数中传递Header和Footer的视图,然后在`getItemViewType()`方法中进行区分。 9. **状态保存和...

    可添加头部和尾部的 RecyclerView

    本篇将详细讲解如何在RecyclerView中添加头布局(header)和尾布局(footer)。 首先,理解RecyclerView的基本结构。RecyclerView由Adapter、LayoutManager和ViewHolder三部分组成。Adapter是数据源,负责处理数据...

    RecyclerView.zip,各种布局的实现

    除了基本布局外,RecyclerView还支持Header和Footer的添加,通过在Adapter的数据集中添加特殊标记,或者使用SectionAdapter等第三方库来实现。此外,还可以实现动画效果,如默认的滑动插入和删除动画,或者自定义更...

    RecyclerView的使用demo

    13. **Header和Footer** 要在RecyclerView中添加头部和尾部,可以利用`addHeaderView()`和`addFooterView()`方法,但需要注意它们不直接支持,需要在Adapter中进行处理。 14. **嵌套滚动** RecyclerView支持嵌套...

    Android-只用recyclerview实现复杂首页布局布局随增减数据动态显示

    4. **Header和Footer**:有时我们需要在列表的顶部或底部添加固定项,可以使用预加载方法在RecyclerView的开始或结束位置添加Header和Footer。 5. **自定义动画**:通过设置ItemAnimator,可以为RecyclerView添加...

    Android-RecyclerView二次封装Adapter支持添加头布局尾部局空布局

    本项目特别提到支持GridLayoutManager和LinearLayoutManager,这意味着封装的Adapter可以处理这两种布局模式下的头尾布局和空布局。 4. **二次封装的Adapter**: - 二次封装的核心在于对原生RecyclerView.Adapter...

    Android-RecyclerView基础写法简单实现

    你可以根据需求添加Header、Footer,或者使用GridLayoutManager、StaggeredGridLayoutManager等其他布局管理器。另外,还可以实现Item点击事件、动画效果以及下拉刷新和上拉加载更多功能。 对于更复杂的需求,例如...

    recyclerview以及各种实用的小demo

    在项目中,还展示了如何添加Header和Footer到RecyclerView。这通常用于显示额外的信息或操作,比如加载更多。可以使用`addHeaderView()`和`addFooterView()`方法,但需要注意它们不直接属于RecyclerView的API,而是...

    RecyclerView加载不同View视图布局

    本教程将深入探讨如何在RecyclerView中实现加载不同View视图布局,类似于ListView中的Header、Footer和不同类型item的效果。 首先,理解RecyclerView的核心概念:Adapter和ViewHolder。Adapter是连接数据源和视图的...

    Recyclerview-Sample.zip

    RecyclerView还可以添加Header和Footer,以及ItemDecoration来实现分割线。通过addItemDecoration()方法添加自定义的ItemDecoration,可以实现定制的分隔线样式。 7. **点击事件处理** 在ViewHolder中,我们可以...

Global site tag (gtag.js) - Google Analytics