Ai
2 Star 1 Fork 1

Aivin_CodeShare/android_tool_code

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
RecyclerViewFastScroller.java 9.37 KB
一键复制 编辑 原始数据 按行查看 历史
Aivin 提交于 2021-09-06 11:59 +08:00 . 快速拖动条
package com.aivin.lib_login.ui;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.aivin.lib_base.tool.WkLog;
public class RecyclerViewFastScroller extends LinearLayout {
/**
* 动画执行时间
*/
private static final int BUBBLE_ANIMATION_DURATION = 100;
/**
* alpha 动画
*/
private ObjectAnimator currentAnimator = null;
/**
* 用来进行微调,可以不要
*/
private static final int TRACK_SNAP_RANGE = 5;
/**
* 指示器(显示文字)
*/
private TextView bubble;
/**
* 拖动条
*/
private View handle;
private RecyclerView recyclerView;
/**
* 当前控件的高度
*/
private int height;
private boolean isInitialized = false;
// region RecyclerView 滚动监听
private final RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
updateBubbleAndHandlePosition(); // onScrolled
}
};
// endregion
public interface BubbleTextGetter {
String getTextToShowInBubble(int pos);
}
// region 构造函数
public RecyclerViewFastScroller(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public RecyclerViewFastScroller(final Context context) {
super(context);
init(context);
}
public RecyclerViewFastScroller(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context);
}
// endregion
// region 初始化 LinearLayout
protected void init(Context context) {
if (isInitialized){
return;
}
isInitialized = true;
setOrientation(HORIZONTAL);
setClipChildren(false);
}
// endregion
// region 函数重新
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
height = h;
updateBubbleAndHandlePosition(); // onSizeChanged
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (event.getX() < handle.getX() - ViewCompat.getPaddingStart(handle)){
return false;
}
if (currentAnimator != null){
currentAnimator.cancel();
}
if (bubble != null && bubble.getVisibility() == INVISIBLE){
showBubble(); // ACTION_DOWN
}
handle.setSelected(true);
case MotionEvent.ACTION_MOVE:
final float y = event.getY();
setBubbleAndHandlePosition(y); // ACTION_MOVE
setRecyclerViewPosition(y);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handle.setSelected(false);
hideBubble(); // ACTION_CANCEL 、ACTION_UP
return true;
}
return super.onTouchEvent(event);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (recyclerView != null) {
recyclerView.removeOnScrollListener(onScrollListener);
recyclerView = null;
}
}
// endregion
/**
* 让 recyclerView 跟随 拖动条滚动
*/
private void setRecyclerViewPosition(float y) {
if(recyclerView==null){
return;
}
if(recyclerView.getAdapter()==null){
return;
}
float proportion; // 滑块目前所在高度的比例
if (handle.getY() == 0){
proportion = 0f;
}else if (handle.getY() + handle.getHeight() >= height - TRACK_SNAP_RANGE){
proportion = 1f;
}else{
proportion = y / (float) height;
}
final int itemCount = recyclerView.getAdapter().getItemCount();
final int targetPos = getTheMinOne( itemCount - 1, (int) (proportion * (float) itemCount));
Object object = recyclerView.getLayoutManager();
if(object instanceof StaggeredGridLayoutManager){
((StaggeredGridLayoutManager) object).scrollToPositionWithOffset(targetPos, 0);
}else if(object instanceof GridLayoutManager){
((GridLayoutManager) object).scrollToPositionWithOffset(targetPos, 0);
}else if(object instanceof LinearLayoutManager){
((LinearLayoutManager) object).scrollToPositionWithOffset(targetPos, 0);
}
final String bubbleText = ((BubbleTextGetter) recyclerView.getAdapter()).getTextToShowInBubble(targetPos);
if (bubble != null) {
bubble.setText(bubbleText);
if (TextUtils.isEmpty(bubbleText)) {
hideBubble(); // TextUtils.isEmpty
} else if (bubble.getVisibility() == View.INVISIBLE) {
showBubble(); // ACTION_MOVE
}
}
}
/**
* 让 滚动条跟随 recyclerView 滚动
*/
private void updateBubbleAndHandlePosition() {
if (bubble == null || handle.isSelected()){
return;
}
final int verticalScrollOffset = recyclerView.computeVerticalScrollOffset();
final int verticalScrollRange = recyclerView.computeVerticalScrollRange();
float proportion = (float) verticalScrollOffset / ((float) verticalScrollRange - height);
setBubbleAndHandlePosition(height * proportion); // updateBubbleAndHandlePosition
}
//region 设置指示气泡 和图标 位置
private void setBubbleAndHandlePosition(float y) {
if(handle==null){
return;
}
final int handleHeight = handle.getHeight();
int max = height - handleHeight;
int value = (int) (y - handleHeight / 2);
float shouldY = getTheMinOne(max, value);
handle.setY(shouldY ); // handle
if(bubble==null){
return;
}
int bubbleHeight = bubble.getHeight();
bubble.setY(getTheMinOne( height - bubbleHeight - handleHeight / 2, (int) (y - bubbleHeight))); // bubble
}
// endregion
private int getTheMinOne(int max, int value) {
value= value>=0 ? value : 0 ;
return Math.min(value, max);
}
// region 动画
private void showBubble() {
if (bubble == null){
return;
}
bubble.setVisibility(VISIBLE);
if (currentAnimator != null){
currentAnimator.cancel();
}
currentAnimator = ObjectAnimator.ofFloat(bubble, "alpha", 0f, 1f).setDuration(BUBBLE_ANIMATION_DURATION);
currentAnimator.start();
}
private void hideBubble() {
WkLog.showLog("进入隐藏 hideBubble ");
if (bubble == null){
return;
}
if (currentAnimator != null){
currentAnimator.cancel();
}
currentAnimator = ObjectAnimator.ofFloat(bubble, "alpha", 1f, 0f).setDuration(BUBBLE_ANIMATION_DURATION);
currentAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
bubble.setVisibility(INVISIBLE);
currentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
bubble.setVisibility(INVISIBLE);
currentAnimator = null;
}
});
currentAnimator.start();
}
// endregion
// region 对外接口
public void setRecyclerView(final RecyclerView recyclerView) {
if(this.recyclerView == recyclerView){
return;
}
if (this.recyclerView != null){
this.recyclerView.removeOnScrollListener(onScrollListener);
}
this.recyclerView = recyclerView;
if (this.recyclerView == null){
return;
}
recyclerView.addOnScrollListener(onScrollListener);
}
public void setViewsToUse(@LayoutRes int layoutResId, @IdRes int bubbleResId, @IdRes int handleResId) {
final LayoutInflater inflater = LayoutInflater.from( getContext());
inflater.inflate( layoutResId, this, true);
bubble = findViewById(bubbleResId);
if (bubble != null){
bubble.setVisibility(INVISIBLE);
}
handle = findViewById(handleResId);
}
// endregion
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/Aivin_CodeShare/android_tool_code.git
git@gitee.com:Aivin_CodeShare/android_tool_code.git
Aivin_CodeShare
android_tool_code
android_tool_code
master

搜索帮助