Android 常用的列表下拉刷新下拉加载的组件

  <com.scwang.smart.refresh.layout.SmartRefreshLayout
                android:id="@+id/mail_sm_refresh"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <com.scwang.smart.refresh.header.ClassicsHeader
                    android:id="@+id/refresh_header"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/lottery_gridview"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />

                <com.scwang.smart.refresh.footer.ClassicsFooter
                    android:id="@+id/refresh_footer"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

            </com.scwang.smart.refresh.layout.SmartRefreshLayout>

上面是第一种(常用的下拉刷新和下拉加载)

下面是第二种

 1. 这种是下拉会有阻力回弹效果,上拉我屏蔽了,

<com.module.lottery.view.PullRecyclerViewGroup
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/lottery_gridview"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fadingEdge="none"
                    android:clipToPadding="true"
                    android:overScrollMode="never"
                    android:scrollbars="none" />
            </com.module.lottery.view.PullRecyclerViewGroup>

PullRecyclerViewGroup 的自定义代码如下

package com.module.lottery.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Sick on 2016/12/1.
 */
public class PullRecyclerViewGroup extends LinearLayout implements ViewTreeObserver.OnGlobalLayoutListener {


    /**
     * 滚动时间
     */
    private static final long ANIM_TIME = 400;

    //listview 或者recyclerview或者ScrollView
    private View childView;

    // 用于记录正常的布局位置
    private Rect originalRect = new Rect();

    //滚动时,移动的view和位置
    private List<View> mMoveViews = new ArrayList<View>();
    private List<Rect> mMoveRects = new ArrayList<Rect>();

    // 在手指滑动的过程中记录是否移动了布局
    private boolean isMoved = false;

    // 如果按下时不能上拉和下拉, 会在手指移动时更新为当前手指的Y值
    private float startY;

    //阻尼
    private static final float OFFSET_RADIO = 0.5f;

    private boolean isRecyclerReuslt = false;


    public PullRecyclerViewGroup(Context context) {
        this(context, null);
    }

