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;
}