先上效果:
整体思路很简单,利用列表上拉加载更多的原理,图中“左划加载”的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{ 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):
自定义属性:
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的写法继续写就可以了。当然有很多的属性也应该提供出来,后期完善会及时更新。不足之处还请大佬们多多指教。