Android RecyclerView侧滑、下拉刷新、上拉加载功能


实现RecyclerView侧滑菜单,下拉刷新上拉加载功能,可以做到侧滑菜单包括数量、大小、样式等完全自定义实现

样式

在这里插入图片描述

准备工作

导入包

下拉刷新
api ‘io.github.scwang90:refresh-layout-kernel:2.0.5’ //核心必须依赖
api ‘io.github.scwang90:refresh-header-classics:2.0.5’ //经典刷新头
api ‘io.github.scwang90:refresh-footer-classics:2.0.5’ //经典加载
github地址:
https://gitee.com/scwang90/SmartRefreshLayout

定义接口

/**
 * 侧滑菜单功能点击回调接口
 * @param <T>
 */
public interface DefaultAdapterFunction<T>  {
    void onClick(T t,int position);
}
/**
 * 自定义布局加载接口
 * @param <T>
 */
public interface DefaultAdapterOnBind<T> {
    View onBind(View view, T data);
}
/**
 * 搜索控件文本更改
 */
public interface SearchTextChangedLinsener {
    default void searchTextChange(String value);
    default void searchButtonClick(String value);
}

侧滑功能bean

/**
 * 侧滑功能bean定义
 * @param <T>
 */
public class FunctionModel<T> {
    public String name;//名称
    public int color;//颜色
    public int layout;//布局
    public DefaultAdapterFunction<T> function;//点击事件

    public FunctionModel(){}
    public FunctionModel(String name){
        this.name = name;
    }
    public FunctionModel(String name,int color){
        this.name = name;
        this.color = color;
    }
    public FunctionModel(String name,DefaultAdapterFunction<T> function){
        this.name = name;
        this.function = function;
    }
    public FunctionModel(String name,int layout,DefaultAdapterFunction<T> function){
        this.name = name;
        this.layout = layout;
        this.function = function;
    }
    public FunctionModel(String name,int color,int layout,DefaultAdapterFunction<T> function){
        this.name = name;
        this.color = color;
        this.layout = layout;
        this.function = function;
    }
}

默认的adapter

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:id="@+id/default_adapter_pot"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
    </LinearLayout>
    
    <LinearLayout
        android:id="@+id/default_adapter_function"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:layout_gravity="center"
        >

    </LinearLayout>
</LinearLayout>

代码实现


import android.content.res.Resources;
import android.graphics.Color;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.pksh.tools.utils.nor.StringUtil;
import java.util.List;

/**
 * 默认RecyclerView的Adapter
 * 主要实现了右滑菜单
 * 驰郡
 * wechat:chijun9
 * 2023/11/18
*/
public class DefaultAdapter<T> extends RecyclerView.Adapter<DefaultAdapter.ViewHolder>{
    int layout;
    //数据
    private List<T> defaultData;
    //获取放入控件的view
    DefaultAdapterOnBind<T> defaultAdapterOnBind;
    //功能按钮设置
    List<FunctionModel<T>> functionModels;
    //功能按钮宽度
    private static final int functionWidth = 150;
    //默认背景颜色列表
    private static final int[] backColor = {
            Color.rgb(217, 80, 138), Color.rgb(254, 149, 7), Color.rgb(254, 247, 120),
            Color.rgb(106, 167, 134), Color.rgb(53, 194, 209)
    };

    public DefaultAdapter() {}

    /**
     *
     * @param defaultData 数据
     * @param layout 布局
     * @param defaultAdapterOnBind 布局加载回调
     */
    public DefaultAdapter(List<T> defaultData,int layout,DefaultAdapterOnBind<T> defaultAdapterOnBind) {
        this.defaultData = defaultData;
        this.defaultAdapterOnBind = defaultAdapterOnBind;
        this.layout = layout;
    }

