1:修改群了会抽奖的动画

2:动画未完成
This commit is contained in:
2025-09-05 00:46:27 +08:00
parent c8adbbc590
commit cb3b7aa183
8 changed files with 828 additions and 30 deletions

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}