package com.weishitech.qichechangtingyinyue.utils;
import android.view.View;
import android.widget.ImageView;
import com.weishitech.qichechangtingyinyue.R;
public class ThemeManager {
public static final int THEME_BLUE = 0;
public static final int THEME_GREEN = 1;
public static final int THEME_RED = 2;
private int[] backgrounds = {
R.mipmap.img_lan_bg,
R.mipmap.img_lv_bg,
R.mipmap.img_hong_bg
};
private int[] background = {
R.mipmap.img_lan_mh,
R.mipmap.img_lv_mh_bg,
R.mipmap.img_hong_mh
};
private int[] playIcons = {
R.mipmap.img_lan_bf,
R.mipmap.img_lv_bf,
R.mipmap.img_hong_bf
};
private int[] pauseIcons = {
R.mipmap.img_lan_zt,
R.mipmap.img_lv_zt,
R.mipmap.img_hong_zt
};
private int currentThemeIndex = 0;
/**
* 下一个主题(循环)
*/
public void nextTheme() {
currentThemeIndex = (currentThemeIndex + 1) % backgrounds.length;
}
/**
* 设置指定主题
*/
public void setTheme(int index) {
if (index >= 0 && index < backgrounds.length) {
currentThemeIndex = index;
}
}
/**
* 应用当前主题到视图
*/
public void applyThemeTo(View backgroundView1, View backgroundView2, ImageView iconView, boolean isPlaying) {
try {
// 更新背景
if (backgroundView1 != null) {
backgroundView1.setBackgroundResource(backgrounds[currentThemeIndex]);
}
if (backgroundView2 != null) {
backgroundView2.setBackgroundResource(backgrounds[currentThemeIndex]);
}
// 更新图标
if (iconView != null) {
int resId = isPlaying ? pauseIcons[currentThemeIndex] : playIcons[currentThemeIndex];
iconView.setImageResource(resId);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public int getCurrentThemeIndex() {
return currentThemeIndex;
}
public int getBackgroundRes() {
return backgrounds[currentThemeIndex];
}
public int getPauseIconRes() {
return pauseIcons[currentThemeIndex];
}
public int getPlayIconRes() {
return playIcons[currentThemeIndex];
}
}
package com.weishitech.qichechangtingyinyue.fragment.home;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.hfd.common.base.BaseFragment;
import com.hfd.common.net.GenericsCallback;
import com.hfd.common.net.HttpBuiler;
import com.hfd.common.net.JsonGenericsSerializator;
import com.hfd.common.net.Url;
import com.hfd.common.util.ToastUtil;
import com.weishitech.qichechangtingyinyue.MainActivity;
import com.weishitech.qichechangtingyinyue.R;
import com.weishitech.qichechangtingyinyue.bean.MusicBean;
import com.weishitech.qichechangtingyinyue.bean.MusicCache;
import com.weishitech.qichechangtingyinyue.bean.NavigationSource;
import com.weishitech.qichechangtingyinyue.bean.PlayStatusUpdateEvent;
import org.greenrobot.eventbus.EventBus;
import com.weishitech.qichechangtingyinyue.fragment.Adapter.PrivateAdapter;
import com.weishitech.qichechangtingyinyue.fragment.Adapter.QyAdapter;
import com.weishitech.qichechangtingyinyue.fragment.Adapter.SongTopAdapter;
import com.weishitech.qichechangtingyinyue.fragment.Adapter.XzAdapter;
import com.weishitech.qichechangtingyinyue.fragment.lilv.LiLvFragment;
import com.weishitech.qichechangtingyinyue.utils.DisplayUtils;
import com.weishitech.qichechangtingyinyue.utils.LeftGravitySnapHelper;
import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager;
import com.weishitech.qichechangtingyinyue.utils.OnMultiClickListener;
import com.weishitech.qichechangtingyinyue.utils.RotationAnimatorHelper;
import com.weishitech.qichechangtingyinyue.utils.ThemeManager;
import com.weishitech.qichechangtingyinyue.view.FixedSideSnapHelper;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import okhttp3.Call;
/**
* 高端语音导航首页
*/
public class HomeFragment extends BaseFragment {
// UI Views
private RecyclerView rv, sr_rv, qy_rv, xz_rv;
private ImageView iv_ss, iv_gd, sr_start, qy_start, xz_start, iv_bf;
private TextView tv_time, tv_song_name;
private LinearLayout line;
private RelativeLayout relative,relative1,relative2,relative3;
// Managers & Helpers
private MusicPlayerManager playerManager;
private ThemeManager themeManager;
private RotationAnimatorHelper rotationHelper;
// private boolean isMainPlaybackActive = false; // 是否由主流程控制播放状态
// Data & State
private SongTopAdapter songTopAdapter;
private List<MusicBean.DataBean> restList = new ArrayList<>();
private List<MusicBean.DataBean> privateSongList;//私人播放列表字段
private List<MusicBean.DataBean> qySongList;//轻音乐播放列表字段
private List<MusicBean.DataBean> xzSongList;//小众音乐播放列表字段
private GestureDetector gestureDetector;
private PrivateAdapter privateAdapter;
private boolean isAutoSwitching = false; // 标记是否正在自动切换下一首
// 自动滑动相关
private Handler autoScrollHandler;
private Runnable autoScrollRunnable;
private boolean isAutoScrollEnabled = true; // 是否启用自动滑动
private long autoScrollInterval = 5000; // 自动滑动间隔(毫秒),默认5秒
private long lastManualScrollTime = 0; // 最后一次手动滑动的时间
private long manualScrollPauseDuration = 10000; // 手动滑动后暂停自动滑动的时间(毫秒),默认10秒
private MainActivity mActivity;
private List<MusicBean.DataBean> musicDataList;
@Override
protected int setLayout() {
return R.layout.fragment_home;
}
@Override
protected void initView() {
iv_ss = fvbi(R.id.iv_ss);
iv_gd = fvbi(R.id.iv_gd);
iv_bf = fvbi(R.id.iv_bf);
rv = fvbi(R.id.rv);
sr_rv = fvbi(R.id.sr_rv);
qy_rv = fvbi(R.id.qy_rv);
xz_rv = fvbi(R.id.xz_rv);
sr_start = fvbi(R.id.sr_start);
qy_start = fvbi(R.id.qy_start);
xz_start = fvbi(R.id.xz_start);
tv_time = fvbi(R.id.tv_time);
tv_song_name = fvbi(R.id.tv_song_name);
line = fvbi(R.id.line);
relative = fvbi(R.id.relative);
relative1 = fvbi(R.id.relative1);
relative2 = fvbi(R.id.relative2);
relative3 = fvbi(R.id.relative3);
// 初始化组件
playerManager = MusicPlayerManager.getInstance(); //单例获取
themeManager = new ThemeManager();
rotationHelper = new RotationAnimatorHelper();
// 初始化自动滑动Handler
autoScrollHandler = new Handler(Looper.getMainLooper());
// 跑马灯
tv_song_name.setEllipsize(TextUtils.TruncateAt.MARQUEE);
tv_song_name.setSingleLine(true);
tv_song_name.setSelected(true);
tv_song_name.setFocusable(true);
tv_song_name.setFocusableInTouchMode(true);
setupGestureListener(); // 滑动手势换肤
iv_bf.setImageResource(themeManager.getPlayIconRes()); // 默认显示蓝色“播放”图标
if (NavigationSource.isDirectClick()) {
NavigationSource.clear(); // 清理,防止影响下一次
}
mActivity = (MainActivity) getActivity();
}
@Override
protected void initClick() {
// 搜索跳转
iv_ss.setOnClickListener(v -> {
Bundle bundle = new Bundle();
// 添加私人歌曲列表
if (privateSongList != null && !privateSongList.isEmpty()) {
bundle.putSerializable("private_song_list", new ArrayList<>(privateSongList));
} else {
bundle.putSerializable("private_song_list", new ArrayList<MusicBean.DataBean>());
}
// 添加轻音乐列表
if (qySongList != null && !qySongList.isEmpty()) {
bundle.putSerializable("qingyin_song_list", new ArrayList<>(qySongList));
} else {
bundle.putSerializable("qingyin_song_list", new ArrayList<MusicBean.DataBean>());
}
// 跳转并传参
toClass(SearchActivity.class, bundle);
});
iv_gd.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
mActivity.JumpToPrice();
}
});
// 播放/暂停按钮
iv_bf.setOnClickListener(v -> {
if (musicDataList.isEmpty()) {
ToastUtil.showShortToast("暂无歌曲可播放");
return;
}
//&& isMainPlaybackActive isMainPlaybackActive = false; isMainPlaybackActive = true; // 标记为主控模式
if (playerManager.isPlaying() ) {
playerManager.pause();
} else {
int pos = findBestObscuredItem(rv, DisplayUtils.dp2px(requireContext(), 50f));
if (pos == RecyclerView.NO_POSITION) pos = 0;
playMusicAtPosition(pos);
}
updatePlayButtonIcon(); // 只有主控才更新 iv_bf
});
relative1.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
if (privateSongList == null || privateSongList.isEmpty()) {
ToastUtil.showShortToast("暂无数据");
return;
}
// 标记为「非直接来源」
NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST);
Bundle bundle = new Bundle();
bundle.putString("type", "私人专属好歌");
bundle.putSerializable("song_list", new ArrayList<>(privateSongList)); // 拷贝一份
toClass(MusicListActivity.class, bundle);
}
});
relative2.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
if (qySongList == null || qySongList.isEmpty()) {
ToastUtil.showShortToast("暂无数据");
return;
}
// 标记为「非直接来源」
NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST);
Bundle bundle = new Bundle();
bundle.putString("type", "轻音乐");
bundle.putSerializable("song_list", new ArrayList<>(qySongList));
toClass(MusicListActivity.class, bundle);
}
});
relative3.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
if (xzSongList == null || xzSongList.isEmpty()) {
ToastUtil.showShortToast("暂无数据");
return;
}
// 标记为「非直接来源」
NavigationSource.setSource(NavigationSource.FROM_MUSIC_LIST);
Bundle bundle = new Bundle();
bundle.putString("type", "小众音乐");
bundle.putSerializable("song_list", new ArrayList<>(xzSongList));
toClass(MusicListActivity.class, bundle);
}
});
// 双击歌曲信息区域(relative)时自动向左滑动一位
relative.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
// 双击时向左滑动一位,并自动播放下一首
scrollToNextItem(true);
}
});
}
@Override
protected void initData() {
updateTimeGreeting();
musicAppInfo();
setupPlaybackListener();
}
/**
* 设置播放状态监听器(确保 HomeFragment 的监听器始终生效)
*/
private void setupPlaybackListener() {
playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() {
@Override
public void onPlaying(int position) {
// 关键修复:检查当前播放的歌曲是否属于首页列表
// 先检查必要的对象是否已初始化
if (songTopAdapter == null || musicDataList == null || musicDataList.isEmpty()) {
// 如果适配器或数据列表未初始化,只更新播放按钮状态
updatePlayButtonIcon();
return;
}
boolean isFromMainList = !playerManager.isPlayingFromPrivate();
if (isFromMainList && position >= 0 && position < musicDataList.size()) {
// 播放的是首页列表中的歌曲,更新首页状态
updatePlayButtonIcon();
songTopAdapter.updatePlayingPosition(position);
startRotationForCurrentItem(position);
// 更新歌曲信息显示
MusicBean.DataBean currentSong = musicDataList.get(position);
if (currentSong != null && tv_song_name != null) {
tv_song_name.setText(currentSong.getTitle() + "-" + currentSong.getSinger());
}
// 关键修复:发送事件更新tab圆形图标,即使封面为空也要发送
// 这样可以确保当歌曲没有封面时,图标会更新为默认图标,而不是卡在之前的封面
if (currentSong != null) {
PlayStatusUpdateEvent event = new PlayStatusUpdateEvent(
currentSong.getCover(), // 可能为null或空,但也要发送
currentSong.getTitle(),
currentSong.getSinger(),
true
);
EventBus.getDefault().post(event);
}
} else {
// 播放的是外部列表的歌曲(私人、轻音乐、小众等),清除首页的播放状态
songTopAdapter.updatePlayingPosition(-1); // 清除播放位置
if (rotationHelper != null) {
rotationHelper.stopRotation(); // 停止旋转动画
}
// 更新其他适配器的状态
String tag = playerManager.getCurrentPlaylistTag();
if ("private".equals(tag) && privateAdapter != null) {
int idx = playerManager.getCurrentExternalIndex();
privateAdapter.updatePlayingPosition(idx, true);
}
}
}
@Override
public void onPaused() {
// 先检查必要的对象是否已初始化
if (rotationHelper == null) {
updatePlayButtonIcon();
return;
}
boolean isFromMainList = !playerManager.isPlayingFromPrivate();
if (isFromMainList) {
// 暂停的是首页列表中的歌曲
updatePlayButtonIcon();
rotationHelper.stopRotation();
} else {
// 暂停的是外部列表的歌曲
rotationHelper.stopRotation(); // 确保停止旋转
// 更新其他适配器的状态
String tag = playerManager.getCurrentPlaylistTag();
if ("private".equals(tag) && privateAdapter != null) {
int idx = playerManager.getCurrentExternalIndex();
privateAdapter.updatePlayingPosition(idx, false);
}
}
}
@Override
public void onCompletion() {
android.util.Log.i("MusicPlayerManager", "========== HomeFragment.onCompletion 被调用 ==========");
android.util.Log.i("HomeFragment", "========== onCompletion: 歌曲播放完成 - 开始处理 ==========");
android.util.Log.i("HomeFragment", "onCompletion: 当前线程=" + Thread.currentThread().getName());
android.util.Log.i("HomeFragment", "onCompletion: isAdded()=" + isAdded() + ", rv=" + (rv != null) + ", musicDataList=" + (musicDataList != null ? musicDataList.size() : "null"));
Log.d("HomeFragment", "onCompletion: 歌曲播放完成 - 开始处理");
// 基本状态检查(放宽条件,只要 rv 和 musicDataList 存在即可)
if (rv == null) {
android.util.Log.w("HomeFragment", "onCompletion: RecyclerView 为 null,跳过");
return;
}
if (musicDataList == null || musicDataList.isEmpty()) {
android.util.Log.w("HomeFragment", "onCompletion: 歌曲列表为空,跳过");
return;
}
// 检查播放源(只处理主列表)
if (playerManager.isPlayingFromPrivate()) {
android.util.Log.d("HomeFragment", "onCompletion: 私人音乐播放完成,不触发主列表自动滑动");
return;
}
// 停止旋转动画(与定时方式保持一致)
rotationHelper.stopRotation();
// 确保在主线程执行(与定时方式完全一致)
// scrollToNextItem 内部会使用 rv.post() 确保 UI 操作在主线程,所以这里直接调用即可
android.util.Log.i("MusicPlayerManager", "========== 执行自动滑动到下一首 ==========");
android.util.Log.i("HomeFragment", "========== onCompletion: 执行自动滑动到下一首 ==========");
Log.d("HomeFragment", "onCompletion: 执行自动滑动到下一首,当前线程=" + Thread.currentThread().getName());
scrollToNextItem(true);
}
@Override
public void onError(String errorMsg) {
ToastUtil.showShortToast(errorMsg);
if (playerManager.isPlayingFromPrivate()) {
privateAdapter.clearPlayingState();
} else {
updatePlayButtonIcon();
}
rotationHelper.stopRotation();
}
});
}
private void updateTimeGreeting() {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
String greeting;
if (hour >= 5 && hour < 11) greeting = "HI,早上好";
else if (hour == 11 || hour == 12 || (hour >= 13 && hour < 18)) greeting = "HI,下午好";
else greeting = "HI,晚上好";
tv_time.setText(greeting);
}
private void musicAppInfo() {
HashMap<String, String> map = new HashMap<>();
showDialog();
HttpBuiler.getInfo(Url.music, map).build().execute(
new GenericsCallback<MusicBean>(new JsonGenericsSerializator()) {
@Override
public void onError(Call call, Exception e, int id) {
dissmiss();
ToastUtil.showShortToast(e.getMessage());
}
@Override
public void onResponse(MusicBean response, int id) {
dissmiss();
if ("0".equals(response.getCode()) && response.getData() != null && !response.getData().isEmpty()) {
restList = response.getData();
// 获取第三条之后的数据(即从索引2开始到末尾)
musicDataList = new ArrayList<>(restList.subList(3, restList.size()));
// 缓存主歌单
MusicCache.setMainMusicList(musicDataList);
setupMusicRecyclerView();
// 在 setupMusicRecyclerView 之后重新设置监听器,因为 PrivateAdapter 可能会覆盖监听器
setupPlaybackListener();
notifyLiLvFragmentRefresh();
// 不再使用定时自动滑动,改为歌曲播放完成后自动滑动
// startAutoScroll();
} else {
ToastUtil.showShortToast("暂无歌曲数据");
}
}
});
}
private void setupMusicRecyclerView() {
songTopAdapter = new SongTopAdapter();
rv.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
rv.setAdapter(songTopAdapter);
// 设置播放状态回调(用于封面旋转)
songTopAdapter.setOnPlayStateChangedListener((position, coverView) -> {
rotationHelper.stopRotation();
rotationHelper.startRotation(coverView);
});
// 必须在设置 adapter 后再初始化滚动逻辑
setupSnappingAndPlayback(rv, songTopAdapter);
// 最后设置数据
songTopAdapter.setList(musicDataList);
//点击top条目跳转到歌词页面
songTopAdapter.setOnItemClickListener((position, dataBean) -> {
// 标记为「直接点击」来源
NavigationSource.setSource(NavigationSource.DIRECT_CLICK);
// 创建 Bundle 传递数据
Bundle bundle = new Bundle();
bundle.putString("title", dataBean.getTitle());
bundle.putString("singer", dataBean.getSinger());
bundle.putString("cover_url", dataBean.getCover());
bundle.putString("music_url", dataBean.getMusic());
bundle.putString("time", dataBean.getSongTime());
bundle.putInt("position", position);
bundle.putInt("total_count", musicDataList.size());
// 跳转到 LyricsActivity
toClass(LyricsActivity.class, bundle);
});
//私人音乐适配器
// 从第三个元素(索引=2)开始,取最多20首歌曲
int start = 3; // 第三个元素的索引
int end = Math.min(start + 20, musicDataList.size()); // 最多取20首,且不能越界
if (start >= musicDataList.size()) {
privateSongList = new ArrayList<>(); // 防止越界
ToastUtil.showShortToast("起始位置超出列表范围");
} else {
privateSongList = new ArrayList<>(musicDataList.subList(start, end));
}
privateAdapter = new PrivateAdapter();
privateAdapter.setMainPlayButtonUpdater(isPlaying -> {
Log.d("11111111",""+isPlaying);
iv_bf.setImageResource(isPlaying ?
themeManager.getPauseIconRes() :
themeManager.getPlayIconRes());
});
// 设置横向 Grid 布局:每行3个
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 3, RecyclerView.HORIZONTAL, false);
sr_rv.setLayoutManager(gridLayoutManager);
sr_rv.setAdapter(privateAdapter);
privateAdapter.setList(privateSongList);
// <<< 添加吸附效果 >>>
new LeftGravitySnapHelper().attachToRecyclerView(sr_rv);
privateAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
// 创建 Bundle 传递数据
Bundle bundle = new Bundle();
bundle.putString("title", privateSongList.get(position).getTitle());
bundle.putString("singer", privateSongList.get(position).getSinger());
bundle.putString("cover_url", privateSongList.get(position).getCover());
bundle.putString("music_url", privateSongList.get(position).getMusic());
bundle.putString("time", privateSongList.get(position).getSongTime());
bundle.putInt("position", position);
bundle.putInt("total_count", privateSongList.size());
// 传递source_list,用于上下首切换
bundle.putSerializable("source_list", new ArrayList<>(privateSongList));
// 传递播放列表标签
bundle.putString("playlist_tag", "private");
// 跳转到 LyricsActivity
toClass(LyricsActivity.class, bundle);
}
});
//轻音乐
// 确保 musicDataList 不为 null 且有数据
if (musicDataList == null || musicDataList.isEmpty()) {
return;
}
int qystart = 5;
int count = 6;
int qyend = Math.min(qystart + count, musicDataList.size());
qySongList = new ArrayList<>(musicDataList.subList(qystart, qyend));
QyAdapter qyAdapter = new QyAdapter();
// 设置横向 Grid 布局:每行3个
GridLayoutManager gridLayoutManagers = new GridLayoutManager(requireContext(), 2);
qy_rv.setLayoutManager(gridLayoutManagers);
qy_rv.setAdapter(qyAdapter);
qyAdapter.setList(qySongList);
qyAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
// 创建 Bundle 传递数据
Bundle bundle = new Bundle();
bundle.putString("title", qySongList.get(position).getTitle());
bundle.putString("singer", qySongList.get(position).getSinger());
bundle.putString("cover_url", qySongList.get(position).getCover());
bundle.putString("music_url", qySongList.get(position).getMusic());
bundle.putString("time", qySongList.get(position).getSongTime());
bundle.putInt("position", position);
bundle.putInt("total_count", qySongList.size());
// 传递source_list,用于上下首切换
bundle.putSerializable("source_list", new ArrayList<>(qySongList));
// 传递播放列表标签
bundle.putString("playlist_tag", "qingyin");
// 跳转到 LyricsActivity
toClass(LyricsActivity.class, bundle);
}
});
//小众音乐
// 确保 musicDataList 不为 null 且有数据
if (musicDataList == null || musicDataList.isEmpty()) {
return;
}
int xzstart = 8;
int xzcount = 6;
int xzend = Math.min(xzstart + xzcount, musicDataList.size());
xzSongList = new ArrayList<>(musicDataList.subList(xzstart, xzend));
XzAdapter xzAdapter = new XzAdapter();
// 设置横向 Grid 布局:每行3个
xz_rv.setLayoutManager(new LinearLayoutManager(requireContext(),LinearLayoutManager.HORIZONTAL, false));
xz_rv.setAdapter(xzAdapter);
xzAdapter.setList(xzSongList);
// <<< 添加吸附效果 >>>
new LeftGravitySnapHelper().attachToRecyclerView(xz_rv);
xzAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
// 创建 Bundle 传递数据
Bundle bundle = new Bundle();
bundle.putString("title", xzSongList.get(position).getTitle());
bundle.putString("singer", xzSongList.get(position).getSinger());
bundle.putString("cover_url", xzSongList.get(position).getCover());
bundle.putString("music_url", xzSongList.get(position).getMusic());
bundle.putString("time", xzSongList.get(position).getSongTime());
bundle.putInt("position", position);
bundle.putInt("total_count", xzSongList.size());
// 传递source_list,用于上下首切换
bundle.putSerializable("source_list", new ArrayList<>(xzSongList));
// 传递播放列表标签
bundle.putString("playlist_tag", "xiaozhong");
// 跳转到 LyricsActivity
toClass(LyricsActivity.class, bundle);
}
});
}
private void setupSnappingAndPlayback(RecyclerView rv, SongTopAdapter adapter) {
LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager();
if (layoutManager == null) return;
int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f);
FixedSideSnapHelper snapHelper = new FixedSideSnapHelper(fixedTargetX);
snapHelper.attachToRecyclerView(rv);
AtomicInteger lastPlayedPosition = new AtomicInteger(RecyclerView.NO_POSITION);
final boolean[] isFirstLayoutDone = {false}; // <<< 添加标志位
// 延迟标记“首次布局已完成”
rv.post(() -> isFirstLayoutDone[0] = true);
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// 关键:只有完成首次布局后才允许自动播放
if (!isFirstLayoutDone[0]) {
return;
}
// 如果是自动切换,不触发滚动监听器的自动播放逻辑
if (isAutoSwitching) {
return;
}
int pos = findBestObscuredItem(recyclerView, fixedTargetX);
if (pos != RecyclerView.NO_POSITION && pos != lastPlayedPosition.get()) {
final int finalPos = pos;
// 使用 post 延迟执行,避免在 layout 过程中更改数据
rv.post(() -> {
playMusicAtPosition(finalPos);
lastPlayedPosition.set(finalPos);
});
}
dispatchVisualFeedback(recyclerView, adapter);
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (layoutManager == null) return;
// 如果是自动切换,不触发滚动状态变化的自动播放逻辑
if (isAutoSwitching) {
Log.d("HomeFragment", "onScrollStateChanged: isAutoSwitching=true, newState=" + newState);
// 不在这里清除标志,让延迟任务来处理
return;
}
int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f);
switch (newState) {
case RecyclerView.SCROLL_STATE_DRAGGING:
// 用户开始手动拖拽,暂停当前播放
// 滑动开始了,暂停当前播放
if (playerManager.isPlaying()) {
playerManager.pause();
rotationHelper.stopRotation();
updatePlayButtonIcon(); // 显示"暂停"图标
}
// 记录手动滑动时间(用于歌曲播放完成时判断是否在暂停期)
if (!isAutoSwitching) {
lastManualScrollTime = System.currentTimeMillis();
// 不再需要停止定时器,因为使用歌曲播放完成方式
// stopAutoScroll();
}
break;
case RecyclerView.SCROLL_STATE_SETTLING:
// 滑动中,暂停当前播放
if (playerManager.isPlaying()) {
playerManager.pause();
rotationHelper.stopRotation();
updatePlayButtonIcon(); // 显示"暂停"图标
}
break;
case RecyclerView.SCROLL_STATE_IDLE:
// 滑动结束,找到应该播放的 item 并自动播放
// 如果是自动切换,不触发这里的逻辑(避免覆盖自动滑动的歌曲信息)
if (isAutoSwitching) {
// 自动切换时,确保歌曲信息已更新
int targetPos = findBestObscuredItem(recyclerView, fixedTargetX);
if (targetPos != RecyclerView.NO_POSITION && targetPos < musicDataList.size()) {
MusicBean.DataBean bean = musicDataList.get(targetPos);
tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger());
}
break;
}
// 手动滑动结束,不再启动定时器(使用歌曲播放完成方式)
int targetPos = findBestObscuredItem(recyclerView, fixedTargetX);
if (targetPos != RecyclerView.NO_POSITION) {
playMusicAtPosition(targetPos); // 这个方法会播放音乐 + 更新 UI + 开始旋转
} else {
// 如果没找到合适的位置,至少恢复状态
updatePlayButtonIcon();
}
break;
}
}
});
setupOneWayScroll(rv, requireContext());
}
private int findBestObscuredItem(RecyclerView rv, int fuzzyRightEdge) {
LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager();
if (lm == null) return RecyclerView.NO_POSITION;
int bestPos = RecyclerView.NO_POSITION;
float minDiff = Float.MAX_VALUE;
for (int i = 0; i < lm.getChildCount(); i++) {
View child = lm.getChildAt(i);
if (child == null) continue;
int left = lm.getDecoratedLeft(child);
int right = lm.getDecoratedRight(child);
int width = right - left;
if (right <= 0 || left >= fuzzyRightEdge) continue; // 无交集
int overlapStart = Math.max(left, 0);
int overlapEnd = Math.min(right, fuzzyRightEdge);
int overlapWidth = Math.max(0, overlapEnd - overlapStart);
float coveredRatio = (float) overlapWidth / width;
float diff = Math.abs(coveredRatio - 0.5f);
if (coveredRatio >= 0.3f && coveredRatio <= 0.7f && diff < minDiff) {
minDiff = diff;
bestPos = lm.getPosition(child);
}
}
return bestPos;
}
@SuppressLint("SetTextI18n")
private void playMusicAtPosition(int position) {
if (position == RecyclerView.NO_POSITION || position >= musicDataList.size()) return;
MusicBean.DataBean bean = musicDataList.get(position);
iv_bf.setImageResource(themeManager.getPauseIconRes());
tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger());
nextSkin(); // 每次播放新歌就换主题
rv.post(() -> {
});
songTopAdapter.updatePlayingPosition(position);
playerManager.play(requireContext(), position, bean.getMusic());
PlayStatusUpdateEvent event = new PlayStatusUpdateEvent(
bean.getCover(),
bean.getTitle(),
bean.getSinger(),
true
);
EventBus.getDefault().post(event);
//使用 post() 延迟更新 adapter,避免在 layout 过程中修改
// rv.post(() -> {
//
//
// // 同时更新底部显示
//
//
// });
// updatePlayButtonIcon();
}
private void playNextSong() {
int currentPos = playerManager.getCurrentPlayingPosition();
int nextPos = currentPos + 1;
if (nextPos >= musicDataList.size()) {
ToastUtil.showShortToast("已播放完全部歌曲");
updatePlayButtonIcon(); // 确保按钮变回"播放"
return;
}
Log.d("HomeFragment", "playNextSong: currentPos=" + currentPos + ", nextPos=" + nextPos);
// 设置自动切换标志,防止滚动监听器干扰
isAutoSwitching = true;
// 先更新播放和 UI(但不更新 adapter),避免延迟
MusicBean.DataBean bean = musicDataList.get(nextPos);
iv_bf.setImageResource(themeManager.getPauseIconRes());
tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger());
nextSkin();
playerManager.play(requireContext(), nextPos, bean.getMusic());
PlayStatusUpdateEvent event = new PlayStatusUpdateEvent(
bean.getCover(),
bean.getTitle(),
bean.getSinger(),
true
);
EventBus.getDefault().post(event);
// 立即执行平滑滚动动画
rv.post(() -> {
scrollToTriggerPosition(nextPos, rv);
});
// 滚动完成后更新 adapter 位置(延迟以避免中断滚动)
rv.postDelayed(() -> {
songTopAdapter.updatePlayingPosition(nextPos);
}, 600);
// 延迟清除自动切换标志
rv.postDelayed(() -> {
isAutoSwitching = false;
}, 1000);
}
/**
* 向左滑动一位(自动滑动到下一个item)
* @param autoPlay 是否自动播放下一首歌曲
*/
public void scrollToNextItem(boolean autoPlay) {
if (rv == null || musicDataList == null || musicDataList.isEmpty()) {
ToastUtil.showShortToast("暂无歌曲数据");
return;
}
LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager();
if (lm == null) {
Log.e("HomeFragment", "scrollToNextItem: LayoutManager is null!");
return;
}
// 找到当前显示的位置
int fixedTargetX = DisplayUtils.dp2px(requireContext(), 50f);
int currentPos = findBestObscuredItem(rv, fixedTargetX);
// 如果找不到当前位置,尝试使用播放器当前的位置
if (currentPos == RecyclerView.NO_POSITION) {
currentPos = playerManager.getCurrentPlayingPosition();
if (currentPos == RecyclerView.NO_POSITION) {
currentPos = 0; // 默认从第一个开始
}
}
// 计算下一个位置
int nextPos = currentPos + 1;
// 检查是否超出范围
// 如果 autoPlay=true(自动播放),则循环回到第一首
// 如果 autoPlay=false(手动调用),则提示并返回
if (nextPos >= musicDataList.size()) {
if (autoPlay) {
// 自动播放时循环回到第一首
nextPos = 0;
} else {
// 手动调用时提示
ToastUtil.showShortToast("已经是最后一首歌曲");
return;
}
}
// 将 nextPos 设为 final,以便在 lambda 中使用
final int finalNextPos = nextPos;
Log.d("HomeFragment", "scrollToNextItem: 当前位置=" + currentPos + ", 下一个位置=" + finalNextPos + ", autoPlay=" + autoPlay);
// 设置自动切换标志,防止滚动监听器干扰
isAutoSwitching = true;
// 更新歌曲信息显示(无论是否自动播放都要更新)
MusicBean.DataBean bean = musicDataList.get(finalNextPos);
tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger());
// 如果自动播放,播放下一首
if (autoPlay) {
iv_bf.setImageResource(themeManager.getPauseIconRes());
nextSkin();
playerManager.play(requireContext(), finalNextPos, bean.getMusic());
PlayStatusUpdateEvent event = new PlayStatusUpdateEvent(
bean.getCover(),
bean.getTitle(),
bean.getSinger(),
true
);
EventBus.getDefault().post(event);
}
// 执行平滑滚动(确保 RecyclerView 已经准备好)
rv.post(() -> {
// 确保 RecyclerView 已经布局完成
if (rv.getLayoutManager() != null && rv.getChildCount() > 0) {
android.util.Log.i("HomeFragment", "========== 开始执行滚动动画,目标位置=" + finalNextPos + " ==========");
scrollToTriggerPosition(finalNextPos, rv);
} else {
// RecyclerView 还没准备好,延迟执行
android.util.Log.w("HomeFragment", "RecyclerView 未准备好,延迟执行滚动");
rv.postDelayed(() -> {
if (rv.getLayoutManager() != null) {
android.util.Log.i("HomeFragment", "========== 延迟执行滚动动画,目标位置=" + finalNextPos + " ==========");
scrollToTriggerPosition(finalNextPos, rv);
}
}, 100);
}
});
// 滚动完成后更新 adapter 位置和歌曲信息
rv.postDelayed(() -> {
songTopAdapter.updatePlayingPosition(finalNextPos);
// 确保歌曲信息已更新(防止被其他逻辑覆盖)
if (finalNextPos < musicDataList.size()) {
MusicBean.DataBean currentBean = musicDataList.get(finalNextPos);
tv_song_name.setText(currentBean.getTitle() + "-" + currentBean.getSinger());
}
}, 600);
// 延迟清除自动切换标志
rv.postDelayed(() -> {
isAutoSwitching = false;
}, 1000);
}
/**
* 向左滑动一位(不自动播放)
*/
public void scrollToNextItem() {
scrollToNextItem(false);
}
private void scrollToTriggerPosition(int targetPos, RecyclerView rv) {
LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager();
if (lm == null) {
android.util.Log.e("HomeFragment", "scrollToTriggerPosition: LayoutManager is null!");
return;
}
// 检查目标位置是否有效
if (targetPos < 0 || targetPos >= musicDataList.size()) {
android.util.Log.e("HomeFragment", "scrollToTriggerPosition: 目标位置无效,targetPos=" + targetPos + ", 列表大小=" + musicDataList.size());
return;
}
android.util.Log.i("HomeFragment", "========== scrollToTriggerPosition: 开始平滑滚动到位置 " + targetPos + " ==========");
int targetX = DisplayUtils.dp2px(requireContext(), 50f);
LinearSmoothScroller scroller = new LinearSmoothScroller(requireContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
PointF vector = lm.computeScrollVectorForPosition(targetPosition);
android.util.Log.d("HomeFragment", "computeScrollVectorForPosition: targetPosition=" + targetPosition + ", vector=" + vector);
return vector;
}
@Override
public int calculateDxToMakeVisible(View view, int snapPreference) {
int left = lm.getDecoratedLeft(view);
int right = lm.getDecoratedRight(view);
int center = (left + right) / 2;
int dx = targetX - center;
android.util.Log.d("HomeFragment", "calculateDxToMakeVisible: view位置 left=" + left + ", right=" + right + ", center=" + center + ", 需要移动dx=" + dx);
return dx;
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
// 滚动速度,值越小越快(与定时方式保持一致)
return 100f / displayMetrics.densityDpi;
}
@Override
protected void onStart() {
super.onStart();
android.util.Log.i("HomeFragment", "========== LinearSmoothScroller.onStart() ==========");
}
@Override
protected void onStop() {
super.onStop();
android.util.Log.i("HomeFragment", "========== LinearSmoothScroller.onStop() ==========");
}
};
scroller.setTargetPosition(targetPos);
try {
lm.startSmoothScroll(scroller);
android.util.Log.i("HomeFragment", "========== scrollToTriggerPosition: ✓ 已调用 startSmoothScroll,目标位置=" + targetPos + " ==========");
} catch (Exception e) {
android.util.Log.e("HomeFragment", "scrollToTriggerPosition: 调用 startSmoothScroll 失败", e);
// 如果平滑滚动失败,尝试直接滚动
lm.scrollToPositionWithOffset(targetPos, targetX);
android.util.Log.w("HomeFragment", "scrollToTriggerPosition: 使用 scrollToPositionWithOffset 作为备选方案");
}
}
private void dispatchVisualFeedback(RecyclerView rv, SongTopAdapter adapter) {
LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager();
if (lm == null) return;
int targetX = DisplayUtils.dp2px(requireContext(), 100f);
for (int i = 0; i < rv.getChildCount(); i++) {
View child = rv.getChildAt(i);
if (child == null) continue;
int centerX = (lm.getDecoratedLeft(child) + lm.getDecoratedRight(child)) / 2;
float distance = Math.abs(centerX - targetX);
if (distance > 600) continue;
// float alpha = 1.0f - Math.min(1.0f, distance / 300f);
// float scale = 0.8f + 0.2f * (1.0f - Math.min(1.0f, distance / 200f));
// child.setAlpha(alpha);
// child.setScaleX(scale);
// child.setScaleY(scale);
}
}
private void setupOneWayScroll(RecyclerView rv, Context context) {
final boolean[] hasScrolledLeft = {false};
final float[] startX = {0f};
rv.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
startX[0] = e.getX();
break;
case MotionEvent.ACTION_MOVE:
float dx = e.getX() - startX[0];
if (dx < -20 && !hasScrolledLeft[0]) {
hasScrolledLeft[0] = true;
}
if (hasScrolledLeft[0] && dx > 15) {
Toast.makeText(context, "暂只支持左滑操作", Toast.LENGTH_SHORT).show();
return true;
}
break;
}
return false;
}
});
}
private void setupGestureListener() {
gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(e2.getY() - e1.getY())) {
if (Math.abs(diffX) > 100 && Math.abs(velocityX) > 100) {
nextSkin(); // 滑动换肤
return true;
}
}
return false;
}
});
View.OnTouchListener touchListener = (v, event) -> gestureDetector.onTouchEvent(event);
line.setOnTouchListener(touchListener);
relative.setOnTouchListener(touchListener);
}
private void nextSkin() {
themeManager.nextTheme();
applyCurrentTheme();
// ToastUtil.showShortToast("切换到主题 " + (themeManager.getCurrentThemeIndex() + 1));
}
private void applyCurrentTheme() {
if (!isAdded()) return;
// 只负责换肤:背景等
themeManager.applyThemeTo(line, relative, null, false);
// 单独设置播放按钮图标,使用动态资源
// 关键修复:只有当播放的是首页列表中的歌曲时,才显示"暂停"状态
boolean isFromMainList = !playerManager.isPlayingFromPrivate();
boolean isPlaying = playerManager.isPlaying();
boolean shouldShowPause = isFromMainList && isPlaying;
iv_bf.setImageResource(shouldShowPause ?
themeManager.getPauseIconRes() :
themeManager.getPlayIconRes());
}
/**
* 更新主播放按钮图标(根据实际播放状态)
* 关键修复:只有当播放的是首页列表中的歌曲时,才显示"暂停"状态
* 如果播放的是外部列表的歌曲,显示"播放"状态(待播放)
*/
private void updatePlayButtonIcon() {
if (!isAdded() || iv_bf == null) return;
// 检查当前播放的歌曲是否属于首页列表
boolean isFromMainList = !playerManager.isPlayingFromPrivate();
boolean isPlaying = playerManager.isPlaying();
// 只有当播放的是首页列表中的歌曲且正在播放时,才显示"暂停"状态
// 其他情况(播放外部列表歌曲或未播放)都显示"播放"状态(待播放)
boolean shouldShowPause = isFromMainList && isPlaying;
Log.d("HomeFragment", "🔄 updatePlayButtonIcon: isPlaying=" + isPlaying +
", isFromMainList=" + isFromMainList +
", shouldShowPause=" + shouldShowPause +
", currentTheme=" + themeManager.getCurrentThemeIndex());
iv_bf.setImageResource(shouldShowPause
? themeManager.getPauseIconRes()
: themeManager.getPlayIconRes());
}
private void startRotationForCurrentItem(int position) {
// 先停止任何正在进行的动画
rotationHelper.stopRotation();
// 获取 ViewHolder
RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(position);
if (vh == null) {
// item 当前不可见,可以延迟执行或跳过
return;
}
ImageView coverView = vh.itemView.findViewById(R.id.iv_song_logo);
if (coverView != null) {
rotationHelper.startRotation(coverView); // 开始旋转
}
}
/**
* 启动自动滑动
*/
private void startAutoScroll() {
if (!isAutoScrollEnabled || musicDataList == null || musicDataList.isEmpty()) {
return;
}
// 检查是否在手动滑动后的暂停期内
if (lastManualScrollTime > 0) {
long timeSinceManualScroll = System.currentTimeMillis() - lastManualScrollTime;
if (timeSinceManualScroll < manualScrollPauseDuration) {
// 还在暂停期内,延迟启动
autoScrollHandler.postDelayed(() -> {
if (isAutoScrollEnabled && musicDataList != null && !musicDataList.isEmpty()) {
startAutoScroll();
}
}, manualScrollPauseDuration - timeSinceManualScroll);
return;
}
}
// 如果已经在运行,先停止
stopAutoScroll();
autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (!isAdded() || rv == null || musicDataList == null || musicDataList.isEmpty()) {
return;
}
// 检查是否在手动滑动后的暂停期内
if (lastManualScrollTime > 0) {
long timeSinceManualScroll = System.currentTimeMillis() - lastManualScrollTime;
if (timeSinceManualScroll < manualScrollPauseDuration) {
// 还在暂停期内,延迟执行
if (autoScrollHandler != null && autoScrollRunnable != null) {
autoScrollHandler.postDelayed(autoScrollRunnable, manualScrollPauseDuration - timeSinceManualScroll);
}
return;
}
lastManualScrollTime = 0; // 重置
}
// 停止旋转动画(与歌曲播放完成时保持一致)
rotationHelper.stopRotation();
// 使用 post 确保在主线程执行,避免状态冲突(与歌曲播放完成时保持一致)
rv.post(() -> {
// 执行滑动并自动播放下一首
scrollToNextItem(true);
});
// 继续下一次定时任务
if (autoScrollHandler != null && autoScrollRunnable != null) {
autoScrollHandler.postDelayed(autoScrollRunnable, autoScrollInterval);
}
}
};
// 延迟启动第一次滑动
autoScrollHandler.postDelayed(autoScrollRunnable, autoScrollInterval);
Log.d("HomeFragment", "自动滑动已启动,间隔=" + autoScrollInterval + "ms");
}
/**
* 停止自动滑动
*/
private void stopAutoScroll() {
if (autoScrollHandler != null && autoScrollRunnable != null) {
autoScrollHandler.removeCallbacks(autoScrollRunnable);
autoScrollRunnable = null;
Log.d("HomeFragment", "自动滑动已停止");
}
}
@Override
public void onDestroy() {
// 不再需要停止定时器(使用歌曲播放完成方式)
// stopAutoScroll();
if (autoScrollHandler != null) {
autoScrollHandler.removeCallbacksAndMessages(null); // 清理 Handler
}
playerManager.release();
rotationHelper.stopRotation();
super.onDestroy();
}
@Override
public void onPause() {
super.onPause();
// 页面不可见时不再需要停止定时器(使用歌曲播放完成方式)
// stopAutoScroll();
}
@Override
public void onResume() {
super.onResume();
Log.d("HomeFragment", "onResume called, source = " + NavigationSource.getSource());
// 重新设置播放状态监听器,确保 HomeFragment 的监听器始终生效
// 因为 PrivateAdapter 等可能会覆盖监听器
setupPlaybackListener();
// 关键修复:检查当前播放的歌曲是否属于首页列表
// 先检查必要的对象是否已初始化
if (songTopAdapter == null || musicDataList == null || musicDataList.isEmpty()) {
// 如果适配器或数据列表未初始化,只更新播放按钮状态
updatePlayButtonIcon();
NavigationSource.clear();
return;
}
boolean isFromMainList = !playerManager.isPlayingFromPrivate();
if (isFromMainList && playerManager.isPlaying()) {
// 播放的是首页列表中的歌曲
int currentPos = playerManager.getCurrentPlayingPosition();
if (currentPos >= 0 && currentPos < musicDataList.size()) {
updatePlayButtonIcon();
songTopAdapter.updatePlayingPosition(currentPos);
// 更新歌曲信息显示
MusicBean.DataBean currentSong = musicDataList.get(currentPos);
if (currentSong != null && tv_song_name != null) {
tv_song_name.setText(currentSong.getTitle() + "-" + currentSong.getSinger());
}
// 只有是从「直接点击」进入 LyricsActivity 再返回,才执行滚动和高亮
if (NavigationSource.isDirectClick()) {
applyCurrentTheme();
syncToCurrentPlayingItem(currentPos);
}
}
} else {
// 播放的是外部列表的歌曲或未播放,清除首页的播放状态
songTopAdapter.updatePlayingPosition(-1); // 清除播放位置
if (rotationHelper != null) {
rotationHelper.stopRotation(); // 停止旋转动画
}
updatePlayButtonIcon(); // 更新按钮状态
// 可选:清除标记,避免下次误判
NavigationSource.clear();
}
// 不再使用定时自动滑动,改为歌曲播放完成后自动滑动
// startAutoScroll();
}
/**
* 滚动并高亮当前正在播放的歌曲
*/
private void syncToCurrentPlayingItem(int position) {
if (songTopAdapter == null || rv == null || musicDataList == null || position >= musicDataList.size()) {
return;
}
LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager();
if (layoutManager == null) return;
// 目标 x 坐标:距离左边 50dp
int targetX = DisplayUtils.dp2px(requireContext(), 50f);
LinearSmoothScroller scroller = new LinearSmoothScroller(requireContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return layoutManager.computeScrollVectorForPosition(targetPosition);
}
@Override
public int calculateDxToMakeVisible(View view, int snapPreference) {
// 正确调用:通过 layoutManager 调用
int left = layoutManager.getDecoratedLeft(view);
int right = layoutManager.getDecoratedRight(view);
int center = (left + right) / 2;
// 返回需要移动的距离
return targetX - center;
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
// 控制滚动速度:越小越快
return 100f / displayMetrics.densityDpi; // 可调
}
};
scroller.setTargetPosition(position);
layoutManager.startSmoothScroll(scroller);
// 延迟查找 ViewHolder 并启动旋转
rv.postDelayed(() -> {
RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(position);
if (vh != null) {
ImageView coverView = vh.itemView.findViewById(R.id.iv_song_logo);
if (coverView != null) {
rotationHelper.stopRotation();
rotationHelper.startRotation(coverView);
}
}
}, 350); // 等待滚动接近完成
}
private void notifyLiLvFragmentRefresh() {
// 假设你通过某种方式获取到 LiLvFragment 实例
// 方法一:通过 Activity 管理
Fragment lilvFragment = getParentFragmentManager().findFragmentByTag("LILV_FRAGMENT");
if (lilvFragment instanceof LiLvFragment) {
((LiLvFragment) lilvFragment).refreshData();
}
}
}
切换主题多加一个 private int[] background = {
R.mipmap.img_lan_mh,
R.mipmap.img_lv_mh_bg,
R.mipmap.img_hong_mh
};