    /**
     *
     * @param defaultData 数据
     * @param functionModels 功能按钮定义
     * @param layout 布局
     * @param defaultAdapterOnBind 布局加载回调
     */
    public DefaultAdapter(List<T> defaultData,List<FunctionModel<T>> functionModels,int layout,DefaultAdapterOnBind<T> defaultAdapterOnBind) {
        this.defaultData = defaultData;
        this.defaultAdapterOnBind = defaultAdapterOnBind;
        this.functionModels = functionModels;
        this.layout = layout;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_default, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
        T t = defaultData.get(position);
        holder.pot.removeAllViews();
        View view = defaultAdapterOnBind.onBind(LayoutInflater.from(holder.pot.getContext()).inflate(layout, null), t);
        holder.pot.addView(view);

        if (functionModels != null) {
            holder.function.removeAllViews();
            int wg = 0;//功能空间总宽度计算
            int i = 0;//用于背景色选择
            for (FunctionModel<T> functionModel : functionModels) {
                if (i > backColor.length) i = 0;
                if (functionModel.layout == 0) {
                    TextView textView = new TextView(holder.function.getContext());
                    //设置名称
                    if (StringUtil.isNull(functionModel.name)) textView.setText("");
                    else textView.setText(functionModel.name);
                    //背景颜色,如果颜色未设置,设置固定颜色
                    if (functionModel.color == 0) textView.setBackgroundColor(backColor[i]);
                    else textView.setBackgroundColor(functionModel.color);
                    //设置点击事件回调
                    final int pp = position;
                    textView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (functionModel.function != null) functionModel.function.onClick(t,pp);
                        }
                    });
                    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(functionWidth, ViewGroup.LayoutParams.MATCH_PARENT);
                    layoutParams.gravity = Gravity.CENTER;//布局居中
                    textView.setLayoutParams(layoutParams);
                    textView.setGravity(Gravity.CENTER);//文字居中
                    wg += functionWidth;
                    holder.function.addView(textView);
                } else {
                    View inflate = LayoutInflater.from(holder.function.getContext()).inflate(functionModel.layout, null);
                    wg += inflate.getLayoutParams().width;
                    holder.function.addView(inflate);
                }
                i++;
            }
            ViewGroup.LayoutParams layoutParams = holder.function.getLayoutParams();
            layoutParams.width = wg;
        }
    }

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

    static class ViewHolder extends  RecyclerView.ViewHolder{
        private final LinearLayout pot,function;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            pot = itemView.findViewById(R.id.default_adapter_pot);
            function = itemView.findViewById(R.id.default_adapter_function);


            if (itemView.getBackground() == null) {
                TypedValue typedValue = new TypedValue();
                Resources.Theme theme = itemView.getContext().getTheme();
                int top = itemView.getPaddingTop();
                int bottom = itemView.getPaddingBottom();
                int left = itemView.getPaddingLeft();
                int right = itemView.getPaddingRight();
                if (theme.resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true)) {
                    itemView.setBackgroundResource(typedValue.resourceId);
                }
                itemView.setPadding(left, top, right, bottom);
            }
        }
    }
}

滑动状态处理

这个是抄的,确实忘记哪里抄的了,罪过罪过

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import androidx.core.view.GestureDetectorCompat;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 处理RecyclerView滑动
 */
public class ItemSlideHelper implements RecyclerView.OnItemTouchListener, GestureDetector.OnGestureListener{
    private final int DEFAULT_DURATION = 200;
    private View mTargetView;

    private int mActivePointerId;
    private int mTouchSlop;
    private int mMaxVelocity;
    private int mMinVelocity;
    private int mLastX;
    private int mLastY;

    private boolean mIsDragging;
    private Animator mExpandAndCollapseAnim;
    private GestureDetectorCompat mGestureDetector;

    private Callback mCallback;

    public ItemSlideHelper(Context context, Callback callback) {
        this.mCallback = callback;

        //手势用于处理fling
        mGestureDetector = new GestureDetectorCompat(context, this);

        ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
        mMaxVelocity = configuration.getScaledMaximumFlingVelocity();
        mMinVelocity = configuration.getScaledMinimumFlingVelocity();
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

//        logUtil.d(TAG,"调用onInterceptTouchEvent");
        int action = MotionEventCompat.getActionMasked(e);
        int x = (int) e.getX();
        int y = (int) e.getY();

        //如果RecyclerView滚动状态不是空闲targetView不是空
        if (rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
            if (mTargetView != null) {
                //隐藏已经打开
//                myLog.d(TAG,"隐藏已打开"+x+y);
                smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);
                mTargetView = null;
            }

            return false;
        }

        //如果正在运行动画 ,直接拦截什么都不做
        if (mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning()) {
            return true;
        }

        boolean needIntercept = false;
        switch (action) {
            case MotionEvent.ACTION_DOWN:

                mActivePointerId = MotionEventCompat.getPointerId(e, 0);
                mLastX = (int) e.getX();
                mLastY = (int) e.getY();

                /*
                 * 如果之前有一个已经打开的项目,当此次点击事件没有发生在右侧的菜单中则返回TRUE,
                 * 如果点击的是右侧菜单那么返回FALSE这样做的原因是因为菜单需要响应Onclick
                 * */
                if (mTargetView != null) {
                    if (!inView(x, y)) {
                        //点击一下(不管点击的是右侧滑出菜单还是哪里)既收回右侧滑出菜单
                        //折叠菜单
                        smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);
                        return true;
                    } else {
                        return false;
                    }
                }

