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.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.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> musicDataList = new ArrayList<>();
private List<MusicBean.DataBean> privateSongList;//私人播放列表字段
private List<MusicBean.DataBean> qySongList;//轻音乐播放列表字段
private List<MusicBean.DataBean> xzSongList;//小众音乐播放列表字段
private GestureDetector gestureDetector;
private PrivateAdapter privateAdapter;
private MainActivity mActivity;
@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();
// 跑马灯
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;
}
if (playerManager.isPlaying() && isMainPlaybackActive) {
playerManager.pause();
// 如果暂停了主播放,可以视为退出主控模式(可选)
isMainPlaybackActive = false;
} else {
isMainPlaybackActive = true; // 标记为主控模式
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);
}
});
}
@Override
protected void initData() {
updateTimeGreeting();
musicAppInfo();
playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() {
@Override
public void onPlaying(int position) {
if (!playerManager.isPlayingFromPrivate()) {
updatePlayButtonIcon();
} else {
String tag = playerManager.getCurrentPlaylistTag();
if ("private".equals(tag)) {
int idx = playerManager.getCurrentExternalIndex();
privateAdapter.updatePlayingPosition(idx, true);
}
}
startRotationForCurrentItem(position);
}
@Override
public void onPaused() {
if (!playerManager.isPlayingFromPrivate()) {
updatePlayButtonIcon();
} else {
String tag = playerManager.getCurrentPlaylistTag();
if ("private".equals(tag)) {
int idx = playerManager.getCurrentExternalIndex();
privateAdapter.updatePlayingPosition(idx, false);
}
}
rotationHelper.stopRotation();
}
@Override
public void onCompletion() {
String currentTag = playerManager.getCurrentPlaylistTag();
Log.d("HomeFragment", "onCompletion: 当前播放来源 = " + currentTag);
Log.d("HomeFragment", "onCompletion: 开始播放下一首");
if ("private".equals(currentTag)) {
// 正在播放私人列表
boolean hasNext = playerManager.playNextInExternalList();
if (hasNext) {
int nextIdx = playerManager.getCurrentExternalIndex();
privateAdapter.updatePlayingPosition(nextIdx, true);
} else {
// 循环播放第一首
playerManager.playFromExternalList(requireContext(), privateSongList, 0, "private");
privateAdapter.updatePlayingPosition(0, true);
}
}
// 其他 tag 可扩展(如 qingyin、xiaozhong)
else {
Log.d("HomeFragment", "onCompletion: 即将调用 playNextSong()");
// 默认行为:播放主列表下一首
playNextSong();
}
rotationHelper.stopRotation();
}
@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()) {
musicDataList = response.getData();
// 缓存主歌单
MusicCache.setMainMusicList(musicDataList);
setupMusicRecyclerView();
notifyLiLvFragmentRefresh();
} 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());
});
// 设置点击事件:点击 item 播放该歌曲
// privateAdapter.setOnItemClickListener((position, dataBean) -> {
// playerManager.playFromExternalList(requireContext(), privateSongList, position, "private");
// playerManager.setPlayingFromPrivate(true);
// ToastUtil.showShortToast("播放: " + dataBean.getTitle());
// });
// 设置横向 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());
// 跳转到 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());
// 跳转到 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());
// 跳转到 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;
}
int pos = findBestObscuredItem(recyclerView, fixedTargetX);
if (pos != RecyclerView.NO_POSITION && pos != lastPlayedPosition.get()) {
playMusicAtPosition(pos);
lastPlayedPosition.set(pos);
}
dispatchVisualFeedback(recyclerView, adapter);
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
boolean isPlayingBefore = playerManager.isPlaying();
if (newState == RecyclerView.SCROLL_STATE_DRAGGING ||
newState == RecyclerView.SCROLL_STATE_SETTLING) {
if (isPlayingBefore) {
playerManager.pause();
rotationHelper.stopRotation();
updatePlayButtonIcon();
}
}
if (newState == RecyclerView.SCROLL_STATE_IDLE && isPlayingBefore) {
playerManager.resume();
startRotationForCurrentItem(playerManager.getCurrentPlayingPosition());
updatePlayButtonIcon();
}
}
});
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);
nextSkin(); // 每次播放新歌就换主题
playerManager.play(requireContext(), position, bean.getMusic());
//使用 post() 延迟更新 adapter,避免在 layout 过程中修改
rv.post(() -> {
songTopAdapter.updatePlayingPosition(position);
// 同时更新底部显示
tv_song_name.setText(bean.getTitle() + "-" + bean.getSinger());
});
}
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);
// 自动播放下一首
playMusicAtPosition(nextPos);
// 滚动 RecyclerView 到目标位置
scrollToTriggerPosition(nextPos, rv);
}
private void scrollToTriggerPosition(int targetPos, RecyclerView rv) {
LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager();
if (lm == null) return;
LinearSmoothScroller scroller = new LinearSmoothScroller(requireContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return lm.computeScrollVectorForPosition(targetPosition);
}
@Override
public int calculateDxToMakeVisible(View view, int snapPreference) {
int left = lm.getDecoratedLeft(view);
int targetX = DisplayUtils.dp2px(requireContext(), 50f); // 目标左边缘
return targetX - left; // 让 view.left 移动到 targetX
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 150f / displayMetrics.densityDpi;
}
};
scroller.setTargetPosition(targetPos);
lm.startSmoothScroll(scroller);
}
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);
// 单独设置播放按钮图标,使用动态资源
iv_bf.setImageResource(playerManager.isPlaying() ?
themeManager.getPauseIconRes() :
themeManager.getPlayIconRes());
}
/**
* 更新主播放按钮图标(根据实际播放状态)
*/
private void updatePlayButtonIcon() {
if (!isAdded()) return;
boolean isPlaying = playerManager.isPlaying();
Log.d("HomeFragment", "🔄 updatePlayButtonIcon: isPlaying=" + isPlaying +
", currentTheme=" + themeManager.getCurrentThemeIndex());
iv_bf.setImageResource(isPlaying
? 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); // 开始旋转
}
}
@Override
public void onDestroy() {
playerManager.release();
rotationHelper.stopRotation();
super.onDestroy();
}
@Override
public void onResume() {
super.onResume();
Log.d("HomeFragment", "onResume called, source = " + NavigationSource.getSource());
// 只有是从「直接点击」进入 LyricsActivity 再返回,才执行以下逻辑
if (NavigationSource.isDirectClick()) {
updatePlayButtonIcon();
applyCurrentTheme();
if (playerManager.isPlaying() && !playerManager.isPlayingFromPrivate()) {
int currentPos = playerManager.getCurrentPlayingPosition();
syncToCurrentPlayingItem(currentPos);
}
} else {
// 其他路径返回,不执行自动滚动和高亮
updatePlayButtonIcon(); // 至少更新按钮状态
// 可选:清除标记,避免下次误判
NavigationSource.clear();
// Log.d("HomeFragment", "非直接路径返回,跳过 syncToCurrentPlayingItem");
}
}
/**
* 滚动并高亮当前正在播放的歌曲
*/
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();
}
}
}
package com.weishitech.qichechangtingyinyue.utils;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import androidx.annotation.NonNull;
import com.weishitech.qichechangtingyinyue.bean.MusicBean;
import java.util.List;
public class MusicPlayerManager {
private static volatile MusicPlayerManager instance; // 双检锁
private MediaPlayer mediaPlayer;
private OnPlaybackStateChangedListener listener;
private int currentPlayingPosition = -1; // 主列表位置
private boolean isPlayingFromPrivate = false;
// 外部播放信息
private List<MusicBean.DataBean> currentExternalList;
private String currentPlaylistTag; // "private", "qingyin", "xiaozhong"
private int currentExternalIndex = -1;
private String currentPlayingUrl = null;
// 私有构造
private MusicPlayerManager() {
// 不再传 context,MediaPlayer 不依赖 Activity Context
}
// 获取单例
public static MusicPlayerManager getInstance() {
if (instance == null) {
synchronized (MusicPlayerManager.class) {
if (instance == null) {
instance = new MusicPlayerManager();
}
}
}
return instance;
}
// 提供对外接口...
public boolean isPlayingFromPrivate() { return isPlayingFromPrivate; }
public void setPlayingFromPrivate(boolean flag) { this.isPlayingFromPrivate = flag; }
public String getCurrentPlayingMusicUrl() { return currentPlayingUrl; }
public int getCurrentExternalIndex() { return currentExternalIndex; }
public String getCurrentPlaylistTag() { return currentPlaylistTag; }
public interface OnPlaybackStateChangedListener {
void onPlaying(int position);
void onPaused();
void onCompletion();
void onError(String errorMsg);
}
public void setOnPlaybackStateChangedListener(OnPlaybackStateChangedListener listener) {
this.listener = listener;
}
// 播放主列表歌曲
public void play(Context context, int position, String musicUrl) {
if (position == currentPlayingPosition && mediaPlayer != null && mediaPlayer.isPlaying()) {
return;
}
try {
prepareAndPlay(musicUrl, () -> {
currentPlayingPosition = position;
currentPlayingUrl = musicUrl;
isPlayingFromPrivate = false;
currentPlaylistTag = "main"; // <<< 关键:设置为 "main"
if (listener != null) listener.onPlaying(position);
});
} catch (Exception e) {
e.printStackTrace();
if (listener != null) listener.onError("无法播放音乐");
}
}
/**
* 播放外部列表(支持多次调用切换源)
*/
public void playFromExternalList(Context context, @NonNull List<MusicBean.DataBean> list, int startIndex, String tag) {
try {
if (startIndex < 0 || startIndex >= list.size()) {
throw new IndexOutOfBoundsException("Invalid start index: " + startIndex);
}
MusicBean.DataBean bean = list.get(startIndex);
String newUrl = bean.getMusic();
// 关键:无论是否是同一个列表,只要 URL 不同就重新播放
if (mediaPlayer != null && mediaPlayer.isPlaying() && newUrl.equals(currentPlayingUrl)) {
// 同一首歌 → 只更新元数据,不重播
currentExternalList = list;
currentExternalIndex = startIndex;
currentPlaylistTag = tag;
isPlayingFromPrivate = true;
if (listener != null) listener.onPlaying(-1);
} else {
// 不同歌曲 or 未播放 → 重置并准备新音频
prepareAndPlay(newUrl, () -> {
currentPlayingPosition = -1; // 不属于主列表
currentPlayingUrl = newUrl;
isPlayingFromPrivate = true;
currentExternalList = list;
currentExternalIndex = startIndex;
currentPlaylistTag = tag;
if (listener != null) listener.onPlaying(-1);
});
}
} catch (Exception e) {
e.printStackTrace();
if (listener != null) listener.onError("无法播放音乐: " + e.getMessage());
}
}
/**
* 公共方法:准备并播放(复用 MediaPlayer)
*/
private void prepareAndPlay(String musicUrl, Runnable onPreparedAction) throws Exception {
boolean needNewPlayer = mediaPlayer == null;
if (needNewPlayer) {
mediaPlayer = new MediaPlayer();
setupListeners();
} else if (musicUrl.equals(currentPlayingUrl) && !mediaPlayer.isPlaying()) {
// 已加载过此 URL,直接 start
mediaPlayer.start();
onPreparedAction.run();
return;
} else {
// 不同 URL,重置并重新加载
mediaPlayer.reset();
setupListeners(); //reset 后必须重新设置监听器!
}
mediaPlayer.setDataSource(musicUrl);
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mp -> {
mp.start();
currentPlayingUrl = musicUrl;
onPreparedAction.run();
});
}
private void setupListeners() {
mediaPlayer.setOnCompletionListener(mp -> {
if (listener != null) listener.onCompletion();
});
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
if (listener != null) listener.onError("播放错误: " + what);
return true;
});
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
if (listener != null) listener.onPaused();
}
}
public void resume() {
if (mediaPlayer != null && !mediaPlayer.isPlaying() && currentPlayingUrl != null) {
mediaPlayer.start();
if (listener != null) listener.onPlaying(isPlayingFromPrivate ? -1 : currentPlayingPosition);
}
}
public boolean isPlaying() {
return mediaPlayer != null && mediaPlayer.isPlaying();
}
public int getCurrentPlayingPosition() {
return currentPlayingPosition;
}
public boolean playNextInExternalList() {
if (currentExternalList == null || currentExternalIndex < 0) return false;
int nextIndex = (currentExternalIndex + 1) % currentExternalList.size(); // 循环
MusicBean.DataBean bean = currentExternalList.get(nextIndex);
try {
prepareAndPlay(bean.getMusic(), () -> {
currentPlayingPosition = -1;
currentPlayingUrl = bean.getMusic();
currentExternalIndex = nextIndex;
isPlayingFromPrivate = true;
if (listener != null) listener.onPlaying(-1);
});
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void release() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
currentPlayingPosition = -1;
currentPlayingUrl = null;
currentExternalIndex = -1;
currentPlaylistTag = null;
currentExternalList = null;
}
// 新增:获取当前播放时间
public int getCurrentPosition() {
if (mediaPlayer != null) {
return mediaPlayer.getCurrentPosition();
}
return 0;
}
// 新增:获取总时长
public int getDuration() {
if (mediaPlayer != null) {
return mediaPlayer.getDuration();
}
return 0;
}
// 新增:跳转到指定位置
public void seekTo(int milliseconds) {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(milliseconds);
}
}
}
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[] 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];
}
}
滑动列表播放,播放完第一首,没有自动滑动到下一个歌曲播放没有走public void onCompletion()方法
最新发布