RecycleView横向滑动,要求实现如下滑轮蓝条可以随着手势跟随RecycleView界面左右滑动,类似滚轴
1.自定义View,单独设置setxoffSet()可实现滚动
package com.wttech.gm.tranmg.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.wttech.gm.tranmg.R;
/**
* @author LZY
* @time 2020-04-15.
*/
public class BottomGlideScrollView extends View {
private Paint mPaint;
private Path mPath;
private int mBgColor = 0xffEDEDED;
private int mScrollCollor = 0xff4090FF;
private float mScrollWidth = 20;//滚轮宽度
private float mScrollPostion = 0;//滚轮距离左边间距
private float inVisableWidth = 0;//RecycleView不可见宽度
private LinearLayoutManager layoutManager;
public static final String TAG = "BottomGlideScrollView";
public BottomGlideScrollView(Context context) {
this(context, null);
}
public BottomGlideScrollView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BottomGlideScrollView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomGlideScrollView);
mScrollWidth = (int) ta.getDimension(R.styleable.BottomGlideScrollView_scrollWidth, 20);
ta.recycle();
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawOrginBg(canvas);
drawScrollBg(canvas);
}
private void drawOrginBg(Canvas c) {
int width = getWidth();
drawLayout(c, width, mBgColor, 0);
}
private void drawScrollBg(Canvas c) {
drawLayout(c, mScrollWidth, mScrollCollor, mScrollPostion);
}
private void drawLayout(Canvas c, float width, int color, float xoffset) {
mPath.reset();
mPaint.setColor(color);
int height = getHeight();
float radius = height / 2.0f;
if (xoffset + width > getWidth()) {
xoffset = (float) getWidth() - width;
}
RectF rectLeft = new RectF(xoffset, 0, height + xoffset, height);
mPath.arcTo(rectLeft, 90, 180, false);
mPath.moveTo(radius + xoffset, 0);
mPath.lineTo(width - radius + xoffset, 0);
mPath.lineTo(width - radius + xoffset, height);
mPath.lineTo(radius + xoffset, height);
mPath.close();
RectF rectRight = new RectF(width - radius * 2 + xoffset, 0, width + xoffset, height);
mPath.arcTo(rectRight, 270, 180, true);
c.drawPath(mPath, mPaint);
}
/**
* 设置scroll距离左边间距
*
* @param xoffset
*/
public void setxoffSet(float xoffset) {
if (xoffset < 0) {
xoffset = 0;
}
if (inVisableWidth > 0) {
mScrollPostion = (xoffset / inVisableWidth) * (getWidth() - mScrollWidth);
} else {
mScrollPostion = 0.0f;
}
invalidate();
}
public void setPaintWidth(int visableWidth, int totalWidth) {
inVisableWidth = totalWidth - visableWidth;
if (inVisableWidth < 0) {
inVisableWidth = 0;
}
float percent = (float) visableWidth / totalWidth;
if (percent <= 0 || percent > 1) {
percent = 1;
}
mScrollWidth = (getWidth() * percent);
}
/**
* 与RecycleView绑定,获取rv滚动距离
*
* @param recyclerView
* @return
*/
public int getRvScrollDistance(RecyclerView recyclerView) {
View firstVisibleItem = recyclerView.getChildAt(0);
int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
int itemWidth = firstVisibleItem.getWidth();
int firstItemRight = layoutManager.getDecoratedRight(firstVisibleItem);
return (firstItemPosition + 1) * itemWidth - firstItemRight;
}
/**
* 与RecycleView绑定,获取rv全部宽度
* 并不是严格意义宽度
*
* @param recyclerView
* @return
*/
public int getRvTotalWidth(RecyclerView recyclerView) {
int width = 0;
View firstVisibleItem = recyclerView.getChildAt(0);
if (firstVisibleItem == null) {
return width;
}
int decoratedWidth = layoutManager.getDecoratedMeasuredWidth(firstVisibleItem);
Log.i(TAG, "decoratedWidth:" + decoratedWidth + ",firstVisibleItem:" + firstVisibleItem.getWidth());
int size = layoutManager.getItemCount();
if (size > 0) {
width = decoratedWidth * (size - 1) + firstVisibleItem.getWidth();
}
return width;
}
/**
* 绑定联动Recycleview
*/
public void bindRecycleView(RecyclerView recyclerView) {
layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
float scrollY = getRvScrollDistance(recyclerView);
setPaintWidth(recyclerView.getWidth(), getRvTotalWidth(recyclerView));
setxoffSet(scrollY);
Log.i(TAG, "scrollY:" + scrollY + "---width:" + recyclerView.getWidth());
}
});
//监听数据改变layout,更新显示条宽度
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
setPaintWidth(recyclerView.getWidth(), getRvTotalWidth(recyclerView));
}
});
}
}
attrs.xml
<declare-styleable name="BottomGlideScrollView">
<attr name="scrollWidth" format="dimension|reference"/>
</declare-styleable>
2.布局文件
<com.custom.BottomGlideScrollView
android:id="@+id/bottomGlideScrollView"
android:layout_width="@dimen/dp40"
android:layout_height="@dimen/dp4"
app:scrollWidth="@dimen/dp15"
/>
3.Activity
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
recycleview.setLayoutManager(linearLayoutManager);
//将RecycleView与控件绑定
bottomGlideScrollView.bindRecycleView(recycleview);