                //查找需要显示菜单的view;
                mTargetView = mCallback.findTargetView(x, y);

                break;
            case MotionEvent.ACTION_MOVE:

                int deltaX = (x - mLastX);
                int deltaY = (y - mLastY);

                if (Math.abs(deltaY) > Math.abs(deltaX))
                    return false;

                //如果移动距离达到要求,则拦截
                needIntercept = mIsDragging = mTargetView != null && Math.abs(deltaX) >= mTouchSlop;
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                /*
                 * 走这是因为没有发生过拦截事件
                 * */
                if (isExpanded()) {

                    if (inView(x, y)) {
                        // 如果走这那行这个ACTION_UP的事件会发生在右侧的菜单中
                    } else {
                        //拦截事件,防止targetView执行onClick事件
                        needIntercept = true;
                    }

                    //折叠菜单
                    smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);
                }

                mTargetView = null;
                break;
        }

        return needIntercept;
    }

    private boolean isExpanded() {
        return mTargetView != null && mTargetView.getScrollX() == getHorizontalRange();
    }

    private boolean isCollapsed() {

        return mTargetView != null && mTargetView.getScrollX() == 0;
    }

    /*
     * 根据targetView的scrollX计算出targetView的偏移,这样能够知道这个point
     * 是在右侧的菜单中
     * */
    private boolean inView(int x, int y) {

        if (mTargetView == null)
            return false;

        int scrollX = mTargetView.getScrollX();
        int left = mTargetView.getWidth() - scrollX;
        int top = mTargetView.getTop();
        int right = left + getHorizontalRange();
        int bottom = mTargetView.getBottom();
        Rect rect = new Rect(left, top, right, bottom);
        return rect.contains(x, y);
    }
    private static final String TAG = "rec的Item滑动事件";

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

        if (mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning() || mTargetView == null)
            return;

        //如果要响应fling事件设置将mIsDragging设为false
        if (mGestureDetector.onTouchEvent(e)) {
            mIsDragging = false;
            return;
        }

        int topRowVerticalPosition = ( rv.getChildCount() == 0) ? 0 : rv.getChildAt(0).getTop();


        int x = (int) e.getX();
        int y = (int) e.getY();
        int action = MotionEventCompat.getActionMasked(e);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //RecyclerView 不会转发这个Down事件

                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = (int) (mLastX - e.getX());
                if (mIsDragging) {
                    horizontalDrag(deltaX);
                }

                mLastX = x;
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mIsDragging) {

                    if (!smoothHorizontalExpandOrCollapse(0) && isCollapsed())
                        mTargetView = null;
                    mIsDragging = false;
                }

                break;
        }
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }

    /**
     * 根据touch事件来滚动View的scrollX
     *
     * @param delta
     */
    private void horizontalDrag(int delta) {
        int scrollX = mTargetView.getScrollX();
        int scrollY = mTargetView.getScrollY();
        if ((scrollX + delta) <= 0) {
            mTargetView.scrollTo(0, scrollY);
            return;
        }

        int horRange = getHorizontalRange();
        scrollX += delta;
        if (Math.abs(scrollX) < horRange) {
            mTargetView.scrollTo(scrollX, scrollY);
        } else {
            mTargetView.scrollTo(horRange, scrollY);
        }
    }

    /**
     * 根据当前scrollX的位置判断是展开还是折叠
     *
     * @param velocityX 如果不等于0那么这是一次fling事件,否则是一次ACTION_UP或者ACTION_CANCEL
     */
    private boolean smoothHorizontalExpandOrCollapse(float velocityX) {

        int scrollX = mTargetView.getScrollX();
        int scrollRange = getHorizontalRange();

        if (mExpandAndCollapseAnim != null)
            return false;

        int to = 0;
        int duration = DEFAULT_DURATION;

        if (velocityX == 0) {

            //如果已经展一半,平滑展开
            if (scrollX > scrollRange / 2) {
                to = scrollRange;
            }
        } else {
            if (velocityX > 0) {
                to = 0;
            } else {
                to = scrollRange;
            }

            duration = (int) ((1.f - Math.abs(velocityX) / mMaxVelocity) * DEFAULT_DURATION);
        }

        if (to == scrollX)
            return false;

        mExpandAndCollapseAnim = ObjectAnimator.ofInt(mTargetView, "scrollX", to);
        mExpandAndCollapseAnim.setDuration(duration);
        mExpandAndCollapseAnim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mExpandAndCollapseAnim = null;
                if (isCollapsed())
                    mTargetView = null;

            }

            @Override
            public void onAnimationCancel(Animator animation) {
                //onAnimationEnd(animation);
                mExpandAndCollapseAnim = null;

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        mExpandAndCollapseAnim.start();

        return true;
    }

    public int getHorizontalRange() {
        RecyclerView.ViewHolder viewHolder = mCallback.getChildViewHolder(mTargetView);
        return mCallback.getHorizontalRange(viewHolder);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        if (Math.abs(velocityX) > mMinVelocity && Math.abs(velocityX) < mMaxVelocity) {
            if (!smoothHorizontalExpandOrCollapse(velocityX)) {
                if (isCollapsed())
                    mTargetView = null;
                return true;
            }
        }
        return false;
    }

    /**
     * 左滑菜单Callback
     */
    public interface Callback {

        int getHorizontalRange(RecyclerView.ViewHolder holder);

        RecyclerView.ViewHolder getChildViewHolder(View childView);

        View findTargetView(float x, float y);

    }
}

