diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/adapter/AppUpdateDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/adapter/AppUpdateDialog.java index 8c5615d..0a0d6a0 100644 --- a/moduleUtil/src/main/java/com/xscm/moduleutil/adapter/AppUpdateDialog.java +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/adapter/AppUpdateDialog.java @@ -63,7 +63,7 @@ public class AppUpdateDialog extends BaseDialog 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为是,反之为否 diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java index 37925e0..b17cde4 100644 --- a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java @@ -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 ; } diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java index 4c7696c..b8a4db7 100644 --- a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java @@ -15,7 +15,7 @@ public class GiftItemAdapter extends BaseQuickAdapter { + private List 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 data) { + this.giftLists = data != null ? data : new ArrayList<>(); + super.setNewData(createLoopData()); + } + + /** + * 创建循环数据 + * @return 循环数据列表 + */ + private List createLoopData() { + List 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(); } } diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java index 7961f88..fd7ad7c 100644 --- a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java @@ -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 { + if (giftXlhChouAdapter.getOriginalDataSize() > 0) { + int middlePosition = giftXlhChouAdapter.getItemCount() / 2; + mBinding.recycleView.scrollToPosition(middlePosition); + } + }); + } @@ -190,6 +215,8 @@ public class TourClubDialogFragment extends BaseMvpDialogFragment 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 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 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 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); + + } + + + + + } diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java new file mode 100644 index 0000000..4368bab --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java @@ -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; + } + + +} + + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java new file mode 100644 index 0000000..234425e --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java @@ -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); + } + } +} + + diff --git a/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml b/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml index ecf09b7..8e104ff 100644 --- a/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml +++ b/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml @@ -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"/>