1:修改群了会抽奖的动画
2:动画未完成
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
package com.xscm.moduleutil.widget;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @Author lxj$
|
||||
* @Time $ 2025-9-4 21:04:34$
|
||||
* @Description 自定义滚动辅助类$
|
||||
*/
|
||||
public class CenterScrollHelper {
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
public CenterScrollHelper(RecyclerView recyclerView) {
|
||||
this.recyclerView = recyclerView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环滚动指定圈数后停在目标位置
|
||||
* @param targetPosition 目标位置
|
||||
* @param circles 滚动圈数
|
||||
* @param durationPerItem 每个item滚动的持续时间(控制速度)
|
||||
* @param adapterSize 适配器总大小
|
||||
*/
|
||||
public void scrollWithCircles(int targetPosition, int circles, int durationPerItem, int adapterSize) {
|
||||
scrollWithCircles(targetPosition, circles, durationPerItem, adapterSize, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环滚动指定圈数后停在目标位置(带回调)
|
||||
* @param targetPosition 目标位置
|
||||
* @param circles 滚动圈数
|
||||
* @param durationPerItem 每个item滚动的持续时间(控制速度)
|
||||
* @param adapterSize 适配器总大小
|
||||
* @param onComplete 滚动完成回调
|
||||
*/
|
||||
public void scrollWithCircles(int targetPosition, int circles, int durationPerItem,
|
||||
int adapterSize, Runnable onComplete) {
|
||||
if (recyclerView.getLayoutManager() == null) {
|
||||
if (onComplete != null) onComplete.run();
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算总滚动位置(多圈+目标位置)
|
||||
int totalItems = circles * adapterSize + targetPosition;
|
||||
|
||||
|
||||
// 使用LinearSmoothScroller进行平滑滚动
|
||||
LinearSmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
|
||||
@Override
|
||||
protected int calculateTimeForScrolling(int dx) {
|
||||
// 使用缓动函数计算时间,实现从慢到快再到慢的效果
|
||||
// return calculateEasingTime(dx, durationPerItem);
|
||||
|
||||
// 简单线性时间计算,确保滚动速度一致
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) {
|
||||
return durationPerItem * 3;
|
||||
}
|
||||
int itemWidth = screenWidth / 3;
|
||||
int items = Math.max(1, dx / itemWidth);
|
||||
return durationPerItem * items;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
// 滚动停止后确保目标位置居中
|
||||
// scrollToCenter(targetPosition);
|
||||
// 执行完成回调
|
||||
if (onComplete != null) {
|
||||
recyclerView.post(onComplete);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
smoothScroller.setTargetPosition(totalItems);
|
||||
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
|
||||
}
|
||||
/**
|
||||
* 使用缓动函数计算滚动时间,实现加速减速效果
|
||||
* @param dx 滚动距离
|
||||
* @param baseDurationPerItem 基础时间
|
||||
* @return 计算后的时间
|
||||
*/
|
||||
private int calculateEasingTime(int dx, int baseDurationPerItem) {
|
||||
if (dx <= 0) return 0;
|
||||
|
||||
// 获取屏幕宽度作为参考
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) {
|
||||
return baseDurationPerItem * 3; // 默认值
|
||||
}
|
||||
|
||||
// 计算item宽度(假设每屏3个item)
|
||||
int itemWidth = screenWidth / 3;
|
||||
// 计算滚动的item数量
|
||||
int items = Math.max(1, dx / itemWidth);
|
||||
|
||||
// 使用easeInOutQuad缓动函数实现先慢中快后慢的效果
|
||||
double progress = Math.min(1.0, (double) items / 100); // 假设100个item为完整过程
|
||||
|
||||
// easeInOutQuad缓动函数
|
||||
double easeProgress;
|
||||
if (progress < 0.5) {
|
||||
easeProgress = 2 * progress * progress; // 先慢后快
|
||||
} else {
|
||||
easeProgress = 1 - Math.pow(-2 * progress + 2, 2) / 2; // 后慢
|
||||
}
|
||||
|
||||
// 计算时间:开始慢(500ms),后来快(50ms)
|
||||
int minDuration = 50; // 最快速度
|
||||
int maxDuration = 500; // 最慢速度
|
||||
int calculatedTime = (int) (maxDuration - (maxDuration - minDuration) * easeProgress);
|
||||
|
||||
return Math.max(minDuration, calculatedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定位置的item精确居中显示
|
||||
* @param position 需要居中的位置(在循环列表中的实际位置)
|
||||
* @param originalSize 原始数据大小
|
||||
*/
|
||||
public void scrollToCenter(int position, int originalSize) {
|
||||
if (recyclerView.getLayoutManager() == null) return;
|
||||
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
// 计算item宽度(假设每个item等宽)
|
||||
int itemWidth = screenWidth / 3; // 每屏显示3个item
|
||||
|
||||
// 计算使item居中需要滚动的总距离
|
||||
int targetScrollX = position * itemWidth - (screenWidth - itemWidth) / 2;
|
||||
|
||||
// 获取当前滚动位置
|
||||
int currentScrollX = recyclerView.computeHorizontalScrollOffset();
|
||||
|
||||
// 计算需要滚动的距离
|
||||
int scrollDistance = targetScrollX - currentScrollX;
|
||||
|
||||
// 执行滚动
|
||||
recyclerView.smoothScrollBy(scrollDistance, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定位置的item精确居中显示(简化版)
|
||||
* @param position 需要居中的位置
|
||||
*/
|
||||
public void scrollToCenter(int position) {
|
||||
if (recyclerView.getLayoutManager() == null) return;
|
||||
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
// 计算item宽度
|
||||
int itemWidth = screenWidth / 3;
|
||||
|
||||
// 计算目标位置的左边缘
|
||||
int targetLeft = position * itemWidth;
|
||||
|
||||
// 计算使item居中需要滚动到的位置
|
||||
int targetScrollX = targetLeft - (screenWidth - itemWidth) / 2;
|
||||
|
||||
// 获取当前滚动位置
|
||||
int currentScrollX = recyclerView.computeHorizontalScrollOffset();
|
||||
|
||||
// 计算需要滚动的距离
|
||||
int scrollDistance = targetScrollX - currentScrollX;
|
||||
|
||||
// 如果距离很小,就不需要滚动了
|
||||
if (Math.abs(scrollDistance) > 5) {
|
||||
// 执行滚动
|
||||
recyclerView.smoothScrollBy(scrollDistance, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 将指定位置的item居中显示(支持循环)
|
||||
*/
|
||||
public void centerItem(int targetPosition, int adapterSize) {
|
||||
if (recyclerView.getLayoutManager() == null) return;
|
||||
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
int itemWidth = screenWidth / 3; // 每个item占屏幕1/3
|
||||
|
||||
// 计算需要滚动的距离使item居中
|
||||
// 这里需要根据实际的item宽度和屏幕宽度来计算居中位置
|
||||
int targetScrollX = targetPosition * itemWidth - (screenWidth - itemWidth) / 2;
|
||||
int currentScrollX = recyclerView.computeHorizontalScrollOffset();
|
||||
int scrollDistance = targetScrollX - currentScrollX;
|
||||
|
||||
// 使用smoothScrollBy确保平滑滚动到居中位置
|
||||
recyclerView.smoothScrollBy(scrollDistance, 0);
|
||||
}
|
||||
/**
|
||||
* 使用更复杂的缓动函数计算滚动时间
|
||||
* @param dx 滚动距离
|
||||
* @param baseDurationPerItem 基础时间
|
||||
* @return 计算后的时间
|
||||
*/
|
||||
private int calculateAdvancedEasingTime(int dx, int baseDurationPerItem) {
|
||||
if (dx <= 0) return 0;
|
||||
|
||||
int screenWidth = recyclerView.getWidth();
|
||||
if (screenWidth <= 0) {
|
||||
return baseDurationPerItem * 3;
|
||||
}
|
||||
|
||||
int itemWidth = screenWidth / 3;
|
||||
int totalItems = dx / itemWidth;
|
||||
|
||||
// 分段处理:开始慢,中间快,结束慢
|
||||
int totalTime = 0;
|
||||
for (int i = 0; i < totalItems; i++) {
|
||||
// 计算当前位置的进度 (0-1)
|
||||
double progress = (double) i / Math.max(1, totalItems);
|
||||
|
||||
// 使用贝塞尔缓动函数:慢-快-慢
|
||||
double easedProgress = bezierEasing(progress, 0.25, 0.1, 0.25, 1.0);
|
||||
|
||||
// 根据进度调整时间
|
||||
int minTime = 30; // 最快时间
|
||||
int maxTime = baseDurationPerItem * 2; // 最慢时间
|
||||
int itemTime = (int) (maxTime - (maxTime - minTime) * easedProgress);
|
||||
|
||||
totalTime += itemTime;
|
||||
}
|
||||
|
||||
return Math.max(100, totalTime); // 至少100ms
|
||||
}
|
||||
|
||||
/**
|
||||
* 贝塞尔缓动函数
|
||||
* @param t 时间进度 (0-1)
|
||||
* @param x1 控制点1 x
|
||||
* @param y1 控制点1 y
|
||||
* @param x2 控制点2 x
|
||||
* @param y2 控制点2 y
|
||||
* @return 缓动后的值
|
||||
*/
|
||||
private double bezierEasing(double t, double x1, double y1, double x2, double y2) {
|
||||
// 简化的贝塞尔曲线计算
|
||||
// 这里使用一个近似算法
|
||||
double a = 1 - t;
|
||||
return 3 * a * a * t * y1 + 3 * a * t * t * y2 + t * t * t;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.xscm.moduleutil.widget;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @Author lxj$
|
||||
* @Time $ 2025-9-4 20:32:52$
|
||||
* @Description 自定义的,让在item平分屏幕宽度$
|
||||
*/
|
||||
public class EqualSpaceItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private int spanCount;
|
||||
private int spacing;
|
||||
|
||||
public EqualSpaceItemDecoration(int spanCount, int spacing) {
|
||||
this.spanCount = spanCount;
|
||||
this.spacing = spacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
|
||||
// 设置间距
|
||||
outRect.left = spacing / 2;
|
||||
outRect.right = spacing / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
super.onDraw(c, parent, state);
|
||||
|
||||
// 确保每个item宽度为屏幕的1/3
|
||||
int childCount = parent.getChildCount();
|
||||
int screenWidth = parent.getWidth();
|
||||
int itemWidth = screenWidth / spanCount;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
ViewGroup.LayoutParams params = child.getLayoutParams();
|
||||
params.width = itemWidth;
|
||||
child.setLayoutParams(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user