RecyclerView定义

布局

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

    <LinearLayout
        android:id="@+id/base_recycler_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_margin="5dp"
        android:background="@drawable/yuanjiaobaise"
        >

        <EditText
            android:id="@+id/base_recycler_search_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            style="@style/DefEditText2"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:textSize="@dimen/def_text_default_size"
            android:padding="5dp"
            android:background="@null"
            android:imeOptions="actionSearch"
            android:inputType="text"
            android:hint="@string/base_recycler_search_hint" />

        <ImageView
            android:id="@+id/base_recycler_search_img"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/def_search"
            android:padding="5dp"
            android:layout_margin="5dp"
            android:layout_gravity="center"
            />
    </LinearLayout>


    <LinearLayout
        android:id="@+id/base_recycler_load_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@+id/base_recycler_search"
        >

        <LinearLayout
            android:id="@+id/base_recycler_load_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_gravity="center"
            >
            <ProgressBar
                android:layout_width="30dp"
                android:layout_height="30dp"
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="@string/base_recycler_default_load_data"
                android:gravity="center"
                android:textSize="@dimen/def_text_small_size"
                android:textColor="@color/red1"
                />
        </LinearLayout>


        <TextView
            android:id="@+id/base_recycler_empty_data"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/base_recycler_default_empty_tip"
            android:gravity="center"
            android:textSize="@dimen/def_text_small_size"
            android:textColor="@color/custom_m_gray"
            android:visibility="gone"
            />

        <TextView
            android:id="@+id/base_recycler_get_data_error"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/base_recycler_default_error_data"
            android:gravity="center"
            android:textSize="@dimen/def_text_small_size"
            android:textColor="@color/red1"
            android:visibility="gone"
            />

        <com.scwang.smart.refresh.layout.SmartRefreshLayout
            android:id="@+id/base_recycler_refreshLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:srlHeaderMaxDragRate="2.5"
            app:srlPrimaryColor="@android:color/darker_gray"
            app:srlAccentColor="@android:color/white"
            >
            <!--srlHeaderMaxDragRate=2.5时候WaterDropHeader的下拉效果最好-->
            <com.scwang.smart.refresh.header.ClassicsHeader
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

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

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

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

代码实现

package com.pksh.tools.base.control;

import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.blankj.utilcode.util.ActivityUtils;
import com.pksh.tools.style.adapter.ItemSlideHelper;
import com.pksh.tools.style.display.SearchTextChangedLinsener;
import com.scwang.smart.refresh.layout.SmartRefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnLoadMoreListener;
import com.scwang.smart.refresh.layout.listener.OnRefreshListener;

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

/**
 * RecyclerView模板
 */
public class BaseRecycler<T> extends RelativeLayout {
    private static final String TAG = "BaseRecycler";
    private RecyclerView recyclerView;
    private SmartRefreshLayout refreshLayout;//下拉刷新
    //正在加载控件 搜索控件
    private LinearLayout loadData,search;
    //空数据提示  错误提示
    private TextView emptyData,errorData;
    //搜索文本框
    private EditText searchText;
    //搜索按钮
    private ImageView searchImg;
    private RecyclerView.Adapter<?> adapter;
    //数据
    private List<T> defaultData;

