public class HomeFragment extends BaseFragment {
RecyclerView rv,sr_rv, qy_rv, xz_rv;
ImageView iv_ss, iv_gd, sr_start, qy_start, xz_start,iv_bf;
TextView tv_time,tv_song_name;
private MediaPlayer mediaPlayer;
private int currentPlayingPosition = -1; // 初始值设为 -1,表示没有播放
private boolean isScrollInProgress = false; // 防止重复滚动
private ObjectAnimator rotationAnimator;
private SongTopAdapter songTopAdapter;
private ImageView currentRotationView;
private boolean isPlayingState = false; // 记录当前是否处于“正在播放”的逻辑状态
private boolean wasPlayingBeforeScroll = false; // 是否在滑动前是播放状态
@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);
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);
}
@Override
protected void initClick() {
//跳转搜索页面
iv_ss.setOnClickListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
toClass(SearchActivity.class);
}
});
// 设置点击事件:切换播放/暂停
iv_bf.setOnClickListener(v -> {
if (mediaPlayer == null) return;
if (mediaPlayer.isPlaying()) {
// 当前正在播放 → 暂停
mediaPlayer.pause();
isPlayingState = false;
iv_bf.setImageResource(R.mipmap.img_lan_bf); // 显示“播放”图标
stopRotationAnimation(); // 停止旋转动画
ToastUtil.showShortToast("已暂停");
} else {
// 当前暂停 → 继续播放
mediaPlayer.start();
isPlayingState = true;
iv_bf.setImageResource(R.mipmap.img_lan_zt); // 显示“暂停”图标
// 启动旋转:需要获取当前播放项的封面
// startRotationForCurrentItem(currentPlayingPosition);
ToastUtil.showShortToast("继续播放");
}
});
}
@Override
protected void initData() {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY); // 获取 24 小时制的小时
String greeting;
if (hour >= 5 && hour < 11) {
greeting = "HI,早上好";
} else if (hour == 11) {
greeting = "HI,中午好";
} else if (hour == 12) {
greeting = "HI,下午好";
} else if (hour >= 13 && hour < 18) {
greeting = "HI,下午好";
} else { // hour >= 18 或 hour < 5(凌晨)
greeting = "HI,晚上好";
}
tv_time.setText(greeting);
musicAppInfo();
}
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 (response.getCode().equals("0")) {
if (null != response.getData() && response.getData().size() > 0) {
// 1. 创建 Adapter
songTopAdapter = new SongTopAdapter();
// 2. 设置布局管理器和适配器
rv.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
rv.setAdapter(songTopAdapter);
// 3. 【关键】先设置播放状态监听器(必须在 setup 前!)
songTopAdapter.setOnPlayStateChangedListener((position, coverView) -> {
Log.d("Rotation", "收到播放通知: position=" + position);
stopRotationAnimation(); // 停止旧动画
startRotationAnimation(coverView); // 启动新动画
});
// 4. 【重要】现在才能调用 setupSnappingAndPlayback
// 因为这里面会触发滚动检测 → 可能立即调用 playMusicAtPosition → 需要监听器已准备好!
setupSnappingAndPlayback(rv, songTopAdapter);
// 5. 最后设置数据(避免提前触发 convert 导致空指针)
songTopAdapter.setList(response.getData());
} else {
ToastUtil.showShortToast("暂无歌曲数据");
}
} else {
ToastUtil.showShortToast(response.getMessage());
}
}
});
}
// ================== 滚动监听 + 自动播放 ==================
private void setupSnappingAndPlayback(RecyclerView rv, SongTopAdapter adapter) {
LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager();
if (layoutManager == null) return;
int fixedTargetX = dp2px(50f); // 模糊图右边界
// 使用 SnapHelper(保留吸附动画)
FixedSideSnapHelper snapHelper = new FixedSideSnapHelper(fixedTargetX);
snapHelper.attachToRecyclerView(rv);
// 新增:记录已触发播放的位置,防止重复
final AtomicInteger lastPlayedPosition = new AtomicInteger(RecyclerView.NO_POSITION);
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int pos = findBestObscuredItem(recyclerView, fixedTargetX);
if (pos != RecyclerView.NO_POSITION && pos != lastPlayedPosition.get()) {
playMusicAtPosition(pos, adapter.getData());
lastPlayedPosition.set(pos);
}
dispatchVisualFeedback(recyclerView, adapter);
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_DRAGGING ||
newState == RecyclerView.SCROLL_STATE_SETTLING) {
// 用户开始滑动或惯性滑动 → 暂停音乐和动画
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
wasPlayingBeforeScroll = true; // 记录原来是播放状态
stopRotationAnimation();
iv_bf.setImageResource(R.mipmap.img_lan_bf); // 更新按钮图标
Log.d("ScrollPause", "滑动中暂停音乐");
} else {
wasPlayingBeforeScroll = false;
}
isScrollInProgress = true;
}
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// 滑动结束 → 如果原来是播放状态,则恢复
isScrollInProgress = false;
if (wasPlayingBeforeScroll && mediaPlayer != null) {
mediaPlayer.start();
iv_bf.setImageResource(R.mipmap.img_lan_zt);
startRotationForCurrentItem(currentPlayingPosition);
Log.d("ScrollResume", "滑动结束,恢复播放");
}
}
}
});
setupOneWayScroll(rv, rv.getContext());
}
private void dispatchVisualFeedback(RecyclerView rv, SongTopAdapter adapter) {
LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager();
if (layoutManager == null) return;
int targetX = dp2px(100f); // 模糊图右侧位置
for (int i = 0; i < rv.getChildCount(); i++) {
View child = rv.getChildAt(i);
if (child == null) continue;
int left = layoutManager.getDecoratedLeft(child);
int right = layoutManager.getDecoratedRight(child);
int centerX = (left + right) / 2;
float distance = Math.abs(centerX - targetX);
// 只处理附近的 item
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);
}
}
/**
* 查找当前是否有 item 被模糊图遮挡其左半部分约 50%
* 假设模糊图固定显示在 [0, fuzzyRightEdge] 区域内(例如宽度 100dp)
*/
private int findBestObscuredItem(RecyclerView rv, int fuzzyRightEdge) {
LinearLayoutManager layoutManager = (LinearLayoutManager) rv.getLayoutManager();
if (layoutManager == null) return RecyclerView.NO_POSITION;
int childCount = layoutManager.getChildCount();
int bestPos = RecyclerView.NO_POSITION;
float minDiffToHalf = Float.MAX_VALUE;
for (int i = 0; i < childCount; i++) {
View child = layoutManager.getChildAt(i);
if (child == null) continue;
int left = layoutManager.getDecoratedLeft(child);
int right = layoutManager.getDecoratedRight(child);
int width = right - left;
// 必须有交集:item 必须与模糊图区域 [0, fuzzyRightEdge] 相交
if (right <= 0 || left >= fuzzyRightEdge) continue; // 无交集
// 计算重叠区域:模糊图 [0, fuzzyRightEdge] 与 item [left, right]
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 < minDiffToHalf) {
minDiffToHalf = diff;
bestPos = layoutManager.getPosition(child);
}
}
return bestPos;
}
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 currentX = e.getX();
float dx = currentX - startX[0]; // 手指移动距离
if (dx < -20 && !hasScrolledLeft[0]) {
// 用户向左滑动(内容向右移出视野),视为“已前进”
hasScrolledLeft[0] = true;
}
// 如果已经左滑过,则禁止任何右滑(手指向右拖)
if (hasScrolledLeft[0] && dx > 15) {
// 检测到右滑意图 → 拦截事件,不交给 RecyclerView
Toast.makeText(context, "暂只支持左滑操作", Toast.LENGTH_SHORT).show();
return true; // 拦截触摸事件,防止 RecyclerView 滚动
}
break;
}
return false; // 正常处理其他情况
}
});
}
private void playMusicAtPosition(int position, List<MusicBean.DataBean> dataList) {
if (position == RecyclerView.NO_POSITION || position >= dataList.size()) return;
MusicBean.DataBean bean = dataList.get(position);
currentPlayingPosition = position;
try {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
} else {
if (mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.setOnPreparedListener(null);
mediaPlayer.setOnCompletionListener(null);
}
mediaPlayer.setDataSource(bean.getMusic());
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mp -> {
mp.start();
isPlayingState = true;
iv_bf.setImageResource(R.mipmap.img_lan_zt); // 播放时显示暂停图标
});
mediaPlayer.setOnCompletionListener(mp -> {
Log.d("AutoPlay", "歌曲播放完成: " + bean.getTitle());
playNextSong(dataList);
});
// 通知 Adapter 刷新界面(触发 convert)
songTopAdapter.updatePlayingPosition(position);
// 尝试获取当前可见的 itemView 上的 ImageView 并启动旋转
// startRotationForCurrentItem(position);
Log.d("AutoPlay", "正在播放: " + bean.getTitle());
ToastUtil.showShortToast("播放: " + bean.getTitle());
tv_song_name.setText(bean.getTitle()+"-"+bean.getSinger());
// 在 playMusicAtPosition 方法末尾
iv_bf.setImageResource(R.mipmap.img_lan_zt); // 新歌开始播,设为暂停图标
} catch (Exception e) {
e.printStackTrace();
ToastUtil.showShortToast("无法播放");
playNextSong(dataList);
}
}
private void playNextSong(List<MusicBean.DataBean> dataList) {
int nextPos = currentPlayingPosition + 1;
if (nextPos < dataList.size()) {
playMusicAtPosition(nextPos, dataList);
scrollToTriggerPosition(nextPos, rv); // 自动滚动到触发位置
} else {
ToastUtil.showShortToast("已播放完全部歌曲");
}
}
private void scrollToTriggerPosition(int targetPos, RecyclerView recyclerView) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (layoutManager == null) return;
LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) {
private static final float TARGET_OFFSET = 80f; // 调整此值
@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;
int targetX = dp2px(50f); // 模糊图右边界的 X 坐标
return targetX - center; // 偏移量
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 150f / displayMetrics.densityDpi;
}
};
scroller.setTargetPosition(targetPos);
layoutManager.startSmoothScroll(scroller);
}
private int dp2px(float dp) {
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dp,
rv.getResources().getDisplayMetrics()
);
}
/**
* 启动封面旋转动画
*/
private void startRotationAnimation(ImageView imageView) {
if (imageView == null || imageView.getDrawable() == null) return;
// 先清除旧动画
if (rotationAnimator != null && rotationAnimator.isRunning()) {
rotationAnimator.cancel();
}
// 方法一:使用 ObjectAnimator(保留,但需设置 LayerType)
rotationAnimator = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f);
rotationAnimator.setDuration(10000); // 10秒一圈
rotationAnimator.setRepeatCount(ObjectAnimator.INFINITE);
rotationAnimator.setInterpolator(new LinearInterpolator());
// 关键一步:启用硬件层加速(否则某些设备上动画卡顿或不显示)
imageView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
rotationAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
imageView.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
rotationAnimator.start();
}
/**
* 停止旋转动画
*/
private void stopRotationAnimation() {
if (rotationAnimator != null) {
rotationAnimator.cancel();
rotationAnimator = null;
}
if (currentRotationView != null) {
currentRotationView.setLayerType(View.LAYER_TYPE_NONE, null);
currentRotationView = null;
}
}
/**
* 根据 position 手动启动该 itemView 的旋转动画(用于恢复播放)
*/
private void startRotationForCurrentItem(int position) {
if (position == RecyclerView.NO_POSITION || songTopAdapter == null) return;
RecyclerView.ViewHolder viewHolder = rv.findViewHolderForAdapterPosition(position);
if (viewHolder != null) {
ImageView coverView = viewHolder.itemView.findViewById(R.id.iv_song_logo); // 替换为你的封面ID
if (coverView != null) {
stopRotationAnimation(); // 安全起见先停
startRotationAnimation(coverView);
}
} else {
// 如果 item 不可见,通过 adapter 回调间接启动(convert 会触发)
Log.d("Rotation", "目标 itemView 不可见,等待 convert 触发");
}
}
@Override
public void onDestroy() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
super.onDestroy();
}
}
public class SongTopAdapter extends RecyclerView.Adapter<SongTopAdapter.DeliveryViewHolder> {
private List<MusicBean.DataBean> dataList = new ArrayList<>();
private int currentPlayingPosition = -1;
// 播放状态监听器
public interface OnPlayStateChangedListener {
void onPlayingAtPosition(int position, ImageView coverView);
}
private OnPlayStateChangedListener playStateListener;
public void setOnPlayStateChangedListener(OnPlayStateChangedListener listener) {
this.playStateListener = listener;
}
// 设置数据(替代 setList)
public void setList(List<MusicBean.DataBean> list) {
this.dataList.clear();
if (list != null) {
this.dataList.addAll(list);
}
notifyDataSetChanged();
}
public List<MusicBean.DataBean> getData() {
return dataList;
}
public int getCurrentPlayingPosition() {
return currentPlayingPosition;
}
public void updatePlayingPosition(int pos) {
int oldPos = currentPlayingPosition;
currentPlayingPosition = pos;
// 通知旧位置和新位置刷新
if (oldPos >= 0 && oldPos < dataList.size()) {
notifyItemChanged(oldPos);
}
if (pos >= 0 && pos < dataList.size()) {
notifyItemChanged(pos);
}
}
// ViewHolder 类
public static class DeliveryViewHolder extends RecyclerView.ViewHolder {
ImageView ivCover;
public DeliveryViewHolder(@NonNull View itemView) {
super(itemView);
ivCover = itemView.findViewById(R.id.iv_song_logo);
}
}
@NonNull
@Override
public DeliveryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.song_top_adapter, parent, false);
return new DeliveryViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull DeliveryViewHolder holder, int position) {
MusicBean.DataBean dataBean = dataList.get(position);
// 使用 Glide 加载封面
Glide.with(holder.itemView.getContext())
.load(dataBean.getCover())
.transform(new CircleCrop())
.error(getErrorDrawable(holder.itemView.getContext()))
.into(holder.ivCover);
boolean isPlaying = (position == currentPlayingPosition);
if (isPlaying && playStateListener != null) {
holder.ivCover.post(() -> playStateListener.onPlayingAtPosition(position, holder.ivCover));
}
}
@Override
public int getItemCount() {
return dataList.size();
}
// 静态错误图缓存(防止重复创建)
private static BitmapDrawable sErrorDrawable;
private BitmapDrawable getErrorDrawable(Context context) {
if (sErrorDrawable == null) {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.img_home_sing);
Bitmap circularBitmap = ImageUtils.getCircularBitmap(bitmap);
sErrorDrawable = new BitmapDrawable(context.getResources(), circularBitmap);
}
return sErrorDrawable;
}
}
保持现有逻辑,其中有两张歌曲图片是因为添加的错误图片没有旋转动画,怎么修改让他也有旋转动画 .error(getErrorDrawable(holder.itemView.getContext()))
最新发布