package com.xscm.modulemain.dialog; import android.app.Dialog; import android.content.Context; import android.graphics.Typeface; import android.os.Bundle; import android.os.CountDownTimer; import android.os.Handler; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.Window; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSnapHelper; import androidx.recyclerview.widget.RecyclerView; import com.blankj.utilcode.util.GsonUtils; import com.xscm.moduleutil.R; import com.xscm.moduleutil.base.BaseMvpDialogFragment; import com.xscm.moduleutil.bean.GiftBean; import com.xscm.moduleutil.bean.MqttXlhEnd; import com.xscm.moduleutil.bean.RoomMessageEvent; import com.xscm.moduleutil.bean.WalletBean; import com.xscm.moduleutil.bean.XLHBean; import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; import com.xscm.moduleutil.databinding.FragmentTourClubDialogBinding; import com.xscm.moduleutil.dialog.RechargeDialogFragment; import com.xscm.moduleutil.dialog.giftLottery.GiftLotteryContacts; import com.xscm.moduleutil.dialog.giftLottery.GiftLotteryPresenter; import com.xscm.moduleutil.dialog.giftLottery.GiftXlhChouAdapter; import com.xscm.moduleutil.dialog.giftLottery.NewXlhRankingDialog; import com.xscm.moduleutil.dialog.giftLottery.PrizePoolDialog; import com.xscm.moduleutil.dialog.giftLottery.XlhObtainDialog; import com.xscm.moduleutil.dialog.giftLottery.XlhRecordDialog; import com.xscm.moduleutil.widget.CenterScrollHelper; import com.xscm.moduleutil.widget.EqualSpaceItemDecoration; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.List; /** * @author qx * @data 2025/9/15 * @description: 玄镜之旅 */ public class TourClubDialogFragment extends BaseMvpDialogFragment implements GiftLotteryContacts.View { private String roomId; private List giftLists = new ArrayList<>(); private String getRule_url; private CountDownTimer mCountDownTimer; private long endTime; // 服务器返回的结束时间戳 private String num; private NewXlhRankingDialog newXlhRankingDialog; private XlhRecordDialog xlhRecordDialog; private XlhObtainDialog xlhObtainDialog; private GiftXlhChouAdapter giftXlhChouAdapter; private CenterScrollHelper scrollHelper; private static final int ITEM_COUNT = 24; private static final int ROTATION_COUNT = 3; private Handler handler = new Handler(); private boolean isLotteryRunning = false; private int scrollSpeed = 10; // 滚动速度 private int totalScrollTime = 5000; // 总滚动时间,单位:毫秒 private int targetPosition; private boolean isDrawing;//是否正在抽奖 // 添加自动滚动相关的成员变量 private Handler autoScrollHandler = new Handler(); private Runnable autoScrollRunnable; private boolean isAutoScrolling = false; private static final int AUTO_SCROLL_DELAY = 1000; // 1秒滚动一个item private boolean vCheckbox=false; @Override protected GiftLotteryPresenter bindPresenter() { return new GiftLotteryPresenter(this, getActivity()); } public static TourClubDialogFragment newInstance(String roomId) { TourClubDialogFragment dialog = new TourClubDialogFragment(); Bundle args = new Bundle(); args.putString("roomId", roomId); dialog.setArguments(args); return dialog; } @Nullable @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setCancelable(true); return dialog; } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); roomId = getArguments().getString("roomId"); } @Override protected void initData() { MvpPre.xlh(roomId); MvpPre.wallet(); } @Override protected void initDialogStyle(Window window) { super.initDialogStyle(window); window.setGravity(Gravity.BOTTOM); } @Override public void onStart() { super.onStart(); Window window = getDialog().getWindow(); if (window != null) { // 获取屏幕高度 android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int screenHeight = displayMetrics.heightPixels; // 设置高度为屏幕高度的100%(全屏) int heightInPx = (int) (screenHeight * 0.85); window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); window.setBackgroundDrawableResource(android.R.color.transparent); // 可选:设置动画样式(从底部弹出) window.setWindowAnimations(R.style.CommonShowDialogBottom); } } @Override protected void initView() { mBinding.tvJc.setOnClickListener(this::onClick); mBinding.llOne.setOnClickListener(this::onClick); mBinding.llTen.setOnClickListener(this::onClick); mBinding.llHundred.setOnClickListener(this::onClick); mBinding.tvGz.setOnClickListener(this::onClick); mBinding.tvBd.setOnClickListener(this::onClick); mBinding.tvJl.setOnClickListener(this::onClick); mBinding.exchangeLayout.setOnClickListener(this::onClick); mBinding.vCheckbox.setOnClickListener(this::onClick); giftXlhChouAdapter = new GiftXlhChouAdapter(); // 使用 LinearLayoutManager 横向滚动 LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false); mBinding.recycleView.setLayoutManager(layoutManager); mBinding.recycleView.setOnFlingListener(null); // 设置滚动辅助工具 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); } }); mBinding.tvNumber.setText("x0"); mBinding.tvNumber.setTypeface(android.graphics.Typeface.create("semibold", Typeface.NORMAL)); } // 添加自动滚动相关的方法 private void startAutoScroll() { // 如果已经在自动滚动或数据为空,则不启动 if (isAutoScrolling || giftLists == null || giftLists.isEmpty()) { return; } isAutoScrolling = true; autoScrollRunnable = new Runnable() { @Override public void run() { if (isAutoScrolling && mBinding != null && mBinding.recycleView != null) { // 获取当前显示的第一个可见item位置 LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager(); if (layoutManager != null) { int currentPosition = layoutManager.findFirstVisibleItemPosition(); // 如果没有完全可见的item,使用第一个可见item if (currentPosition == RecyclerView.NO_POSITION) { currentPosition = layoutManager.findFirstVisibleItemPosition(); } // 如果还是没有有效的position,从0开始 if (currentPosition == RecyclerView.NO_POSITION) { currentPosition = 0; } // 计算下一个位置 int nextPosition = currentPosition + 1; // 如果到达末尾,回到开始位置 if (nextPosition >= giftXlhChouAdapter.getItemCount()) { nextPosition = 0; } // 平滑滚动到下一个位置 mBinding.recycleView.smoothScrollToPosition(nextPosition); } // 1秒后继续滚动 autoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY); } } }; // 开始自动滚动 autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_DELAY); } private void stopAutoScroll() { isAutoScrolling = false; if (autoScrollRunnable != null) { autoScrollHandler.removeCallbacks(autoScrollRunnable); autoScrollRunnable = null; } } // 在抽奖结束后重新启动自动滚动 private void resumeAutoScrollAfterLottery() { // 延迟一段时间后再启动自动滚动,让用户看到抽奖结果 mBinding.recycleView.postDelayed(() -> { if (isVisible() && !isDrawing) { startAutoScroll(); } }, 3000); // 3秒后重新开始自动滚动 } private void onClick(View view) { int id = view.getId(); if (id == R.id.tv_jc) { if (giftLists != null && !giftLists.isEmpty()) { PrizePoolDialog prizePoolDialog = new PrizePoolDialog(getActivity()); prizePoolDialog.updateData(giftLists, 13); prizePoolDialog.show(); } else { com.hjq.toast.ToastUtils.show("奖池数据加载中,请稍后再试"); } } else if (id == R.id.ll_one) { if (!isDrawing) { isDrawing = true; prepareForNewLottery(); num = "1"; MvpPre.xlhChou(roomId, num); } else { // com.hjq.toast.ToastUtils.show("正在抽奖中..."); } } else if (id == R.id.ll_ten) { if (!isDrawing) { isDrawing = true; prepareForNewLottery(); num = "10"; MvpPre.xlhChou(roomId, num); } else { // com.hjq.toast.ToastUtils.show("正在抽奖中..."); } } else if (id == R.id.ll_hundred) { if (!isDrawing) { isDrawing = true; prepareForNewLottery(); num = "100"; MvpPre.xlhChou(roomId, num); } else { // com.hjq.toast.ToastUtils.show("正在抽奖中..."); } } else if (id == R.id.tv_gz) { Bundle bundle = new Bundle(); bundle.putString("url", getRule_url); bundle.putInt("type", 13); WebViewDialog dialog = new WebViewDialog(getActivity(), bundle); dialog.show(); } else if (id == R.id.tv_bd) { // 如果当前dialog存在且正在显示,先关闭 if (newXlhRankingDialog != null && newXlhRankingDialog.isVisible()) { newXlhRankingDialog.dismiss(); } newXlhRankingDialog = NewXlhRankingDialog.newInstance(roomId); newXlhRankingDialog.show(getChildFragmentManager(), "newXlhRankingDialog"); } else if (id == R.id.tv_jl) { // 如果当前dialog存在且正在显示,先关闭 if (xlhRecordDialog != null && xlhRecordDialog.isVisible()) { xlhRecordDialog.dismiss(); } xlhRecordDialog = XlhRecordDialog.newInstance(roomId); xlhRecordDialog.show(getChildFragmentManager(), "XlhRecordDialog"); } else if (id == R.id.exchange_layout) {//钻石兑换 // ARouter.getInstance().build(ARouteConstants.CURRENCY).navigation(); RechargeDialogFragment.show(roomId, null, getActivity().getSupportFragmentManager(),"0","0"); }else if (id==R.id.v_checkbox){ mBinding.vCheckbox.setSelected(!mBinding.vCheckbox.isSelected()); vCheckbox=mBinding.vCheckbox.isSelected(); } } @Override protected int getLayoutId() { return R.layout.fragment_tour_club_dialog; } @Override public void getGiftListSuccess(BlindBoxBean blindBoxBean) { if (blindBoxBean != null) { 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()) { try { endTime = Long.parseLong(blindBoxBean.getXlh_end_time()); mBinding.qxDjs.setEndTime(endTime); // 假设 end_time 是时间戳字符串 // startCountdown(); } catch (NumberFormatException e) { // 如果不是时间戳,可能是日期字符串,需要相应解析 // 例如:2025-08-26 19:10:47 // 可以使用 SimpleDateFormat 解析 e.printStackTrace(); } } if (blindBoxBean.getGive_homeowner_gift() != null) { // ImageUtils.loadHeadCC(blindBoxBean.getGive_homeowner_gift().getBase_image(), mBinding.giveIm); mBinding.gvFzlw.setModel(blindBoxBean.getGive_homeowner_gift()); } if (blindBoxBean.getLocking_gift() != null) { // ImageUtils.loadHeadCC(blindBoxBean.getLocking_gift().getBase_image(), mBinding.giftImg); // mBinding.tvGiftName.setText(blindBoxBean.getLocking_gift().getGift_name()); // mBinding.tvGiftPrice.setText(blindBoxBean.getLocking_gift().getGift_price()); // mBinding.tvGiftCount.setText(blindBoxBean.getLocking_gift().getGift_num()); mBinding.tvNumber.setText("x"+(blindBoxBean.getLocking_gift().getGift_num()!=null ?blindBoxBean.getLocking_gift().getGift_num():"0")); mBinding.gvSdlw.setModel(blindBoxBean.getLocking_gift()); mBinding.gvSdlw.setIsLockGift(true); mBinding.gvSdlw.stopAnimation(); mBinding.gvSdlw.startAnimation(); } if (blindBoxBean.getXlh_user() != null) { // ImageUtils.loadHeadCC(blindBoxBean.getXlh_user().getAvatar(), mBinding.userPic); // mBinding.userName.setText(blindBoxBean.getXlh_user().getNickname()); mBinding.gvXyz.setModel(blindBoxBean.getXlh_user()); } mBinding.gvXyz.setIsLuckUser(true); if (blindBoxBean.getHomeowner_user()!=null){ mBinding.gvFz.setModel(blindBoxBean.getHomeowner_user()); } mBinding.gvFz.setIsLuckUser(false); giftXlhChouAdapter.setNewData(giftLists); // // 数据加载完成后启动自动滚动 // if (giftLists != null && !giftLists.isEmpty()) { // mBinding.recycleView.post(() -> { // // 确保在UI线程中启动自动滚动 // startAutoScroll(); // }); // } }else { isDrawing = false; } } int mboxPrice; // TODO: 2025/9/4 设置底部按钮文字 private void upTitle(int boxPrice) { this.mboxPrice = boxPrice; mBinding.tvOne.setText(boxPrice + "币一次"); mBinding.tvTen.setText((boxPrice * 10) + "币十次"); mBinding.tvHundred.setText((boxPrice * 100) + "币百次"); } // TODO: 2025/8/29 接收im推送过来的消息 // @Subscribe(threadMode = ThreadMode.MAIN) public void onMusicPlay(RoomMessageEvent message) { if (message.getMsgType() == 1057) { // UpView(message.getText().getXlh_data()); endTime = Long.parseLong(message.getText().getEnd_time() != null ? message.getText().getEnd_time() : "0"); // startCountdown(); // mBinding.tvGiftCount.setText(message.getText().getGift_num() != null ? message.getText().getGift_num() : "0"); // mBinding.userName.setText(message.getText().getFromUserInfo().getNickname() != null ? message.getText().getFromUserInfo().getNickname() : ""); // ImageUtils.loadHeadCC(message.getText().getFromUserInfo().getAvatar(), mBinding.userPic); BlindBoxBean.xlhUser xlhUser = new BlindBoxBean.xlhUser(); xlhUser.setAvatar(message.getText().getFromUserInfo().getAvatar()); xlhUser.setNickname(message.getText().getFromUserInfo().getNickname()); mBinding.gvXyz.setModel(xlhUser); mBinding.qxDjs.setEndTime(endTime); mBinding.tvNumber.setText("x"+(message.getText().getGift_num())); isDrawing=false; } } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageReceived(RoomMessageEvent event) { onMusicPlay( event); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageReceived(MqttXlhEnd event) { XLHBean xlhBean = GsonUtils.fromJson(event.getMessage(), XLHBean.class); if (xlhBean.getFrom_type()==103){ endTime = Long.parseLong(xlhBean.getEnd_time() != null ? xlhBean.getEnd_time() : "0"); BlindBoxBean.xlhUser xlhUser = new BlindBoxBean.xlhUser(); xlhUser.setAvatar(xlhBean.getFromUserInfo().getAvatar()); xlhUser.setNickname(xlhBean.getFromUserInfo().getNickname()); mBinding.gvXyz.setModel(xlhUser); mBinding.qxDjs.setEndTime(endTime); mBinding.tvNumber.setText("x"+(xlhBean.getGift_num() != null ? xlhBean.getGift_num() : "0")); isDrawing=false; if (xlhBean.getRoom_user()!=null){ mBinding.gvFz.setModel(xlhBean.getRoom_user()); } mBinding.gvFz.setIsLuckUser(false); }else if (xlhBean.getFrom_type()==104){ dismiss(); } } /** * 启动倒计时 */ private void startCountdown() { // 先释放之前的倒计时器 releaseCountDownTimer(); // 获取当前时间 long currentTime = System.currentTimeMillis() / 1000; // 转换为秒 long countdownTime = endTime - currentTime; // 计算剩余时间(秒) // 如果倒计时时间已经结束,显示00:00 if (countdownTime <= 0) { updateCountdownDisplay(0, 0); return; } // 确保不超过最大时间59:59 (3599秒) countdownTime = Math.min(countdownTime, 3599); mCountDownTimer = new CountDownTimer(countdownTime * 1000, 1000) { @Override public void onTick(long millisUntilFinished) { long seconds = millisUntilFinished / 1000; long minutes = seconds / 60; long remainingSeconds = seconds % 60; updateCountdownDisplay((int) minutes, (int) remainingSeconds); } @Override public void onFinish() { updateCountdownDisplay(0, 0); } }; mCountDownTimer.start(); } /** * 更新倒计时显示 * * @param minutes 分钟数 * @param seconds 秒数 */ private void updateCountdownDisplay(int minutes, int seconds) { // 假设布局中有以下TextView: // mBinding.tvMinutes 十位分钟 // mBinding.tvMinutesUnit 个位分钟 // mBinding.tvSeconds 十位秒数 // mBinding.tvSecondsUnit 个位秒数 // 分解分钟数 int minutesTens = minutes / 10; // 十位分钟 int minutesUnits = minutes % 10; // 个位分钟 // 分解秒数 int secondsTens = seconds / 10; // 十位秒数 int secondsUnits = seconds % 10; // 个位秒数 // 更新UI显示(根据你的实际布局调整) mBinding.tvTime1.setText(String.valueOf(minutesTens)); mBinding.tvTime2.setText(String.valueOf(minutesUnits)); mBinding.tvTime3.setText(String.valueOf(secondsTens)); mBinding.tvTime4.setText(String.valueOf(secondsUnits)); // 或者如果是一个整体的显示: // mBinding.tvCountdown.setText(String.format("%02d:%02d", minutes, seconds)); } /** * 释放倒计时器资源 */ private void releaseCountDownTimer() { if (mCountDownTimer != null) { mCountDownTimer.cancel(); mCountDownTimer = null; } } @Override public void onDestroyView() { super.onDestroyView(); releaseCountDownTimer(); // 清理所有待执行的任务 clearPendingTasks(); // 清理滚动帮助类 if (scrollHelper != null) { scrollHelper = null; } // 清理适配器引用 if (giftXlhChouAdapter != null) { giftXlhChouAdapter = null; } if (xlhRecordDialog != null && xlhRecordDialog.isVisible()) { xlhRecordDialog.dismiss(); } // 如果当前dialog存在且正在显示,先关闭 if (newXlhRankingDialog != null && newXlhRankingDialog.isVisible()) { newXlhRankingDialog.dismiss(); } if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { xlhObtainDialog.dismiss(); } stopAutoScroll(); autoScrollHandler.removeCallbacksAndMessages(null); } @Override public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { } @Override public void getMyRecordSuccess(List data) { } @Override public void getAllRecordSuccess(List data) { } @Override public void finishRefreshLoadMore() { } private int icon; @Override public void wallet(WalletBean walletBean) { if (walletBean != null) { icon = (int) Double.parseDouble( (walletBean.getCoin() != null && !walletBean.getCoin().isEmpty()) ? walletBean.getCoin() : "0" ); mBinding.tvIcon.setText(walletBean.getCoin()!=null && !walletBean.getCoin().isEmpty() ?walletBean.getCoin():"0"); showView(); } } private void showView() { if (icon>=mboxPrice){ mBinding.llOne.setClickable( true); }else { mBinding.llOne.setClickable( false); } if (icon>=mboxPrice*10){ mBinding.llTen.setClickable( true); }else { mBinding.llTen.setClickable( false); } if (icon>=mboxPrice*100){ mBinding.llHundred.setClickable( true); }else { mBinding.llHundred.setClickable( false); } } private Runnable pendingLotteryRunnable; private Runnable pendingCenteringRunnable; @Override public void xlhChouSuccess(List data) { if (data != null) { if (vCheckbox){ showResultDialog(data); }else { // showResultDialog(data); // 取消之前可能存在的任务 clearPendingTasks(); // 抽奖完成后执行动画滚动 pendingLotteryRunnable = new Runnable() { @Override public void run() { // 清理之前的状态 if (giftXlhChouAdapter != null) { giftXlhChouAdapter.clearSelection(); } int winningPosition = findHighestValueWinningPosition(data);//这是获取到的中奖位置下标 if (winningPosition != -1) { if (scrollHelper == null) { scrollHelper = new CenterScrollHelper(mBinding.recycleView); } // 计算在循环列表中的目标位置(滚动几圈后停在目标位置) int loopCount = 4; // 滚动4圈 int originalSize = giftLists.size();///这是列表的总大小 // 计算目标在循环列表中的位置(确保在中间区域) ///这是计算总圈数的大小 int middleBaseIndex = (loopCount * originalSize); ///这里是展示在中奖的位置,加上总圈数的大小, int targetLoopIndex = middleBaseIndex + (winningPosition % originalSize); // 使用scrollWithCircles方法执行带动画的滚动(带完成回调) scrollHelper.scrollWithCircles( targetLoopIndex, // 在循环列表中的位置 loopCount, // 滚动圈数 1000, // 每个item滚动时间200ms(控制速度) originalSize, // 原始数据大小 () -> { // 滚动完成回调 // 滚动完成后更新选中状态(使用原始位置) if (giftXlhChouAdapter != null) { giftXlhChouAdapter.setSelectedPosition(winningPosition); } // 滚动完成后延迟一小段时间再居中,确保UI更新完成 pendingCenteringRunnable = new Runnable() { @Override public void run() { // 手动将选中项居中 centerSelectedItem(winningPosition, originalSize); // 显示结果对话框 getActivity().runOnUiThread(() -> { scrollHelper = null; showResultDialog(data); // 抽奖结束后重新启动自动滚动 // resumeAutoScrollAfterLottery(); }); } }; mBinding.recycleView.postDelayed(pendingCenteringRunnable, 1000); } ); } else { // 如果没有找到中奖位置,直接显示对话框 showResultDialog(data); // 抽奖结束后重新启动自动滚动 // resumeAutoScrollAfterLottery(); } } }; mBinding.recycleView.postDelayed(pendingLotteryRunnable, 1000); } }else { isDrawing=false; // 抽奖失败也重新启动自动滚动 // resumeAutoScrollAfterLottery(); } MvpPre.wallet(); } /** * 为新的抽奖做准备,清理之前的状态 */ private void prepareForNewLottery() { // 停止自动滚动 stopAutoScroll(); // 取消之前可能存在的任务 clearPendingTasks(); // 清除之前的选择状态 if (giftXlhChouAdapter != null) { giftXlhChouAdapter.clearSelection(); } // 重置滚动帮助类 if (scrollHelper != null) { scrollHelper.reset(); } // 停止可能正在进行的滚动 mBinding.recycleView.stopScroll(); // 清理可能存在的回调 if (mBinding.recycleView.getHandler() != null) { mBinding.recycleView.getHandler().removeCallbacksAndMessages(null); } // 重新初始化滚动帮助类 scrollHelper = new CenterScrollHelper(mBinding.recycleView); } /** * 清除所有待执行的任务 */ private void clearPendingTasks() { // 取消抽奖动画任务 if (pendingLotteryRunnable != null) { mBinding.recycleView.removeCallbacks(pendingLotteryRunnable); pendingLotteryRunnable = null; } // 取消居中任务 if (pendingCenteringRunnable != null) { mBinding.recycleView.removeCallbacks(pendingCenteringRunnable); pendingCenteringRunnable = null; } // 停止可能正在进行的滚动 mBinding.recycleView.stopScroll(); // 清理handler中的所有消息 if (mBinding.recycleView.getHandler() != null) { mBinding.recycleView.getHandler().removeCallbacksAndMessages(null); } } 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 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; // 先滚动到目标位置附近 mBinding.recycleView.scrollToPosition(targetPosition); // 使用post确保布局完成后进行精确居中 mBinding.recycleView.post(() -> { View targetView = layoutManager.findViewByPosition(targetPosition); if (targetView == null) { // 如果目标view不可见,使用smoothScrollToPosition mBinding.recycleView.smoothScrollToPosition(targetPosition); // 再次尝试居中 mBinding.recycleView.postDelayed(() -> { View refreshedView = layoutManager.findViewByPosition(targetPosition); if (refreshedView != null) { performCentering(layoutManager, refreshedView); } }, 50); return; } performCentering(layoutManager, targetView); }); } // 执行实际的居中操作 private void performCentering(LinearLayoutManager layoutManager, View targetView) { // 计算RecyclerView的中心点 int recyclerViewWidth = mBinding.recycleView.getWidth(); int recyclerViewCenter = recyclerViewWidth / 2; // 计算目标view的中心点 int targetViewLeft = targetView.getLeft(); int targetViewWidth = targetView.getWidth(); int targetViewCenter = targetViewLeft + targetViewWidth / 2; // 计算需要滚动的偏移量 int offset = targetViewCenter - recyclerViewCenter; // 精确滚动使目标view居中 mBinding.recycleView.scrollBy(offset, 0); } /** * 直接滚动到指定位置并居中 * * @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 data) { isDrawing = false; // 创建并显示对话框 // 关闭之前可能存在的对话框 // if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { // xlhObtainDialog.dismiss(); // } // 创建并显示对话框 xlhObtainDialog = new XlhObtainDialog(getActivity()); xlhObtainDialog.setOnGiftItemClickListener(new XlhObtainDialog.OnGiftItemClickListener() { @Override public void onPlayAgainClick() { isDrawing = true; // 处理再玩一次点击事件 MvpPre.xlhChou(roomId, num); } @Override public void onCloseClick() { // 处理关闭点击事件 if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { isDrawing = false; xlhObtainDialog.dismiss(); } xlhObtainDialog = null; } }); xlhObtainDialog.show(); xlhObtainDialog.setGiftList(data); } /** * 根据中奖结果找到最高价值奖品在giftLists中的位置 * * @param data 中奖结果列表 * @return 最高价值奖品在giftLists中的下标,如果没有找到则返回-1 */ private int findHighestValueWinningPosition(List 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); } }