    private static final int DATA_STATE_NULL = 1;
    private static final int DATA_STATE_LOAD = 2;
    private static final int DATA_STATE_LOAD_ERROR = 3;
    private static final int DATA_STATE_OK = 4;

    public BaseRecycler(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        LayoutInflater.from(getContext()).inflate(R.layout.base_recycler,this);
        recyclerView = findViewById(R.id.base_recycler_rec);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        recyclerView.setItemAnimator(new DefaultItemAnimator());
        refreshLayout = findViewById(R.id.base_recycler_refreshLayout);
        search = findViewById(R.id.base_recycler_search);
        searchText = findViewById(R.id.base_recycler_search_text);
        searchImg = findViewById(R.id.base_recycler_search_img);
        search.setVisibility(View.GONE);

        loadData = findViewById(R.id.base_recycler_load_data);//正在加载
        emptyData = findViewById(R.id.base_recycler_empty_data);//空数据
        errorData = findViewById(R.id.base_recycler_get_data_error);//错误数据
        adapter = new DefaultAdapter<>();
        //设置动画
        setAnimator();
    }

    private void setControlState(int state){
        switch (state) {
            case DATA_STATE_NULL:
                loadData.setVisibility(View.GONE);
                emptyData.setVisibility(View.VISIBLE);
                errorData.setVisibility(View.GONE);
                break;
            case DATA_STATE_LOAD:
                loadData.setVisibility(View.VISIBLE);
                emptyData.setVisibility(View.GONE);
                errorData.setVisibility(View.GONE);
                break;
            case DATA_STATE_LOAD_ERROR:
                loadData.setVisibility(View.GONE);
                emptyData.setVisibility(View.GONE);
                errorData.setVisibility(View.VISIBLE);
                break;
            case DATA_STATE_OK:
                loadData.setVisibility(View.GONE);
                emptyData.setVisibility(View.GONE);
                errorData.setVisibility(View.GONE);
                break;
        }
    }

    private void setDataState(){
        if (defaultData == null || defaultData.size() < 1) {
            setControlState(DATA_STATE_NULL);
        } else {
            setControlState(DATA_STATE_OK);
        }
    }

    /**
     * 设置分割线
     */
    public void setItemDecoration(@NonNull RecyclerView.ItemDecoration decor){
        recyclerView.addItemDecoration(decor);
    }

