自定义ListView下拉刷新,上拉加载

/**
 * Created by on 2016/12/2.
 * 自定义listview:
 *      一、下拉刷新:
 *          1. 添加头部布局,并设置位置隐藏
 *          2. 监听滑动事件,判断当前显示在最顶端的item是否是第一个item
 *          3. 监听onTouch事件,根据下拉的距离来判断下来状态的变化
 *      二、加载更多:
 *          1. 添加底部布局,并隐藏
 *          2. 监听滑动事件,判断最后显示的item是不是最后一个item来决定是否加载更多
 *      这里通过传递参数的方式来传递handler来延迟刷新
 *      (推荐)通过接口回调的方式可以实现加载数据
 */
public class ReFlashListView extends ListView implements AbsListView.OnScrollListener{

    private Handler handler;//这个handler用来做一个延时处理刷新

    private View header;//头布局
    private int headerHeight;//header的高度
    int firstVisibleItem;//listview中可见的第一个item的位置
    int visibleItemCount;//可见的item的数量
    int totalItemCounts;//已经显示出来的总数量
    int scrollState;//滑动状态

    int state;//滑动的状态
    final int NONE = 0; //正常状态
    final int PULL = 1; //提示下拉状态
    final int RELSE = 2; //提示释放状态
    final int RELSING = 3; //正在刷新状态

    private boolean isTop = false; //判断按下的时候当前显示在最上面一个item是listview的第一个item
    private int stateY;//按下的时候Y轴的位置

    private ImageView iv_header;
    private TextView tv_header;
    private ProgressBar pg_header;

    private View footer;//底部布局
    private boolean isLoading = false;


    public ReFlashListView(Context context) {
        super(context);
        initView(context);
    }

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

    public ReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    /**
     * 实例化handler
     */
    public void setListViewHandler(Handler handler){
        this.handler = handler;
    }

    /**
     * 给ListView添加头布局
     * @param context
     */
    private void initView(Context context){
        header = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_header, null);
        iv_header = (ImageView) header.findViewById(R.id.iv_header);
        tv_header = (TextView) header.findViewById(R.id.tv_header);
        pg_header = (ProgressBar) header.findViewById(R.id.pg_header);
        measureHeight(header);
        headerHeight = header.getMeasuredHeight();
        initHeaderTopPadding();
        this.addHeaderView(header);
        loadFooter(context);
        this.setOnScrollListener(this);
    }

    /**
     * 加载底部布局
     */
    private void loadFooter(Context context){
        footer = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_footer, null);
        footer.findViewById(R.id.ll_load_more).setVisibility(View.GONE);
        this.addFooterView(footer);
    }

    /**
     * 初始化header的位置
     */
    public void initHeaderTopPadding(){
        setTopPadding(-headerHeight);
    }

    /**
     * 设置header的高度:隐藏header
     */
    private void setTopPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());
    }

    /**
     * 高度父布局当前view的宽高
     *      如果没有这一步,header.getMeasuredHeight() == 0
     */
    private void measureHeight(View view){
        ViewGroup.LayoutParams p = view.getLayoutParams();
        if(p == null){
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
        int height;
        int temHeight = p.height;
        if(temHeight > 0){
            height = MeasureSpec.makeMeasureSpec(temHeight , MeasureSpec.EXACTLY);
        }else {
            height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(width, height);
    }

    /**
     * @param view
     * @param scrollState:即滑动的状态。分为三种 0,1,2
                            0 表示停止滑动的状态 SCROLL_STATE_IDLE
                            1表示正在滚动,用户手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL
                            2表示正在滑动。用户手指已经离开屏幕 SCROLL_STATE_FLING
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState = scrollState;
        if((firstVisibleItem + visibleItemCount) == totalItemCounts && scrollState == SCROLL_STATE_IDLE){
            if(!isLoading){
                //显示出footer,并在这里加载数据
                footer.findViewById(R.id.ll_load_more).setVisibility(View.VISIBLE);
                /**
                 * TODO:加载数据
                 */
            }
        }
    }

    /**
     * @param view
     * @param firstVisibleItem : 第一个可见的item的位置
     * @param visibleItemCount : 可见的item的数量
     * @param totalItemCount : 总的数量
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.firstVisibleItem = firstVisibleItem;
        this.visibleItemCount = visibleItemCount;
        this.totalItemCounts = totalItemCount;
    }

    /**
     * 监听滑动状态的改变
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                if(firstVisibleItem == 0){//当前显示在最上面一个item是listview的第一个item
                    state = NONE;//设置状态,表示继续下拉可以触发刷新
                    isTop = true;
                    stateY = (int) ev.getY();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                reFlashing(ev);
                break;
            case MotionEvent.ACTION_UP:
                if(state == RELSE){
                    state = RELSING;
                    reFlasTip();
                    //加载数据               
                    /**
                     * TODO:刷新数据
                     */
}else if(state == PULL){ state = NONE; isTop = false; reFlasTip(); } break; } return super.onTouchEvent(ev); } /** * 判断移动过程中的操作 */ private void reFlashing(MotionEvent ev){ if(!isTop){ return; } int evY = (int) ev.getY(); int spaceY = evY - stateY; int topPadding = spaceY - headerHeight; if(topPadding >= headerHeight * 3){ topPadding = headerHeight * 2; } switch (state){ case NONE: if(spaceY >= 0){ //表示往下拉动 state = PULL; reFlasTip(); } break; case PULL: setTopPadding(topPadding); if(spaceY >= headerHeight+20 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ //表示往下拉动,并且正在滚动 state = RELSE; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; case RELSE: setTopPadding(topPadding); if(spaceY < headerHeight){ state = PULL; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; } } /** * 根据下拉状态的变化改变header的提示 */ private void reFlasTip(){ switch (state){ case NONE: setTopPadding(-headerHeight); break; case PULL: tv_header.setText("下拉可以刷新"); break; case RELSE: tv_header.setText("松开可以刷新"); break; case RELSING: setTopPadding(headerHeight); tv_header.setText("正在刷新"); break; } }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值