    public PullRecyclerViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PullRecyclerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //关闭右侧滚动条
        this.setVerticalScrollBarEnabled(false);
    }

    /**
     * 加载布局后初始化,这个方法会在加载完布局后调用
     */
    @Override
    protected void onFinishInflate() {
        //此处为容器中的子view   必须有RecyclerView、ListView、ScrollView,当然这里忽略ListView和ScrollView
        if (getChildCount() > 0) {
            for (int i = 0; i < getChildCount(); i++) {
                if (getChildAt(i) instanceof RecyclerView || getChildAt(i) instanceof ListView || getChildAt(i) instanceof ScrollView) {
                    if (childView == null) {
                        childView = getChildAt(i);
                    } else {
                        throw new RuntimeException("PullRecyclerViewGroup 中只能存在一个RecyclerView、ListView或者ScrollView");
                    }
                }
            }
        }

        if (childView == null) {
            throw new RuntimeException("PullRecyclerViewGroup 子容器中必须有一个RecyclerView、ListView或者ScrollView");
        }
        //布局重绘监听,比如华为屏幕键盘可以弹出和隐藏,改变布局,加监听就可以虽键盘弹出关闭的变化而变化
        getViewTreeObserver().addOnGlobalLayoutListener(this);

        super.onFinishInflate();
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //ScrollView中唯一的子控件的位置信息,这个位置在整个控件的生命周期中保持不变
        originalRect.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
        for (int i = 0; i < mMoveViews.size(); i++) {
            final View v = mMoveViews.get(i);
            v.addOnLayoutChangeListener(new OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    Rect rect = new Rect();
                    rect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
                    mMoveRects.add(rect);
                    v.removeOnLayoutChangeListener(this);
                }
            });
        }
    }

    /**
     * 事件分发
     */

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (childView == null) {
            return super.dispatchTouchEvent(ev);
        }

        boolean isTouchOutOfScrollView = ev.getY() >= originalRect.bottom || ev.getY() <= originalRect.top; //如果当前view的Y上的位置
        if (isTouchOutOfScrollView) {//如果不在view的范围内
            if (isMoved) {      //当前容器已经被移动
                recoverLayout();
            }
            return true;
        }

        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //记录按下时的Y
                startY = ev.getY();
            case MotionEvent.ACTION_MOVE:
                float nowY = ev.getY();
                int scrollY = (int) (nowY - startY);
                if ((isCanPullDown() && scrollY > 0) || (isCanPullUp() && scrollY < 0) || (isCanPullDown() && isCanPullUp())) {
                    int offset = (int) (scrollY * OFFSET_RADIO);
                    childView.layout(originalRect.left, originalRect.top + offset, originalRect.right, originalRect.bottom + offset);
                    for (int i = 0; i < mMoveViews.size(); i++) {
                        if (mMoveViews.get(i) != null) {
                            mMoveViews.get(i).layout(mMoveRects.get(i).left, mMoveRects.get(i).top + offset, mMoveRects.get(i).right, mMoveRects.get(i).bottom + offset);
                        }
                    }
                    isMoved = true;
                    isRecyclerReuslt = false;
                    return true;
                } else {
                    startY = ev.getY();
                    isMoved = false;
                    isRecyclerReuslt = true;
                    recoverLayout();
                    return super.dispatchTouchEvent(ev);
                }
            case MotionEvent.ACTION_UP:

                if (isMoved) {
                    recoverLayout();
                }

                if (isRecyclerReuslt) {
                    return super.dispatchTouchEvent(ev);
                } else {
                    return true;
                }
            default:
                return true;
        }

    }

    /**
     * 位置还原
     */
    private void recoverLayout() {

        if (!isMoved) {
            return;//如果没有移动布局,则跳过执行
        }

        for (int i = 0; i < mMoveViews.size(); i++) {
            if (mMoveRects.get(i) != null) {
                TranslateAnimation anims = new TranslateAnimation(0, 0, mMoveViews.get(i).getTop(), mMoveRects.get(i).top);
                anims.setDuration(ANIM_TIME);
                mMoveViews.get(i).startAnimation(anims);
                mMoveViews.get(i).layout(mMoveRects.get(i).left, mMoveRects.get(i).top, mMoveRects.get(i).right, mMoveRects.get(i).bottom);
            }

        }

        TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop() - originalRect.top, 0);
        anim.setDuration(ANIM_TIME);
        childView.startAnimation(anim);

        childView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom);

        isMoved = false;
    }

    /**
     * 容器的的事件都在事件分发中处理,这里处理的是事件分发传递过来的事件,
     *
     * 传递过来的为RecyclerVIew的事件  不拦截,直接交给reyclerview处理
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;  //不拦截  直接传递给子的view
    }


    /**
     * 判断是否可以下拉
     * @return
     */
    private boolean isCanPullDown() {

        if(true){
            return false;
        }

        final RecyclerView.Adapter adapter = ((RecyclerView) childView).getAdapter();
        if (null == adapter) {
            return true;
        }
        //spf  ========================================================
        final int firstVisiblePosition = ((LinearLayoutManager) ((RecyclerView) childView).getLayoutManager()).findFirstVisibleItemPosition();
        if (firstVisiblePosition != 0 && adapter.getItemCount() != 0) {
            return false;
        }
        //===================================================================================
        int mostTop = (((RecyclerView) childView).getChildCount() > 0) ? ((RecyclerView) childView).getChildAt(0).getTop() : 0;
        return mostTop >= 0;
    }


    /**
     * 判断是否可以上拉
     * @return
     */
    private boolean isCanPullUp() {
        final RecyclerView.Adapter adapter = ((RecyclerView) childView).getAdapter();

        if (null == adapter) {
            return true;
        }

        final int lastItemPosition = adapter.getItemCount() - 1;
        final int lastVisiblePosition = ((LinearLayoutManager) ((RecyclerView) childView).getLayoutManager()).findLastVisibleItemPosition();

        if (lastVisiblePosition >= lastItemPosition) {
            final int childIndex = lastVisiblePosition - ((LinearLayoutManager) ((RecyclerView) childView).getLayoutManager()).findFirstVisibleItemPosition();
            final int childCount = ((RecyclerView) childView).getChildCount();
            final int index = Math.min(childIndex, childCount - 1);
            final View lastVisibleChild = ((RecyclerView) childView).getChildAt(index);
            if (lastVisibleChild != null) {
                return lastVisibleChild.getBottom() <= childView.getBottom() - childView.getTop();
            }
        }

        return false;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onGlobalLayout() {
        //华为手机屏幕下方的返回、home键显示隐藏改变布局
        requestLayout();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * 跟随弹性移动的view
     * @param view
     */
    public void setMoveViews(View view) {
        this.mMoveViews.add(view);
        requestLayout();
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值