    /**
     * 设置默认分割线
     */
    public void setItemDecoration(){
        recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), 1));
    }

    /**
     * 设置默认Adapter
     * @param defaultData 数据
     * @param layout 布局文件
     * @param defaultAdapterOnBind  自定义布局加载回调
     */
    public void setDefaultAdapter(List<T> defaultData,int layout,DefaultAdapterOnBind<T> defaultAdapterOnBind){
        this.defaultData = defaultData;
        setDataState();
        adapter = new DefaultAdapter<>(this.defaultData,layout,defaultAdapterOnBind);
        setAdapter(adapter);
    }

    /**
     * 设置默认Adapter带右滑菜单功能
     * @param layout 布局文件
     * @param defaultData 数据
     * @param functionModels 右滑菜单功能按钮定义
     * @param defaultAdapterOnBind 自定义布局加载回调
     */
    public void setDefaultAdapter(List<T> defaultData,List<FunctionModel<T>> functionModels,int layout,DefaultAdapterOnBind<T> defaultAdapterOnBind){
        this.defaultData = defaultData;
        setDataState();
        adapter = new DefaultAdapter<>(this.defaultData,functionModels,layout,defaultAdapterOnBind);
        if (functionModels != null && functionModels.size() > 0 ) showRightFunction();
        setAdapter(adapter);
    }

    /**
     * 显示右侧划出功能
     */
    private void showRightFunction(){
        if (adapter != null && adapter instanceof DefaultAdapter) {
            //触摸监听
            recyclerView.addOnItemTouchListener(new ItemSlideHelper(getContext(), new ItemSlideHelper.Callback() {
                @Override
                public int getHorizontalRange(RecyclerView.ViewHolder holder) {
                    if (holder.itemView instanceof LinearLayout) {
                        ViewGroup viewGroup = (ViewGroup) holder.itemView;
                        int count = viewGroup.getChildCount();
                        int resultWieth = 0;
                        //返回左移的宽度
                        if (count >1) {
                            //略过第一个控件,因为第一个一般是主体
                            for (int i=1;i<count;i++) {
                                if (viewGroup.getChildAt(i).getVisibility() == View.VISIBLE) {
                                    resultWieth += viewGroup.getChildAt(i).getLayoutParams().width;
                                }
                            }
                            return resultWieth;
                        }
                    }
                    return 0;
                }

                @Override
                public RecyclerView.ViewHolder getChildViewHolder(View childView) {
                    return recyclerView.getChildViewHolder(childView);
                }

                @Override
                public View findTargetView(float x, float y) {
                    return recyclerView.findChildViewUnder(x, y);
                }
            }));
        } else {
            logUtil.d("设置右侧功能键划出失败 adapter为空或者其不是默认的布局!");
        }
    }

    /**
     * 添加默认动画
     */
    public void setAnimator(){
        DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
        defaultItemAnimator.setAddDuration(200);
        defaultItemAnimator.setRemoveDuration(200);
        recyclerView.setItemAnimator(defaultItemAnimator);
    }

    /**
     * 添加自定义动画
     */
    public void setAnimator(DefaultItemAnimator defaultItemAnimator){
        if (defaultItemAnimator == null) setAnimator();
        else recyclerView.setItemAnimator(defaultItemAnimator);
    }

    /**
     * 添加自定义Adapter
     */
    public void setAdapter(@Nullable RecyclerView.Adapter<?> adapter){
        loadData.setVisibility(View.GONE);

        if (adapter == null || adapter.getItemCount() < 1) {
            emptyData.setVisibility(View.VISIBLE);
        } else {
            emptyData.setVisibility(View.GONE);
        }
        this.adapter = adapter;
        recyclerView.setAdapter(this.adapter);
    }


    /**
     * 设置布局样式
     */
    public void setLayoutManager(@Nullable RecyclerView.LayoutManager layout){
        recyclerView.setLayoutManager(layout);
    }

    //下拉刷新
    public void setDownRefresh(OnRefreshListener onRefreshListener){
        refreshLayout.setOnRefreshListener(onRefreshListener);
    }

    //上拉加载更多
    public void setUpRefresh(OnLoadMoreListener onLoadMoreListener){
        refreshLayout.setOnLoadMoreListener(onLoadMoreListener);
    }

    /**
     * 显示新的搜索界面activity
     * @param tag 新的搜索界面所需要的标记 用于获取历史数据
     */
    public void showNewSearchActivity(int tag){
        search.setVisibility(View.VISIBLE);
        searchText.setOnClickListener(getSearchOnclick(tag));
        searchImg.setOnClickListener(getSearchOnclick(tag));
    }

    /**
     * 跳转新的搜索界面
     * @param tag 新的搜索界面所需要的标记 用于获取历史数据
     * @return 点击事件
     */
    private View.OnClickListener getSearchOnclick(int tag){
        return new OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(),SearchActivity.class);
                intent.putExtra("type",tag);
                ActivityUtils.getTopActivity().startActivityForResult(intent,tag);
            }
        };
    }

    /**
     * 显示搜索控件
     * @param changedListener 搜索
     */
    public void showSearchControl(SearchTextChangedLinsener changedListener){
        search.setVisibility(View.VISIBLE);
        //edittext输入监听  注意该方法需要通过敲击回车键才会有所监听返回
        searchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                //在最后有这个代码
                    KeyboardUtils.hideSoftInput(textView);//隐藏软键盘
                    changedListener.searchTextChange(textView.getText().toString());
                }
                return false;
            }
        });
        searchImg.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                changedListener.searchButtonClick(searchText.getText().toString());
            }
        });
    }

    /**
     * 设置错误提示
     * @param value 错误信息
     */
    public void setErrorData(String value){
        errorData.setVisibility(VISIBLE);
        errorData.setText(value);
    }

    private boolean isIndexOutOfBounds(int position){
        return position >= adapter.getItemCount();
    }

    /**
     * 刷新某条数据
     * @param position 数据编号
     */
    public void refreshData(int position){
        if (isIndexOutOfBounds(position)) {
            logUtil.e(TAG,"刷新数据失败,下标越界:"+position+",当前最大下标值:"+(adapter.getItemCount()-1));
        }
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                adapter.notifyItemChanged(position);
            }
        });
    }

    /**
     * 固定位置插入数据
     * @param position 数据编号
     * @param data 数据
     */
    public void addDataOnFix(int position,T data){
        if (data == null) {
            logUtil.e(TAG,"头部添加数据失败,传入数据为null");
            return;
        }
        if (!isIndexOutOfBounds(position)) {
            defaultData.add(position,data);
        } else {
            defaultData.add(data);
            position = defaultData.size()-1;
        }
        int finalPos = position;
        recyclerView.post(() -> {
            adapter.notifyItemInserted(finalPos);//通知演示插入动画
            adapter.notifyItemRangeChanged(finalPos,defaultData.size()-finalPos);//通知数据与界面重新绑定
            recyclerView.scrollToPosition(finalPos);
        });
        setDataState();
    }

    /**
     * 头插数据
     * @param data  数据
     */
    public void addDataOnHead(T data){
        if (data == null) {
            logUtil.e(TAG,"头部添加数据失败,传入数据为null");
            return;
        }
        defaultData.add(0,data);
        recyclerView.post(() -> {
            adapter.notifyItemInserted(0);//通知演示插入动画
            adapter.notifyItemRangeChanged(0,defaultData.size());//通知数据与界面重新绑定
            recyclerView.scrollToPosition(0);
        });
        setDataState();
    }


    /**
     * 尾插数据
     * @param data 数据
     */
    public void addDataOnTail(T data){
        if (data == null) {
            logUtil.e(TAG,"尾部添加数据失败,传入数据为null");
            return;
        }
        defaultData.add(data);
        recyclerView.post(() -> {
            adapter.notifyItemInserted(adapter.getItemCount());//通知演示插入动画
        });
        setDataState();
    }

    /**
     * 删除数据
     * @param position 数据编号
     */
    public void removeData(int position){
        if (isIndexOutOfBounds(position)) {
            logUtil.e(TAG,"删除数据失败,下标越界:"+position+",当前最大下标值:"+(adapter.getItemCount()-1));
            return;
        }
        defaultData.remove(position);
        recyclerView.post(() -> {
            adapter.notifyItemRemoved(position);
            adapter.notifyItemRangeChanged(0,defaultData.size());//通知数据与界面重新绑定
        });
        setDataState();
    }


    /**
     * 批量添加数据
     * @param data 数据
     */
    public void addDatas(List<T> data){
        //是否为空
        if (data == null) {
            logUtil.e(TAG,"添加多条数据,数据不可为空");
            return;
        }
        //是否没有数据
        if (data.size() < 1) {
            logUtil.e(TAG,"添加多条数据,传入参数无数据");
            return;
        }
        int oldSize = defaultData.size();
        defaultData.addAll(data);
        recyclerView.post(() -> {
            adapter.notifyItemRangeInserted(oldSize, defaultData.size());
        });
        setDataState();
    }

    /**
     * 清空所有数据
     */
    public void clearDataAll(){
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                int previousSize = defaultData.size();
                defaultData.clear();
                adapter.notifyItemRangeRemoved(0, previousSize);
                defaultData.addAll(new ArrayList<>());
                adapter.notifyItemRangeInserted(0, defaultData.size());
                setDataState();
            }
        });
    }

    /**
     * 替换数据,刷新操作
     * @param data 数据
     */
    public void replaceData(@NonNull List<T> data){
        //是否没有数据
        recyclerView.post(() -> {
            int previousSize = defaultData.size();
            defaultData.clear();
            adapter.notifyItemRangeRemoved(0, previousSize);
            defaultData.addAll(data);
            adapter.notifyItemRangeInserted(0, defaultData.size());
            setDataState();
        });
    }



    public RecyclerView.Adapter<?>  getAdapter(){
        return recyclerView.getAdapter();
    }
    public RecyclerView getRecyclerView() {
        return recyclerView;
    }
    public void setRefreshLayout(SmartRefreshLayout refreshLayout) {
        this.refreshLayout = refreshLayout;
    }
    public void setRecyclerView(RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
    }
    public SmartRefreshLayout getRefreshLayout() {
        return refreshLayout;
    }

    public LinearLayout getLoadData() {
        return loadData;
    }

    public void setLoadData(LinearLayout loadData) {
        this.loadData = loadData;
    }

    public LinearLayout getSearch() {
        return search;
    }

    public void setSearch(LinearLayout search) {
        this.search = search;
    }

    public TextView getEmptyData() {
        return emptyData;
    }

    public void setEmptyData(TextView emptyData) {
        this.emptyData = emptyData;
    }

    public TextView getErrorData() {
        return errorData;
    }

    public void setErrorData(TextView errorData) {
        this.errorData = errorData;
    }

    public EditText getSearchText() {
        return searchText;
    }

    public void setSearchText(EditText searchText) {
        this.searchText = searchText;
    }

    public ImageView getSearchImg() {
        return searchImg;
    }

    public void setSearchImg(ImageView searchImg) {
        this.searchImg = searchImg;
    }

    public List<T> getDefaultData() {
        return defaultData;
    }

    public void setDefaultData(List<T> defaultData) {
        this.defaultData = defaultData;
    }
}

