先上效果:

整体思路很简单,利用列表上拉加载更多的原理,图中“左划加载”的view作为Adapter最后一个itemView,我们将自定义这个itemView, 根据recyclerView的左滑距离来操作这个自定义view, 然后再封装一下BaseAdapter,让子Adapter继承并实现它的方法即可。也可以通过自定义属性moreViewHideMode=true隐藏这个view, 就会有从外侧拉进来的效果。不足之处后期会及时更新。
HorizontalMoreDataView:
public class HorizontalMoreDataView extends View {
private Paint paint;
private int mCenterY;
private int mCenterX;
int x = 0;
private Paint fontPaint;
int fontSize = 35;
float fontHeight = 0;
private float offset;
String title = "左划加载";
String jumpTitle = "松开跳转";
String content = "";
private int diverWidth;
private int dampingNum = 80;
private int changeNum = 5;
private int mWidth;
private int viewWidth = -1;
private boolean hideMode;
private char[] chars;
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
try {
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.width = mWidth;
setLayoutParams(layoutParams);
} catch (Exception e) {
}
}
};
public HorizontalMoreDataView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public HorizontalMoreDataView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
/**
* 初始化
*
* @param context
* @param attrs
* @param defStyleAttr
*/
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorizontalMoreDataView, defStyleAttr, 0);
fontSize = typedArray.getLayoutDimension(R.styleable.HorizontalMoreDataView_moreViewTextSize, -1);
title = typedArray.getString(R.styleable.HorizontalMoreDataView_moreViewText);
jumpTitle = typedArray.getString(R.styleable.HorizontalMoreDataView_moreViewJumpText);
diverWidth = typedArray.getLayoutDimension(R.styleable.HorizontalMoreDataView_moreViewDiverWidth, 5);
hideMode = typedArray.getBoolean(R.styleable.HorizontalMoreDataView_moreViewHideMode, false);
content = title;
fontHeight = fontSize / 1.94f;
typedArray.recycle();
paint = new Paint();
paint.setStrokeWidth(diverWidth);
paint.setColor(Color.parseColor("#333333"));
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setDither(true);
fontPaint = new Paint();
fontPaint.setStrokeWidth(7);
fontPaint.setColor(Color.parseColor("#333333"));
fontPaint.setTextSize(fontSize);
fontPaint.setAntiAlias(true);
fontPaint.setDither(true);
offset = (fontPaint.getFontMetrics().top + fontPaint.getFontMetrics().bottom) / 2; //文字偏移量4
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (hideMode) {
width = 0;
hideMode = false;
}
if (viewWidth == -1)
viewWidth = width;
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mCenterY = getHeight() / 2;
mCenterX = getWidth() / 2;
Path path = new Path();
path.moveTo(mCenterX / 1.6F, mCenterY - mCenterY / 3);
path.lineTo(mCenterX / 1.6F - x, mCenterY);
path.lineTo(mCenterX / 1.6F, mCenterY + mCenterY / 3);
canvas.drawPath(path, paint);
chars = content.toCharArray();
//文字竖向居中排布处理
for (int i = 0; i < chars.length; i++) {
if (chars.length % 2 == 0) { //偶数索引
if (i == (chars.length / 2 - 1)) //中间位置的 靠上第一个
canvas.drawText(chars[i] + "", mCenterX, mCenterY - (fontSize * 1.4F) / 2 - offset, fontPaint);
if (i == (chars.length / 2)) //中间位置的 靠下第一个
canvas.drawText(chars[i] + "", mCenterX, mCenterY + (fontSize * 1.4F) / 2 - offset, fontPaint);
if (i < (chars.length / 2 - 1)) { // 靠上第一个的 上边的n个
int num = Math.abs((chars.length / 2 - 1) - i); //间隔个数
canvas.drawText(chars[i] + "", mCenterX, mCenterY - (num * ((fontSize * 1.4F)) + ((fontSize * 1.4F)) / 2) - offset, fontPaint);
}
if (i > (chars.length / 2)) { //靠下第一个的 下边的n个
int num = Math.abs(i - (chars.length / 2));
canvas.drawText(chars[i] + "", mCenterX, mCenterY + (num * ((fontSize * 1.4F)) + ((fontSize * 1.4F)) / 2) - offset, fontPaint);
}
} else { //奇数索引
if (i == ((chars.length - 1) / 2)) //中间位置
canvas.drawText(chars[i] + "", mCenterX, mCenterY - offset, fontPaint);
if (i < ((chars.length - 1) / 2)) { //中间以上的
int num = Math.abs(i - (chars.length / 2));
canvas.drawText(chars[i] + "", mCenterX, mCenterY - (num * ((fontSize * 1.4F))) - offset, fontPaint);
}
if (i > ((chars.length - 1) / 2)) { //中间以下的
int num = Math.abs(i - (chars.length / 2));
canvas.drawText(chars[i] + "", mCenterX, mCenterY + (num * ((fontSize * 1.4F))) - offset, fontPaint);
}
}
}
}
/**
* 设置移动距离
*
* @param distance
*/
public void setSlipDistance(int distance) {
x = distance / dampingNum;
if (x > changeNum) {
content = jumpTitle;
} else {
content = title;
}
invalidate();
mWidth = viewWidth + ((distance - 50) / 5);
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.width = mWidth;
setLayoutParams(layoutParams);
}
/**
* 是否到达可跳转的阀值
* @return
*/
public boolean getCanJump() {
return x > changeNum;
}
/**
* 手指释放 恢复view
*/
public void release() {
x = 0;
content = title;
new Thread(new Runnable() {
@Override
public void run() {
while (mWidth >= viewWidth) {
try {
Thread.sleep(1);
mWidth = mWidth - 6;
handler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
invalidate();
}
}
HorizontalMoreBaseAdapter:
public abstract class HorizontalMoreBaseAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public HorizontalMoreDataView horizontalView;
public static int MOREDATAVIEWTYPE = 9000;
private float x1;
private float y1;
private float x2;
private float y2;
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 9000) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_more_view_footer, null);
return new HorizontalMoreDataViewViewHolder(view);
} else {
return HorizontalMoreOnCreateViewHolder(parent, viewType);
}
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return MOREDATAVIEWTYPE;
} else {
return HorizontalMoreGetItemViewType(position);
}
}
class HorizontalMoreDataViewViewHolder extends RecyclerView.ViewHolder {
public HorizontalMoreDataViewViewHolder(@NonNull View itemView) {
super(itemView);
horizontalView = (HorizontalMoreDataView) itemView.findViewById(R.id.horzonView);
}
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {//当手指按下的时候
x1 = event.getX();
y1 = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {//当手指移动的时候
x2 = event.getX();
y2 = event.getY();
//45度分割 横向滑动
if (Math.abs(x2 - x1) > 50 && Math.abs(x2 - x1) > Math.abs(y2 - y1)) {
if (horizontalView != null)
horizontalView.setSlipDistance((int) (Math.abs(x1 - x2)));
}
//纵向滑动
if (Math.abs(y2 - y1) > 50 && Math.abs(y2 - y1) > Math.abs(x2 - x1)) {
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
x1 = 0;
x2 = 0;
if (horizontalView != null) {
if (horizontalView.getCanJump() && relaseJumpActivityListener != null)
relaseJumpActivityListener.relaseJump();
horizontalView.release();
}
}
return false;
}
});
}
public abstract RecyclerView.ViewHolder HorizontalMoreOnCreateViewHolder(@NonNull ViewGroup parent, int viewType);
public abstract int HorizontalMoreGetItemViewType(int postion);
RelaseJumpActivityListener relaseJumpActivityListener;
public void setRelaseJumpActivityListener(RelaseJumpActivityListener relaseJumpActivityListener) {
this.relaseJumpActivityListener = relaseJumpActivityListener;
}
public interface RelaseJumpActivityListener {
void relaseJump();
}
}
horizontal_more_view_footer(xml):
<com.xxx.xx.utils.HorizontalMoreDataView
android:background="#fff"
app:moreViewTextSize="16sp"
app:moreViewText="左划加载"
app:moreViewJumpText="松开跳转"
app:moreViewDiverWidth="5"
app:moreViewHideMode="false"
android:id="@+id/horzonView"
android:layout_width="55dp"
android:layout_height="wrap_content">
</com.watcn.wat.utils.HorizontalMoreDataView>
自定义属性:
<declare-styleable name="HorizontalMoreDataView">
<attr name="moreViewTextSize" format="dimension"/>
<attr name="moreViewText" format="string"/>
<attr name="moreViewJumpText" format="string"/>
<attr name="moreViewDiverWidth" format="integer"/>
<attr name="moreViewHideMode" format="boolean"/>
</declare-styleable>
MainActivity(使用方法):
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
MyAdapter myAdapter = new MyAdapter();
recyclerView.setAdapter(myAdapter);
myAdapter.setRelaseJumpActivityListener(new HorizontalMoreBaseAdapter.RelaseJumpActivityListener() {
@Override
public void relaseJump() {
Toast.showToast("跳转新Activity");
}
});
adapter继承HorizontalMoreBaseAdapter,实现HorizontalMoreOnCreateViewHolder和HorizontalMoreGetItemViewType,按照adapter的写法继续写就可以了。当然有很多的属性也应该提供出来,后期完善会及时更新。不足之处还请大佬们多多指教。
本文介绍如何通过自定义HorizontalMoreDataView和HorizontalMoreBaseAdapter,实现RecyclerView的左滑加载更多功能,包括视图动画、滑动响应和可跳转逻辑。通过设置自定义属性,提供了灵活的用户体验和界面控制。
1904

被折叠的 条评论
为什么被折叠?



