1:修改群了会抽奖的动画
2:动画未完成
This commit is contained in:
@@ -63,7 +63,7 @@ public class AppUpdateDialog extends BaseDialog<DialogAppUpdateBinding> implemen
|
||||
};
|
||||
mProgressDialog.setMax(100);//设置最大值
|
||||
mProgressDialog.setTitle("安装包下载");//设置标题
|
||||
mProgressDialog.setIcon(R.mipmap.ic_launcher);//设置标题小图标
|
||||
mProgressDialog.setIcon(R.mipmap.ic_launcher_app);//设置标题小图标
|
||||
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置样式为横向显示进度的样式
|
||||
mProgressDialog.incrementProgressBy(0);//设置初始值为0,其实可以不用设置,默认就是0
|
||||
mProgressDialog.setIndeterminate(false);//是否精确显示对话框,flase为是,反之为否
|
||||
|
||||
@@ -10,7 +10,7 @@ import lombok.Data;
|
||||
public class XlhDrawBean {
|
||||
private int gift_id;
|
||||
private String gift_name;
|
||||
private String gift_base_image;
|
||||
private String base_image;
|
||||
private String gift_price;
|
||||
private int count ;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class GiftItemAdapter extends BaseQuickAdapter<XlhDrawBean, BaseViewHolde
|
||||
protected void convert(BaseViewHolder helper, XlhDrawBean item) {
|
||||
|
||||
helper.setText(R.id.tv_gift_name, item.getGift_name()+"x"+item.getCount());
|
||||
ImageUtils.loadHeadCC(item.getGift_base_image(),helper.getView(R.id.gift_img));
|
||||
ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.gift_img));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,143 @@
|
||||
package com.xscm.moduleutil.dialog.giftLottery;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter;
|
||||
import com.chad.library.adapter.base.BaseViewHolder;
|
||||
import com.xscm.moduleutil.R;
|
||||
import com.xscm.moduleutil.bean.GiftBean;
|
||||
import com.xscm.moduleutil.utils.ImageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class GiftXlhChouAdapter extends BaseQuickAdapter<GiftBean, BaseViewHolder> {
|
||||
private List<GiftBean> giftLists = new ArrayList<>();
|
||||
private int selectedPosition = -1;
|
||||
private static final int LOOP_COUNT = 6; // 循环倍数
|
||||
|
||||
|
||||
public GiftXlhChouAdapter() {
|
||||
super(R.layout.item_xlh);
|
||||
}
|
||||
// 设置数据时创建循环数据
|
||||
@Override
|
||||
public void setNewData(List<GiftBean> data) {
|
||||
this.giftLists = data != null ? data : new ArrayList<>();
|
||||
super.setNewData(createLoopData());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建循环数据
|
||||
* @return 循环数据列表
|
||||
*/
|
||||
private List<GiftBean> createLoopData() {
|
||||
List<GiftBean> loopData = new ArrayList<>();
|
||||
if (giftLists.isEmpty()) {
|
||||
return loopData;
|
||||
}
|
||||
|
||||
// 创建足够多的循环数据以实现循环效果
|
||||
for (int i = 0; i < LOOP_COUNT; i++) {
|
||||
loopData.addAll(giftLists);
|
||||
}
|
||||
return loopData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
// 如果原始数据为空,返回0
|
||||
if (giftLists.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
// 返回循环数据的数量
|
||||
return super.getItemCount();
|
||||
}
|
||||
/**
|
||||
* 获取实际位置(将循环位置映射到原始数据位置)
|
||||
* @param position 循环列表中的位置
|
||||
* @return 原始数据中的实际位置
|
||||
*/
|
||||
private int getActualPosition(int position) {
|
||||
if (giftLists.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return position % giftLists.size();
|
||||
}
|
||||
@Override
|
||||
protected void convert(BaseViewHolder helper, GiftBean item) {
|
||||
helper.setText(R.id.tv_gift_name, item.getGift_name());
|
||||
helper.setText(R.id.tv_gift_pic, item.getGift_price());
|
||||
ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_image));
|
||||
// 获取实际位置
|
||||
int actualPosition = getActualPosition(helper.getAdapterPosition());
|
||||
GiftBean actualItem = giftLists.get(actualPosition);
|
||||
|
||||
helper.setText(R.id.tv_gift_name, actualItem.getGift_name());
|
||||
helper.setText(R.id.tv_gift_pic, actualItem.getGift_price());
|
||||
ImageUtils.loadHeadCC(actualItem.getBase_image(), helper.getView(R.id.iv_gift_image));
|
||||
// 处理选中状态
|
||||
View selectedIcon = helper.getView(R.id.selected_icon);
|
||||
// 处理选中状态
|
||||
if (selectedIcon != null) {
|
||||
// 检查当前item是否为选中位置
|
||||
if (actualPosition == selectedPosition) {
|
||||
selectedIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
selectedIcon.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置选中位置并更新UI
|
||||
* @param position 选中的位置
|
||||
*/
|
||||
public void setSelectedPosition(int position) {
|
||||
int previousPosition = selectedPosition;
|
||||
selectedPosition = position;
|
||||
|
||||
if (previousPosition >= 0) {
|
||||
notifyItemsByActualPosition(previousPosition, false);
|
||||
}
|
||||
|
||||
if (selectedPosition >= 0) {
|
||||
notifyItemsByActualPosition(selectedPosition, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 根据实际位置通知所有匹配的item更新
|
||||
* @param actualPosition 原始数据中的位置
|
||||
* @param isSelected 是否选中
|
||||
*/
|
||||
private void notifyItemsByActualPosition(int actualPosition, boolean isSelected) {
|
||||
if (giftLists.isEmpty() || actualPosition >= giftLists.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 通知所有匹配该实际位置的item更新
|
||||
for (int i = 0; i < getItemCount(); i++) {
|
||||
if (getActualPosition(i) == actualPosition) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 清除选中状态
|
||||
*/
|
||||
public void clearSelection() {
|
||||
int previousPosition = selectedPosition;
|
||||
selectedPosition = -1;
|
||||
|
||||
if (previousPosition >= 0) {
|
||||
notifyItemsByActualPosition(previousPosition, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始数据大小
|
||||
* @return 原始数据大小
|
||||
*/
|
||||
public int getOriginalDataSize() {
|
||||
return giftLists.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearSnapHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.blankj.utilcode.util.TimeUtils;
|
||||
import com.xscm.moduleutil.R;
|
||||
@@ -26,6 +28,8 @@ import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean;
|
||||
import com.xscm.moduleutil.databinding.FragmentTourClubDialogBinding;
|
||||
import com.xscm.moduleutil.dialog.WebViewDialog;
|
||||
import com.xscm.moduleutil.utils.ImageUtils;
|
||||
import com.xscm.moduleutil.widget.CenterScrollHelper;
|
||||
import com.xscm.moduleutil.widget.EqualSpaceItemDecoration;
|
||||
import com.xscm.moduleutil.widget.InfintLinearLayoutManager;
|
||||
import com.xscm.moduleutil.widget.pagerecyclerview.PagerGridSnapHelper;
|
||||
|
||||
@@ -47,6 +51,10 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment<GiftLotteryPre
|
||||
private XlhRecordDialog xlhRecordDialog;
|
||||
|
||||
private GiftXlhChouAdapter giftXlhChouAdapter;
|
||||
private CenterScrollHelper scrollHelper;
|
||||
|
||||
private static final int ITEM_COUNT = 24;
|
||||
private static final int ROTATION_COUNT = 3;
|
||||
|
||||
@Override
|
||||
protected GiftLotteryPresenter bindPresenter() {
|
||||
@@ -121,14 +129,31 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment<GiftLotteryPre
|
||||
mBinding.tvJl.setOnClickListener(this::onClick);
|
||||
|
||||
giftXlhChouAdapter=new GiftXlhChouAdapter();
|
||||
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 3);
|
||||
|
||||
mBinding.recycleView.setLayoutManager(new InfintLinearLayoutManager(mBinding.recycleView));
|
||||
// 使用 LinearLayoutManager 横向滚动
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
|
||||
mBinding.recycleView.setLayoutManager(layoutManager);
|
||||
mBinding.recycleView.setOnFlingListener(null);
|
||||
|
||||
// 设置滚动辅助工具
|
||||
PagerGridSnapHelper pageSnapHelper = new PagerGridSnapHelper();
|
||||
pageSnapHelper.attachToRecyclerView(mBinding.recycleView);
|
||||
LinearSnapHelper snapHelper = new LinearSnapHelper();
|
||||
snapHelper.attachToRecyclerView(mBinding.recycleView);
|
||||
|
||||
// 添加 ItemDecoration 实现等宽分布
|
||||
int spacing = getResources().getDimensionPixelSize(R.dimen.dp_15); // 根据需要调整间距
|
||||
mBinding.recycleView.addItemDecoration(new EqualSpaceItemDecoration(3, spacing));
|
||||
|
||||
mBinding.recycleView.setAdapter(giftXlhChouAdapter);
|
||||
// 初始化滚动帮助类
|
||||
scrollHelper = new CenterScrollHelper(mBinding.recycleView);
|
||||
|
||||
// 初始化时滚动到中间位置,确保有足够的前后数据
|
||||
mBinding.recycleView.post(() -> {
|
||||
if (giftXlhChouAdapter.getOriginalDataSize() > 0) {
|
||||
int middlePosition = giftXlhChouAdapter.getItemCount() / 2;
|
||||
mBinding.recycleView.scrollToPosition(middlePosition);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -190,6 +215,8 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment<GiftLotteryPre
|
||||
getRule_url=blindBoxBean.getRule_url();
|
||||
upTitle(blindBoxBean.getBox_price());
|
||||
giftLists = blindBoxBean.getGift_list();
|
||||
// 初始滚动到中间位置,避免边界问题
|
||||
// mBinding.recycleView.scrollToPosition(Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2) % giftLists.size());
|
||||
|
||||
// 获取结束时间并启动倒计时
|
||||
if (blindBoxBean.getXlh_end_time() != null && !blindBoxBean.getXlh_end_time().isEmpty()) {
|
||||
@@ -228,7 +255,7 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment<GiftLotteryPre
|
||||
private void upTitle(int boxPrice){
|
||||
mBinding.tvOne.setText(boxPrice+"币一次");
|
||||
mBinding.tvTen.setText((boxPrice*10)+"币十次");
|
||||
mBinding.tvHundred.setText((boxPrice*100)+"币十次");
|
||||
mBinding.tvHundred.setText((boxPrice*100)+"币百次");
|
||||
}
|
||||
|
||||
// TODO: 2025/8/29 接收im推送过来的消息
|
||||
@@ -357,27 +384,367 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment<GiftLotteryPre
|
||||
@Override
|
||||
public void xlhChouSuccess(List<XlhDrawBean> data) {
|
||||
if (data != null){
|
||||
// 创建并显示对话框
|
||||
XlhObtainDialog dialog = new XlhObtainDialog(getActivity());
|
||||
dialog.setOnGiftItemClickListener(new XlhObtainDialog.OnGiftItemClickListener() {
|
||||
// 抽奖完成后执行动画滚动
|
||||
mBinding.recycleView.postDelayed(() -> {
|
||||
int winningPosition = findHighestValueWinningPosition(data);
|
||||
if (winningPosition != -1) {
|
||||
|
||||
@Override
|
||||
public void onPlayAgainClick() {
|
||||
// 处理再玩一次点击事件
|
||||
MvpPre.xlhChou(roomId,num);
|
||||
startLotteryAnimation(winningPosition);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
// 计算在循环列表中的目标位置(滚动几圈后停在目标位置)
|
||||
int loopCount = 4; // 滚动3圈
|
||||
int originalSize = giftXlhChouAdapter.getOriginalDataSize();
|
||||
// 计算目标在循环列表中的位置(确保在中间区域)
|
||||
|
||||
int middleBaseIndex = (loopCount * originalSize) + (originalSize / 2);
|
||||
int targetLoopIndex = middleBaseIndex + (winningPosition % originalSize);
|
||||
|
||||
// 使用scrollWithCircles方法执行带动画的滚动(带完成回调)
|
||||
scrollHelper.scrollWithCircles(
|
||||
targetLoopIndex, // 在循环列表中的位置
|
||||
loopCount, // 滚动圈数
|
||||
500, // 每个item滚动时间200ms(控制速度)
|
||||
originalSize, // 原始数据大小
|
||||
() -> { // 滚动完成回调
|
||||
// 滚动完成后更新选中状态(使用原始位置)
|
||||
if (giftXlhChouAdapter != null) {
|
||||
giftXlhChouAdapter.setSelectedPosition(winningPosition);
|
||||
}
|
||||
// 滚动完成后延迟一小段时间再居中,确保UI更新完成
|
||||
mBinding.recycleView.postDelayed(() -> {
|
||||
// 手动将选中项居中
|
||||
centerSelectedItem(winningPosition, originalSize);
|
||||
|
||||
// 显示结果对话框
|
||||
getActivity().runOnUiThread(() -> {
|
||||
showResultDialog(data);
|
||||
});
|
||||
}, 100);
|
||||
// 在滚动完成后再显示对话框
|
||||
// getActivity().runOnUiThread(() -> {
|
||||
// showResultDialog(data);
|
||||
// });
|
||||
}
|
||||
);
|
||||
*/
|
||||
} else {
|
||||
// 如果没有找到中奖位置,直接显示对话框
|
||||
showResultDialog(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseClick() {
|
||||
// 处理关闭点击事件
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
dialog.setGiftList(data);
|
||||
|
||||
}, 300);
|
||||
}
|
||||
MvpPre.wallet();
|
||||
}
|
||||
|
||||
private void startLotteryAnimation(int targetIndex) {
|
||||
// 确保适配器有数据
|
||||
if (giftXlhChouAdapter == null || giftXlhChouAdapter.getOriginalDataSize() <= 0) {
|
||||
showResultDialogWithoutAnimation(targetIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager();
|
||||
if (layoutManager == null) {
|
||||
showResultDialogWithoutAnimation(targetIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前第一个可见的item位置
|
||||
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
|
||||
if (firstVisiblePosition == RecyclerView.NO_POSITION) {
|
||||
firstVisiblePosition = 0;
|
||||
}
|
||||
|
||||
// 获取当前在原始数据中的实际位置
|
||||
int currentActualPosition = firstVisiblePosition % giftXlhChouAdapter.getOriginalDataSize();
|
||||
|
||||
// 计算需要滚动的总item数
|
||||
// 滚动指定圈数 + 从当前位置到目标位置的距离
|
||||
int itemsToScroll = ROTATION_COUNT * giftXlhChouAdapter.getOriginalDataSize()
|
||||
+ (targetIndex - currentActualPosition + giftXlhChouAdapter.getOriginalDataSize())
|
||||
% giftXlhChouAdapter.getOriginalDataSize();
|
||||
|
||||
// 计算目标位置
|
||||
int targetPosition = firstVisiblePosition + itemsToScroll;
|
||||
|
||||
// 确保目标位置在合理范围内
|
||||
int maxPosition = giftXlhChouAdapter.getItemCount() - 1;
|
||||
if (targetPosition > maxPosition) {
|
||||
targetPosition = maxPosition;
|
||||
}
|
||||
|
||||
// 确保目标位置有效
|
||||
if (targetPosition >= 0) {
|
||||
try {
|
||||
SmoothScroller smoothScroller = new SmoothScroller(getActivity(), targetPosition);
|
||||
layoutManager.startSmoothScroll(smoothScroller);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 如果仍然出现异常,使用备选方案
|
||||
showResultDialogWithoutAnimation(targetIndex);
|
||||
}
|
||||
} else {
|
||||
showResultDialogWithoutAnimation(targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void showResultDialogWithoutAnimation(int targetIndex) {
|
||||
// 直接设置选中状态
|
||||
if (giftXlhChouAdapter != null) {
|
||||
giftXlhChouAdapter.setSelectedPosition(targetIndex);
|
||||
}
|
||||
|
||||
// 延迟显示结果对话框
|
||||
mBinding.recycleView.postDelayed(() -> {
|
||||
// 创建假的XlhDrawBean数据用于显示结果
|
||||
List<XlhDrawBean> fakeData = new ArrayList<>();
|
||||
// 这里根据需要构造假数据
|
||||
showResultDialog(fakeData);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
private class SmoothScroller extends androidx.recyclerview.widget.LinearSmoothScroller {
|
||||
|
||||
private int targetPosition;
|
||||
|
||||
public SmoothScroller(android.content.Context context, int targetPosition) {
|
||||
super(context);
|
||||
this.targetPosition = targetPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateTimeForScrolling(int dx) {
|
||||
// 自定义滚动时间,实现速度变化
|
||||
float distance = Math.abs(dx);
|
||||
float speed = 1f;
|
||||
if (distance < 100) {
|
||||
speed = 0.3f; // 慢
|
||||
} else if (distance < 300) {
|
||||
speed = 1f; // 快
|
||||
} else {
|
||||
speed = 0.3f; // 慢
|
||||
}
|
||||
return (int) (distance / speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
|
||||
// 将目标项移动到屏幕中心
|
||||
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetPosition() {
|
||||
// 添加更严格的边界检查
|
||||
if (giftXlhChouAdapter != null && targetPosition >= 0 && targetPosition < giftXlhChouAdapter.getItemCount()) {
|
||||
return targetPosition;
|
||||
}
|
||||
// 如果超出范围,返回一个安全的位置
|
||||
if (giftXlhChouAdapter != null && giftXlhChouAdapter.getItemCount() > 0) {
|
||||
return Math.max(0, Math.min(targetPosition, giftXlhChouAdapter.getItemCount() - 1));
|
||||
}
|
||||
return 0; // 返回默认位置
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将指定的原始位置item居中显示
|
||||
* @param originalPosition 原始数据中的位置
|
||||
* @param originalSize 原始数据大小
|
||||
*/
|
||||
private void centerSelectedItem(int originalPosition, int originalSize) {
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager();
|
||||
if (layoutManager == null) return;
|
||||
|
||||
// 计算出需要滚动到的目标位置
|
||||
int targetPosition = originalPosition + 4 * originalSize;
|
||||
|
||||
// 使用smoothScrollToPosition滚动到目标位置
|
||||
mBinding.recycleView.smoothScrollToPosition(targetPosition);
|
||||
|
||||
// 等待滚动完成
|
||||
mBinding.recycleView.postDelayed(() -> {
|
||||
// 计算出选中项的偏移量,确保它在中间
|
||||
View view = layoutManager.findViewByPosition(targetPosition);
|
||||
if (view == null) return;
|
||||
|
||||
// 计算出RecyclerView的宽度和View的宽度
|
||||
int recyclerViewWidth = mBinding.recycleView.getWidth();
|
||||
int viewWidth = view.getWidth();
|
||||
|
||||
// 计算偏移量,确保view居中
|
||||
int offsetToCenter = (recyclerViewWidth / 2) - (viewWidth / 2) - view.getLeft();
|
||||
|
||||
// 调整滚动的位置
|
||||
mBinding.recycleView.scrollBy(offsetToCenter, 0);
|
||||
}, 500); // 500毫秒的延迟,根据实际情况调整
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接滚动到指定位置并居中
|
||||
* @param targetPosition 目标位置
|
||||
*/
|
||||
private void directScrollToCenter(int targetPosition) {
|
||||
if (mBinding.recycleView.getLayoutManager() == null) return;
|
||||
|
||||
mBinding.recycleView.post(() -> {
|
||||
int screenWidth = mBinding.recycleView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
// 计算item宽度
|
||||
int itemWidth = screenWidth / 3;
|
||||
|
||||
// 计算目标位置的左边缘
|
||||
int targetLeft = targetPosition * itemWidth;
|
||||
|
||||
// 计算使item居中需要滚动到的位置
|
||||
int targetScrollX = targetLeft - (screenWidth - itemWidth) / 2;
|
||||
|
||||
// 直接滚动到目标位置
|
||||
mBinding.recycleView.scrollBy(
|
||||
targetScrollX - mBinding.recycleView.computeHorizontalScrollOffset(),
|
||||
0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 滚动到指定位置并使该位置的item居中显示
|
||||
* @param selectedPosition 选中的原始位置
|
||||
*/
|
||||
private void scrollToCenterWithSelected(int selectedPosition) {
|
||||
if (mBinding.recycleView.getLayoutManager() == null) return;
|
||||
|
||||
int screenWidth = mBinding.recycleView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
// 计算item宽度
|
||||
int itemWidth = screenWidth / 3;
|
||||
|
||||
// 计算要滚动到的中心位置(使selectedPosition的item居中)
|
||||
int middlePositionInLoop = (giftXlhChouAdapter.getItemCount() / 2 / giftXlhChouAdapter.getOriginalDataSize())
|
||||
* giftXlhChouAdapter.getOriginalDataSize() + selectedPosition;
|
||||
|
||||
// 滚动到目标位置
|
||||
mBinding.recycleView.smoothScrollToPosition(middlePositionInLoop);
|
||||
|
||||
// 额外确保居中
|
||||
mBinding.recycleView.postDelayed(() -> {
|
||||
if (scrollHelper != null) {
|
||||
scrollHelper.scrollToCenter(middlePositionInLoop);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示抽奖结果对话框
|
||||
* @param data 中奖数据
|
||||
*/
|
||||
private void showResultDialog(List<XlhDrawBean> data) {
|
||||
// 创建并显示对话框
|
||||
XlhObtainDialog dialog = new XlhObtainDialog(getActivity());
|
||||
dialog.setOnGiftItemClickListener(new XlhObtainDialog.OnGiftItemClickListener() {
|
||||
|
||||
@Override
|
||||
public void onPlayAgainClick() {
|
||||
// 处理再玩一次点击事件
|
||||
MvpPre.xlhChou(roomId, num);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseClick() {
|
||||
// 处理关闭点击事件
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
dialog.setGiftList(data);
|
||||
}
|
||||
/**
|
||||
* 根据中奖结果找到最高价值奖品在giftLists中的位置
|
||||
* @param data 中奖结果列表
|
||||
* @return 最高价值奖品在giftLists中的下标,如果没有找到则返回-1
|
||||
*/
|
||||
private int findHighestValueWinningPosition(List<XlhDrawBean> data) {
|
||||
if (data == null || data.isEmpty() || giftLists == null || giftLists.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int targetPosition = -1;
|
||||
int highestPrice = -1;
|
||||
|
||||
// 遍历giftLists查找中奖项目
|
||||
for (int i = 0; i < giftLists.size(); i++) {
|
||||
GiftBean giftBean = giftLists.get(i);
|
||||
|
||||
// 在中奖数据中查找匹配的礼品
|
||||
for (XlhDrawBean xlhDrawBean : data) {
|
||||
// 比较gift_id是否匹配
|
||||
if (giftBean.getGift_id().equals(String.valueOf(xlhDrawBean.getGift_id()))) {
|
||||
// 解析价格,处理可能的NumberFormatException
|
||||
try {
|
||||
int currentPrice = Integer.parseInt(giftBean.getGift_price());
|
||||
// 如果当前价格更高,则更新目标位置和最高价格
|
||||
if (currentPrice > highestPrice) {
|
||||
highestPrice = currentPrice;
|
||||
targetPosition = i;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// 如果价格解析失败,使用默认值0进行比较
|
||||
if (highestPrice <= 0) {
|
||||
highestPrice = 0;
|
||||
targetPosition = i;
|
||||
}
|
||||
}
|
||||
break; // 找到匹配项后跳出内层循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确将指定位置的item滚动到中心
|
||||
* @param position 目标位置
|
||||
*/
|
||||
private void preciseScrollToCenter(int position) {
|
||||
if (mBinding.recycleView.getLayoutManager() == null) return;
|
||||
|
||||
int screenWidth = mBinding.recycleView.getWidth();
|
||||
if (screenWidth <= 0) return;
|
||||
|
||||
// 计算item宽度
|
||||
int itemWidth = screenWidth / 3;
|
||||
|
||||
// 计算屏幕中心位置
|
||||
int screenCenter = screenWidth / 2;
|
||||
|
||||
// 计算目标item的中心位置(在当前可见区域中)
|
||||
int targetItemCenter = (mBinding.recycleView.computeHorizontalScrollOffset() / itemWidth) * itemWidth
|
||||
+ position * itemWidth + itemWidth / 2;
|
||||
|
||||
// 计算需要滚动的距离使目标item居中
|
||||
int scrollDistance = targetItemCenter - screenCenter;
|
||||
|
||||
// 获取当前滚动位置
|
||||
int currentScrollX = mBinding.recycleView.computeHorizontalScrollOffset();
|
||||
|
||||
// 执行滚动使选中项居中
|
||||
mBinding.recycleView.smoothScrollBy(scrollDistance - currentScrollX, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,6 +279,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="@dimen/dp_15"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cl_gift"
|
||||
app:layout_constraintBottom_toTopOf="@+id/exchange_layout"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user