其他一些功能

/**
     * 隐藏软键盘
     * @param view The view.
     */
    public static void hideSoftInput(@NonNull final View view) {
        InputMethodManager imm =
                (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm == null) {
            return;
        }
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

调用

布局

		<com.pksh.tools.base.control.BaseRecycler
	        android:id="@+id/beautiful_words_main_show_rec"
	        android:layout_width="match_parent"
	        android:layout_height="match_parent"
        />

代码实现

baseRecycler.setDefaultAdapter(wordsList, getListFunction(), R.layout.adapter_load_beautiful_words, new DefaultAdapterOnBind<BeautifulWords>() {
    @Override
    public View onBind(View view, BeautifulWords data) {
        TextView content = view.findViewById(R.id.adapter_load_beautiful_words_content);
        TextView analysis = view.findViewById(R.id.adapter_load_beautiful_words_analysis);
        content.setText(data.getContent());
        analysis.setText(data.getAnalysis());
        return view;
    }
});

//设置侧滑功能
/**
* 获取右侧滑出功能
* @return 功能配置
*/
private List<FunctionModel<BeautifulWords>> getListFunction(){
   List<FunctionModel<BeautifulWords>> functionModelList = new ArrayList<>();
   FunctionModel<BeautifulWords> see = new FunctionModel<>("详情", new DefaultAdapterFunction<BeautifulWords>() {
       @Override
       public void onClick(BeautifulWords beautifulWords,int position) {
           //功能点击事件
       }
   });

   FunctionModel<BeautifulWords> update = new FunctionModel<>("修改", new DefaultAdapterFunction<BeautifulWords>() {
       @Override
       public void onClick(BeautifulWords beautifulWords,int position) {
           //功能点击事件
       }
   });

   FunctionModel<BeautifulWords> delete = new FunctionModel<>("删除", new DefaultAdapterFunction<BeautifulWords>() {
       @Override
       public void onClick(BeautifulWords beautifulWords,int position) {
     		//功能点击事件
       }
   });
   functionModelList.add(see);
   functionModelList.add(update);
   functionModelList.add(delete);
   return functionModelList;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用 RecyclerView 实现侧滑功能。以下是一种常见的实现方法: 1. 首先,在你的 RecyclerView 的适配器中,创建一个内部类继承自 RecyclerView.ViewHolder。这个 ViewHolder 类将用于表示每个列表项。 ```java public class MyViewHolder extends RecyclerView.ViewHolder { public View containerView; public ImageView deleteButton; public MyViewHolder(View view) { super(view); containerView = view.findViewById(R.id.container_view); deleteButton = view.findViewById(R.id.delete_button); } } ``` 2. 在适配器的 onBindViewHolder 方法中,为每个列表项设置触摸监听器,以处理侧滑手势。 ```java @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { // 设置触摸监听器 holder.containerView.setOnTouchListener(new View.OnTouchListener() { private float initialX; private boolean isSwipeActive = false; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: initialX = event.getX(); isSwipeActive = false; return true; case MotionEvent.ACTION_MOVE: float deltaX = event.getX() - initialX; if (deltaX > 0 && !isSwipeActive) { // 右滑,显示删除按钮 holder.deleteButton.setVisibility(View.VISIBLE); isSwipeActive = true; } else if (deltaX <= 0 && isSwipeActive) { // 左滑,隐藏删除按钮 holder.deleteButton.setVisibility(View.GONE); isSwipeActive = false; } return true; case MotionEvent.ACTION_UP: // 处理点击事件 if (!isSwipeActive) { // TODO: 处理列表项的点击事件 } return true; } return false; } }); // TODO: 对列表项进行其他常规设置 } ``` 3. 最后,在你的布局文件中,为列表项添加删除按钮,并设置其可见性为 Gone。 ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container_view" ...> <!-- 列表项的其他视图 --> <ImageView android:id="@+id/delete_button" ... (设置删除按钮的样式和位置) android:visibility="gone" /> </RelativeLayout> ``` 以上步骤中,我们在 onBindViewHolder 方法中添加了触摸监听器,并根据手势显示或隐藏删除按钮。你可以根据自己的需求,对删除按钮的样式和位置进行调整,并在点击事件中处理列表项的其他操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值