最近想给RecyclerView弄一个自定义样式的滚动条,而我在这里使用的是RecyclerView,看了好多网上的自定义滚动条都是用这个控件那个控件的,我这里采用的是自己写的样式,不需要任何控件,主要是通过Translation设置平移动画来实现,废话不多说直接上代码
效果图
这里用shape写的灰色背景,然后再里面套用一个View也就是图中橙色部分,然后显示了一个滚动条的样式,这里样式有点简陋,如果需要更好看的样式可以自己自定义更好看的样式。
滚动条xml代码
<FrameLayout
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="102dp"
android:layout_height="5dp"
android:background="@drawable/horizontal_track"/>
<View
android:id="@+id/main_line"
android:layout_width="30dp"
android:layout_height="3dp"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:background="@drawable/horizontal_thumb"
android:layout_gravity="center_vertical"/>
</FrameLayout>
第一个view为背景用的一个灰色的shape写的xml背景,第二个为橙色滚动条 实现滚动的代码
float endX = 0;
//这里的mRvHx是需要绑定滚动条的RecyclerView
mRvHx.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//整体的总宽度,注意是整体,包括在显示区域之外的。
int range = mRvHx.computeHorizontalScrollRange();
float density = getScreenDensity();
//计算出溢出部分的宽度,即屏幕外剩下的宽度
float maxEndX = range + (10 * density) + 5 - ScreenUtils.getScreenWidth(MainActivity.this);
//滑动的距离
endX += dx;
//计算比例
float proportion = endX / maxEndX;
//计算滚动条宽度
int transMaxRange = ((ViewGroup) mLine.getParent()).getWidth() - mLine.getWidth();
//设置滚动条移动
mLine.setTranslationX(transMaxRange * proportion);
}
});
public float getScreenDensity() {
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
if (wm != null) {
wm.getDefaultDisplay().getMetrics(dm);
}
int width = dm.widthPixels;// 屏幕宽度(像素)
int height = dm.heightPixels; // 屏幕高度(像素)
float density = dm.density;//屏幕密度(0.75 / 1.0 / 1.5)
int densityDpi = dm.densityDpi;//屏幕密度dpi(120 / 160 / 240)
return density;
}
工具类代码
public class ScreenUtils {
private ScreenUtils() {
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 获得屏幕宽度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获得屏幕高度
*
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
/**
* 获得状态栏的高度
*
* @param context
* @return
*/
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
//获取虚拟按键的高度
public static int getNavigationBarHeight(Context context) {
int result = 0;
if (hasNavBar(context)) {
Resources res = context.getResources();
int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = res.getDimensionPixelSize(resourceId);
}
}
return result;
}
/**
* 检查是否存在虚拟按键栏
*
* @param context
* @return
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static boolean hasNavBar(Context context) {
Resources res = context.getResources();
int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android");
if (resourceId != 0) {
boolean hasNav = res.getBoolean(resourceId);
// check override flag
String sNavBarOverride = getNavBarOverride();
if ("1".equals(sNavBarOverride)) {
hasNav = false;
} else if ("0".equals(sNavBarOverride)) {
hasNav = true;
}
return hasNav;
} else { // fallback
return !ViewConfiguration.get(context).hasPermanentMenuKey();
}
}
/**
* 判断虚拟按键栏是否重写
*
* @return
*/
private static String getNavBarOverride() {
String sNavBarOverride = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Class c = Class.forName("android.os.SystemProperties");
Method m = c.getDeclaredMethod("get", String.class);
m.setAccessible(true);
sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
} catch (Throwable e) {
}
}
return sNavBarOverride;
}
/**
* 获取当前屏幕截图,包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bp;
}
/**
* 获取当前屏幕截图,不包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
- statusBarHeight);
view.destroyDrawingCache();
return bp;
}
}
需要注意的是这里的mRvHx是你需要设置自定义滚动条的RecyclerView,当你这里监听RecyclerView滚动时你自定义的这个view也会根据rv自动滚动,你可以随意将滚动条设置为横向还是纵向,如果是纵向只需要修改一下动画的平移方向即可,即将setTranslationX改成setTranslationY,另外再调试一下看看是否运动方向反了,如有疑问欢迎评论和反馈,谢谢大家