使用java.text包格式化数字和日期-ZT

本文介绍了Java中格式化输出的方法。在Java里,格式化输出需使用java.text包中的类。NumberFormat类可格式化整数、小数、货币和百分比,DecimalFormat可定制数字格式化。DateFormat和SimpleDateFormat分别用于默认和定制日期格式化,还给出了Demo程序及输出结果。
转自优快云友blog“飞翔的天空”——
 

C中可以使用类似printf(“%d %8.2f/n”, 1001, 52.335)的方法实现格式化输出,可是Java中的System.out.println()并没有对应的功能。要格式化输出,必须使用java.text包中的类来实现类似的操作(要不怎么体现面向对象的优越性呢,不过据说jdk1.5准备又补上)。当然了,java.text包的功能还是很强大的,奇怪的是很多书中都没有涉及,而一般谁又有工夫整天去看API

 

注意:由于这里说得很简略,因此请参照下面的Demo程序。

 

格式化数字

NumberFormat类中为我们提供了格式化4种数字的方法:整数、小数、货币和百分比,通过工厂方法getNumberInstance, getNumberIntance, getCurrencyInstance, getPercentInstance方法获得相应的实例对象就行。例如我们要以字符串表示人民币88888.88元,这样来写就行:

NumberFormat nf = NumberFormat.getCurrencyInstance();

System.out.println(nf.format(88888.88));

 

定制格式化数字

可是对于稍微复杂一点的需求,NumberFormat就满足不了了,幸好java还提供了DecimalFormat实现定制的格式化。要使用DecimalFormat对象,必须提供给它提供一个格式化的模式(pattern)

String pattern = …

DecimalFormat df = new DecimalFormat(pattern);

或者:

DecimalFormat df = new DecimalFormat();

df. applyPattern(pattern);

然后就调用它的format方法就行了。

所以关键就是这个模式怎么定义。在DecimalFormat类的JavaDoc中有模式的语法表示,不过很难说清楚(是我说不清楚,呵呵),请看看Demo自己多试试吧。下面是模式中某些字符的含义表:

字符

含义

0

一位数字,这一位缺失显示为0。用来补零

#

一位数字, 这一位缺失就不显示

.

小数点,不用多说了吧

,

千位分隔符

E

科学计数法

%

百分比

 

格式化日期

把日期转化为字符串最简单的方法就是调用Date类的toString或者toLocaleString方法:

System.out.println(new Date());   

输出:2004-8-7 8:16:14。可是如果我们想把月和日补成2位不要时分秒2004-08-07,这就不灵了。java.text.DateFormat提供了大量的工厂方法:getDateInstance(int style), getTimeInstance(int style), getDateTimeInstance(int dateStyle, int timeStyle)等等。其中style必须是DateFormat.LONG, DateFormat.MEDIUM, DateFormat.SHORT之一。Demo中的defaultDateFormat方法作了一个简单的实验。

 

定制格式化日期:

同样,java.text.SimpleDateFormat可以通过模式(pattern)实现定制格式化:

String pattern = …

SimpleDateFormat df = new SimpleDateFormat(pattern);

或者:

SimpleDateFormat df = new SimpleDateFormat();

df. applyPattern(pattern);

下面是SimpleDateFormatjavadoc中的一个模式符号简表:

符号

意义

合法数值

示例

y

Year

Year

1996; 96

M

Month in year

Month

July; Jul; 07

d

Day in month

Number

10

a

Am/pm marker

Text

PM

H

Hour in day (0-23)

Number

0

h

Hour in am/pm (1-12)

Number

12

m

Minute in hour

Number

30

s

Second in minute

Number

55

S

Millisecond

Number

978

z

Time zone

General time zone

Pacific Standard Time; PST; GMT-08:00

Z

Time zone

RFC 822 time zone

-0800

注意的是,符号的大小写意义是不同的,符号的个数也会导致输出不一样。例如用MM就会把1月份显示成01,而用M则不会补零。对于年份,两个yy会只输出两位年份,yyyy则会输出4位年份。

 

实际上,上面的类还提供了很多其他方法,特别是用于本地化(Locale)定制格式化的方法,以及从字符串表示转化为相应对象的parse方法,还有把格式化结果附加到一个StringBuffer的方法(应该是用来提高性能)。

 

最后是一个小Demo和输出结果:

TestFormat.java

import java.text.*;

import java.util.*;

 

public class TestFormat {

 

    public static void main(String[] args) {

       defaultNumberFormat();

       System.out.println();

      

       customNumberFormat();

       System.out.println();

      

       defaultDateFormat();

       System.out.println();

 

       customDateFormat();

       System.out.println();

      

    }

   

    public static void defaultNumberFormat() {

       int i = 123456;

       double x = 882323.23523;

       double p = 0.528;

       double c = 52.83;

 

       NumberFormat nf = NumberFormat.getInstance();

       System.out.println("Integer " + i + " is displayed as " + nf.format(i));

       System.out.println("Double " + x + " is displayed as " + nf.format(x));

 

       NumberFormat nfInt = NumberFormat.getIntegerInstance();

       System.out.println("Integer " + i + " is displayed as " + nfInt.format(i));

      

       NumberFormat nfNumber = NumberFormat.getNumberInstance();

       System.out.println("Double " + x + " is displayed as " + nfNumber.format(x));

      

       NumberFormat nfPercent = NumberFormat.getPercentInstance();

       System.out.println("Percent " + p + " is displayed as " + nfPercent.format(p));

      

       NumberFormat nfCurrency = NumberFormat.getCurrencyInstance();

       System.out.println("Currency " + p + " is displayed as " + nfCurrency.format(c));      

      

       //这里没有涉及相应的parse方法

    }

   

    public static void customNumberFormat() {

       double x = 1000.0 / 3;

       System.out.println("default output is " + x);

       patternPrint("###,###.##", x);

       patternPrint("####.##", x);

       patternPrint("####.00", x);

       patternPrint("####.0#", x);

       patternPrint("00000.##", x);

       patternPrint("$###,###.##", x);

        patternPrint("0.###E0", x);

       patternPrint("00.##%", x);

 

       double y = 23.0012;

       System.out.println("default output is " + y);

       patternPrint("###,###.##", y);

       patternPrint("####.##", y);

       patternPrint("####.00", y);

       patternPrint("####.0#", y);

       patternPrint("00000.##", y);

       patternPrint("$###,###.##", y);

       patternPrint("0.###E0", y);

       patternPrint("00.##%", y);

    }

   

    public static void patternPrint(String pattern, double x) {

       DecimalFormat df = new DecimalFormat(pattern);

       System.out.println("output for pattern " + pattern + " is " + df.format(x));

    }

   

    public static void defaultDateFormat(){

       Date date = new Date();

      

       System.out.println("simple date " + date.toLocaleString());

      

       DateFormat df = DateFormat.getDateTimeInstance();

       System.out.println(df.format(date));

      

       DateFormat dfLong = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);

       System.out.println(dfLong.format(date));

      

       DateFormat dfMedium = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,

           DateFormat.MEDIUM);

       System.out.println(dfMedium.format(date));

 

       DateFormat dfShort = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);

       System.out.println(dfShort.format(date));

    }

   

    public static void customDateFormat() {

       Date date = new Date();

       patternPrint("yyyy.MM.dd HH:mm:ss z", date);  //两个MM, dd会导致补零

       patternPrint("yyMd HHmm", date);  //两个yy就显示为两位年份

       patternPrint("EEE, MMM d, ''yy", date);

       patternPrint("h:mm a", date);

       patternPrint("hh 'o''clock' a, zzzz", date);

       patternPrint("yyyyy.MMMMM.dd GGG hh:mm aaa", date);

       patternPrint("EEE, d MMM yyyy HH:mm:ss Z", date);

       patternPrint("yyMMddHHmmssZ", date);

    }

   

    public static void patternPrint(String pattern, Date date){

       SimpleDateFormat df = new SimpleDateFormat(pattern);

       System.out.println(df.format(date));

    }

}

 

输出:

Integer 123456 is displayed as 123,456

Double 882323.23523 is displayed as 882,323.235

Integer 123456 is displayed as 123,456

Double 882323.23523 is displayed as 882,323.235

Percent 0.528 is displayed as 53%

Currency 0.528 is displayed as 52.83

 

default output is 333.3333333333333

output for pattern ###,###.## is 333.33

output for pattern ####.## is 333.33

output for pattern ####.00 is 333.33

output for pattern ####.0# is 333.33

output for pattern 00000.## is 00333.33

output for pattern $###,###.## is $333.33

output for pattern 0.###E0 is 3.333E2

output for pattern 00.##% is 33333.33%

default output is 23.0012

output for pattern ###,###.## is 23

output for pattern ####.## is 23

output for pattern ####.00 is 23.00

output for pattern ####.0# is 23.0

output for pattern 00000.## is 00023

output for pattern $###,###.## is $23

output for pattern 0.###E0 is 2.3E1

output for pattern 00.##% is 2300.12%

 

simple date 2004-8-7 8:16:14

2004-8-7 8:16:14

200487 上午081614

2004-8-7 8:16:14

04-8-7 上午8:16

 

2004.08.07 08:16:14 GMT + 08:00

0487 0816

星期六, 八月 7, '04

8:16 上午

08 o'clock 上午, GMT+08:00

02004.八月.07 公元 08:16 上午

星期六, 7 八月 2004 08: 16:14 +0800

040807081614+0800

 

 

package com.weishitech.qichechangtingyinyue; import android.annotation.SuppressLint; import android.content.Intent; import android.view.View; import android.widget.ImageView; import androidx.fragment.app.Fragment; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.hfd.common.util.ToastUtil; import com.umeng.commonsdk.UMConfigure; import com.weishitech.qichechangtingyinyue.adtakubase.activity.BaseBindActivity; import com.weishitech.qichechangtingyinyue.adtakubase.inter.insert.IAdInsertView; import com.weishitech.qichechangtingyinyue.adtakubase.inter.nativ.IAdNativeView; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; import com.weishitech.qichechangtingyinyue.bean.PlayStatusUpdateEvent; import com.weishitech.qichechangtingyinyue.databinding.ActivityMainBinding; import com.weishitech.qichechangtingyinyue.fragment.Adapter.NavigationFragmentAdapter; import com.weishitech.qichechangtingyinyue.fragment.home.LyricsActivity; import com.weishitech.qichechangtingyinyue.fragment.specail.SpecialFragment; import com.weishitech.qichechangtingyinyue.fragment.home.HomeFragment; import com.weishitech.qichechangtingyinyue.fragment.lilv.LiLvFragment; import com.weishitech.qichechangtingyinyue.fragment.tools.ToolsFragment; import com.weishitech.qichechangtingyinyue.fragment.wode.WoDeFragment; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.List; public class MainActivity extends BaseBindActivity<ActivityMainBinding> implements View.OnClickListener,IAdInsertView, IAdNativeView { private ImageView imgCurrent; //其中定义了四个Fragment,放入ArrayList中 ArrayList<Fragment> fragments = new ArrayList<>(); //五个fragments添加,暂时使用TempFragment页面做页面简单展示 HomeFragment homeFragment; LiLvFragment liLvFragment; SpecialFragment specialFragment; //WeatherFragment weatherFragment; ToolsFragment toolsFragment; WoDeFragment woDeFragment; //int index = 0;//标记当前页码 private List<AppAdEnum> mAdEnumList; @Override protected void init() { // SDK预初始化函数不会采集设备信息,也不会向友盟后台上报数据。 // preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验 UMConfigure.preInit(getApplication(), LCAppcation.umengKey, LCAppcation.channelName); //初始化组件化基础库, 所有友盟业务SDK都必须调用此初始化接口。 //建议在宿主App的Application.onCreate函数中调用基础组件库初始化函数。 UMConfigure.init(getApplication(), LCAppcation.umengKey, LCAppcation.channelName, UMConfigure.DEVICE_TYPE_PHONE, ""); /** *设置组件化的Log开关 *参数: boolean 默认为false,如需查看LOG设置为true */ UMConfigure.setLogEnabled(BuildConfig.DEBUG); mBinding.include.tabNavigationBottomRili.setOnClickListener(this); mBinding.include.tabNavigationBottomLilv.setOnClickListener(this); mBinding.include.tabNavigationBottomSpecail.setOnClickListener(this); mBinding.include.tabNavigationBottomPssb.setOnClickListener(this); mBinding.include.tabNavigationBottomWode.setOnClickListener(this); //默认选中日历 mBinding.include.imgRili.setSelected(true); mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.tab_select)); imgCurrent = mBinding.include.imgRili; //设置不可滑动 mBinding.idViewpager.setUserInputEnabled(false); homeFragment = new HomeFragment(); liLvFragment = new LiLvFragment(); specialFragment = new SpecialFragment(); // toolsFragment = new ToolsFragment(); woDeFragment = new WoDeFragment(); fragments.add(homeFragment); fragments.add(liLvFragment); fragments.add(specialFragment); // fragments.add(toolsFragment); fragments.add(woDeFragment); //装配NavigationFrameworkAdapter适配器 NavigationFragmentAdapter pagerAdapter = new NavigationFragmentAdapter(getSupportFragmentManager(), getLifecycle(), fragments); //绑定适配器 mBinding.idViewpager.setAdapter(pagerAdapter); if (mAdEnumList == null) { mAdEnumList = new ArrayList<>(); } mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB1); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB2); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB3); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB4); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB5); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB1); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB2); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB3); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB4); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB5); setTextColor(0); mBinding.include.imgSong.setOnClickListener(v -> { Intent intent = new Intent(MainActivity.this, LyricsActivity.class); // 这里需要知道当前播放的是哪首歌 —— 建议配合 MusicCache 或 SharedViewModel 使用 MusicBean.DataBean current = MusicCache.getCurrentPlayingSong(); if (current != null) { intent.putExtra("title", current.getTitle()); intent.putExtra("singer", current.getSinger()); intent.putExtra("cover_url", current.getCover()); intent.putExtra("music_url", current.getMusic()); intent.putExtra("position", current.getPosition()); intent.putExtra("total_count", MusicCache.getTotalCount()); } else { ToastUtil.showShortToast("暂无播放信息"); } }); EventBus.getDefault().register(this); } //页面切换方法,已经含两种情况,滑动点击切换 @SuppressLint("NonConstantResourceId") private void changeTab(int position) { imgCurrent.setSelected(false); //在android中使用switch case语句可能会出现报错冒红现象,请看最后的注意事项,可以解决这个问题 switch (position) { case R.id.tab_navigation_bottom_rili: //点击图片后,切换页面 mBinding.idViewpager.setCurrentItem(0,false); setTextColor(0); case 0: //滑动到第一个界面(索引为0)触发被选中效果,即切换图标(从黑→绿) //imgWeChat.setSelected(true)这部分功能请看后面的tab_navigation__bottom部分 mBinding.include.imgRili.setSelected(true); imgCurrent = mBinding.include.imgRili; break; case R.id.tab_navigation_bottom_lilv: mBinding.idViewpager.setCurrentItem(1,false); setTextColor(1); case 1: mBinding.include.imgLilv.setSelected(true); imgCurrent = mBinding.include.imgLilv; break; case R.id.tab_navigation_bottom_specail: mBinding.idViewpager.setCurrentItem(2,false); setTextColor(2); case 2: mBinding.include.imgSpecail.setSelected(true); imgCurrent = mBinding.include.imgSpecail; break; case R.id.tab_navigation_bottom_pssb: mBinding.idViewpager.setCurrentItem(3,false); setTextColor(3); case 3: mBinding.include.imgPssb.setSelected(true); imgCurrent = mBinding.include.imgPssb; break; case R.id.tab_navigation_bottom_wode: mBinding.idViewpager.setCurrentItem(4,false); setTextColor(4); case 4: mBinding.include.imgWode.setSelected(true); imgCurrent = mBinding.include.imgWode; break; } } private void setTextColor(int index){ initInsert(mAdEnumList.get(index)); initNative(mAdEnumList.get(index+fragments.size())); mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvLilv.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvSpecail.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvPssb.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvWode.setTextColor(getResources().getColor(R.color.text_tab)); switch (index){ case 0: mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.tab_select)); break; case 1: mBinding.include.tvLilv.setTextColor(getResources().getColor(R.color.tab_select)); break; case 2: mBinding.include.tvSpecail.setTextColor(getResources().getColor(R.color.tab_select)); break; case 3: mBinding.include.tvPssb.setTextColor(getResources().getColor(R.color.tab_select)); break; case 4: mBinding.include.tvWode.setTextColor(getResources().getColor(R.color.tab_select)); break; } } // 两次点击按钮之间的点击间隔不能少于1000毫秒 private static final long MIN_CLICK_DELAY_TIME = 500; private static long lastClickTime; //点击导航栏时,将图片的ID入changeTab,触发切换页面事件 @Override public void onClick(View v) { long curClickTime = System.currentTimeMillis(); if((curClickTime - lastClickTime) >= MIN_CLICK_DELAY_TIME) { // 超过点击间隔后再将lastClickTime重置为当前点击时间 lastClickTime = curClickTime; changeTab(v.getId()); } } /** * 跳转到保值fragment * */ public void JumpToPrice() { imgCurrent.setSelected(false); mBinding.include.tvSpecail.setSelected(true); imgCurrent = mBinding.include.imgSpecail; setTextColor(2); mBinding.idViewpager.setCurrentItem(2,false); } // 接收事件(主线程) @Subscribe(threadMode = ThreadMode.MAIN) public void onPlayStatusUpdate(PlayStatusUpdateEvent event) { String coverUrl = event.getCoverUrl(); boolean isPlaying = event.isPlaying(); ImageView ivMiniPlayerCover = mBinding.include.imgSong; // ImageView ivPlayPause = mBinding.include.ivMiniPlayerPlayPause; // 显示 mini 播放栏 mBinding.include.imgSong.setVisibility(View.VISIBLE); // 加载封面 Glide.with(this) .load(coverUrl) .transform(new CircleCrop()) .into(ivMiniPlayerCover); // 更新播放/暂停图标 // ivPlayPause.setImageResource(isPlaying ? // R.mipmap.img_gc_zt : // 暂停 // R.mipmap.img_gc_bf); // 播放 } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }package com.weishitech.qichechangtingyinyue.fragment.home; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.hfd.common.base.BaseActivity; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.bean.FavoriteManager; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; import com.weishitech.qichechangtingyinyue.bean.PlayHistoryManager; import com.weishitech.qichechangtingyinyue.bean.PlayStatusUpdateEvent; import com.weishitech.qichechangtingyinyue.bean.SharedMusicViewModel; import com.weishitech.qichechangtingyinyue.fragment.Adapter.RecentPlayAdapter; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import org.greenrobot.eventbus.EventBus; import java.util.ArrayList; import java.util.List; public class LyricsActivity extends BaseActivity { // UI Views TextView tv_back, tv_song_name, tv_sing_name, tv_start_time, tv_end_time; ImageView iv_sing_logo, iv_tj, iv_gd, iv_xh, iv_sys, iv_bf, iv_xys, iv_zjbf; SeekBar seekbar; private boolean fromSearch = false; private boolean isSingleLoop = false; // 单曲循环开关 private FavoriteManager favoriteManager; private boolean isCurrentSongFavorite = false; // 声明 ViewModel private SharedMusicViewModel sharedViewModel; // 播放管理器 private MusicPlayerManager playerManager; private boolean isBoundToCurrentSong = false; // 是否已绑定当前歌曲 // 数据接收字段 private String title, singer, coverUrl, musicUrl; private int songPosition,totalSongCount; // 进度更新 private final Handler handler = new Handler(); private final Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (playerManager != null && playerManager.isPlaying()) { int currentPosition = playerManager.getCurrentPosition(); int duration = playerManager.getDuration(); if (duration > 0) { seekbar.setMax(duration); seekbar.setProgress(currentPosition); // 更新时间文本(格式 mm:ss) tv_start_time.setText(formatTime(currentPosition)); tv_end_time.setText(formatTime(duration)); } } handler.postDelayed(this, 1000); // 每秒更新一次 } }; private List<MusicBean.DataBean> sourceList; @Override protected int setLayout() { return R.layout.activity_lyrics; } @Override protected void setView() { tv_back = fvbi(R.id.tv_back); iv_sing_logo = fvbi(R.id.iv_sing_logo); tv_song_name = fvbi(R.id.tv_song_name); tv_sing_name = fvbi(R.id.tv_sing_name); iv_tj = fvbi(R.id.iv_tj); iv_gd = fvbi(R.id.iv_gd); seekbar = fvbi(R.id.seekbar); tv_start_time = fvbi(R.id.tv_start_time); tv_end_time = fvbi(R.id.tv_end_time); iv_xh = fvbi(R.id.iv_xh); iv_sys = fvbi(R.id.iv_sys); iv_bf = fvbi(R.id.iv_bf); iv_xys = fvbi(R.id.iv_xys); iv_zjbf = fvbi(R.id.iv_zjbf); } @Override protected void setData() { Bundle bundle = getIntent().getExtras(); if (bundle != null) { title = bundle.getString("title"); singer = bundle.getString("singer"); coverUrl = bundle.getString("cover_url"); musicUrl = bundle.getString("music_url"); songPosition = bundle.getInt("position", -1); totalSongCount = bundle.getInt("total_count", 0); fromSearch = bundle.getBoolean("from_search", false); // 接收来源标记 // 接收来源列表(关键!) if (bundle.containsKey("source_list")) { sourceList = (List<MusicBean.DataBean>) bundle.getSerializable("source_list"); totalSongCount = sourceList.size(); // 再次确认长度 } if (songPosition < 0 || songPosition >= totalSongCount) { ToastUtil.showShortToast("歌曲位置无效"); finish(); return; } tv_song_name.setText(title); tv_sing_name.setText(singer); Glide.with(this) .load(coverUrl) .into(iv_sing_logo); } // 初始化播放器 //使用单例 playerManager = MusicPlayerManager.getInstance(); // 注册播放状态监听 setupPlaybackListener(); // 绑定当前歌曲(检查是否已在播放) bindToCurrentSong(); // 初始化收藏管理器 favoriteManager = FavoriteManager.getInstance(this); updateFavoriteState(); // 更新按钮状态 // 初始化 ViewModel sharedViewModel = new ViewModelProvider(this).get(SharedMusicViewModel.class); // 只要进入页面,就视为“播放此歌”,记录历史 if (title != null && musicUrl != null && coverUrl != null) { MusicBean.DataBean currentSong = new MusicBean.DataBean(); currentSong.setTitle(title); currentSong.setSinger(singer); currentSong.setCover(coverUrl); currentSong.setMusic(musicUrl); currentSong.setSongTime(formatTime(playerManager.getDuration())); // 可选 //记录播放历史 PlayHistoryManager.getInstance(this).addPlayRecord(currentSong); } } @Override protected void setClick() { tv_back.setOnClickListener(v -> finish()); iv_sys.setOnClickListener(v -> { if (songPosition <= 0) { ToastUtil.showShortToast("当前已是第一首"); return; } playMusicAtPosition(songPosition - 1); }); iv_xh.setOnClickListener(v -> { isSingleLoop = !isSingleLoop; if (isSingleLoop) { ToastUtil.showShortToast("已开启单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); // 假设有这个资源 } else { ToastUtil.showShortToast("已关闭单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); } }); iv_xys.setOnClickListener(v -> { if (songPosition >= totalSongCount - 1) { ToastUtil.showShortToast("当前已是最后一首"); return; } playMusicAtPosition(songPosition + 1); }); iv_tj.setOnClickListener(v -> { if (title == null || musicUrl == null) { ToastUtil.showShortToast("歌曲信息不完整"); return; } MusicBean.DataBean currentSong = new MusicBean.DataBean(); currentSong.setTitle(title); currentSong.setSinger(singer); currentSong.setCover(coverUrl); currentSong.setMusic(musicUrl); currentSong.setSongTime(formatTime(playerManager.getDuration())); // 可选 if (isCurrentSongFavorite) { // 已收藏 → 取消收藏 favoriteManager.removeFromFavorites(musicUrl); iv_tj.setImageResource(R.mipmap.img_tj); // 未收藏图标 ToastUtil.showShortToast("已取消收藏"); } else { // 未收藏 → 添加收藏 favoriteManager.addToFavorites(currentSong); iv_tj.setImageResource(R.mipmap.img_tj_u); // 已收藏图标 ToastUtil.showShortToast("已添加到我喜欢"); } isCurrentSongFavorite = !isCurrentSongFavorite; //通知所有页面,收藏列表已改变 List<MusicBean.DataBean> newList = favoriteManager.getFavoriteList(); sharedViewModel.notifyFavoriteChanged(newList); }); iv_zjbf.setOnClickListener(v -> showRecentPlayDialog()); // 播放/暂停按钮 iv_bf.setOnClickListener(v -> { if (!isBoundToCurrentSong) { ToastUtil.showShortToast("暂无歌曲信息"); return; } if (playerManager.isPlaying()) { playerManager.pause(); } else { playerManager.resume(); } updatePlayButtonIcon(); }); // SeekBar 拖动控制 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { tv_start_time.setText(formatTime(progress)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 用户开始拖动 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 用户停止拖动,跳转到指定位置 if (playerManager != null && isBoundToCurrentSong) { playerManager.seekTo(seekbar.getProgress()); } } }); } private void bindToCurrentSong() { if (musicUrl == null || title == null) return; boolean isPlaying = playerManager.isPlaying(); int currentPos = playerManager.getCurrentPlayingPosition(); // 判断是否就是当前正在播放的歌曲 if (isPlaying && currentPos == songPosition) { // 是同一首歌 → 直接同步状态 isBoundToCurrentSong = true; updatePlayButtonIcon(); // 显示“暂停” startUpdatingProgress(); // 开始更新进度条 } else { // 不是当前播放的 → 准备播放这首 playerManager.play(this, songPosition, musicUrl); isBoundToCurrentSong = true; updatePlayButtonIcon(); // 默认播放中 startUpdatingProgress(); } } private void setupPlaybackListener() { playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { if (position == songPosition) { runOnUiThread(() -> { updatePlayButtonIcon(); startUpdatingProgress(); }); } else { // 播放的是其他位置的歌曲 → 当前页面应暂停状态 runOnUiThread(() -> { stopUpdatingProgress(); iv_bf.setImageResource(R.mipmap.img_gc_bf); // 显示播放图标 }); } } @Override public void onPaused() { runOnUiThread(() -> { updatePlayButtonIcon(); stopUpdatingProgress(); }); } @Override public void onCompletion() { runOnUiThread(() -> { // 停止当前进度更新 stopUpdatingProgress(); seekbar.setProgress(0); tv_start_time.setText("00:00"); if (isSingleLoop) { // 重新播放当前歌曲 playerManager.play(LyricsActivity.this, songPosition, musicUrl); startUpdatingProgress(); updatePlayButtonIcon(); } else { // 自动播放下一首 int nextPosition = songPosition + 1; if (nextPosition < totalSongCount) { playMusicAtPosition(nextPosition); } else { // 已到最后 → 可选:循环播放第一首 or 提示 ToastUtil.showShortToast("已播放完毕"); updatePlayButtonIcon(); // 显示为暂停状态 // 如果你想循环回第一首,取消下面注释 playMusicAtPosition(0); } } }); } @Override public void onError(String errorMsg) { runOnUiThread(() -> { // ToastUtil.showShortToast("播放出错:" + errorMsg); updatePlayButtonIcon(); stopUpdatingProgress(); }); } }); } private void updatePlayButtonIcon() { if (playerManager.isPlaying()) { iv_bf.setImageResource(R.mipmap.img_gc_zt); // 暂停图标 } else { iv_bf.setImageResource(R.mipmap.img_gc_bf); // 播放图标 } } private void startUpdatingProgress() { stopUpdatingProgress(); // 防止重复 handler.postDelayed(updateProgressRunnable, 0); } private void stopUpdatingProgress() { handler.removeCallbacks(updateProgressRunnable); } @Override public void onResume() { super.onResume(); // 页面可见时尝试恢复状态 if (isBoundToCurrentSong) { updatePlayButtonIcon(); } } @Override protected void onPause() { super.onPause(); // 可选:不移除监听,让后台也能播放 } @Override protected void onDestroy() { stopUpdatingProgress(); // 注意:不要 release() playerManager,否则其他页面会中断 // playerManager.release(); ❌ 不要在这里释放 super.onDestroy(); } // 时间格式化工具 private String formatTime(int milliseconds) { int seconds = milliseconds / 1000; int minutes = seconds / 60; seconds = seconds % 60; return String.format("%02d:%02d", minutes, seconds); } private void playMusicAtPosition(int pos) { // 使用 MusicCache 判断边界(替代 musicDataList) if (pos < 0 || pos >= totalSongCount) { return; // 越界防护 } MusicBean.DataBean song; if (sourceList != null && pos < sourceList.size()) { song = sourceList.get(pos); } else { // 回退到主列表(兼容主列表播放) song = MusicCache.getMusicAt(pos); } // 播放指定位置的音乐 playerManager.play(this, pos, song.getMusic()); // 更新界面 updateUIForNewSong(song, pos); } /** * 播放新歌时更新界面内部状态 */ private void updateUIForNewSong(MusicBean.DataBean song, int position) { // 更新成员变量 this.title = song.getTitle(); this.singer = song.getSinger(); this.coverUrl = song.getCover(); this.musicUrl = song.getMusic(); this.songPosition = position; // 更新 UI 显示 tv_song_name.setText(title); tv_sing_name.setText(singer); if (isDestroyed() || isFinishing()) return; Glide.with(this) .load(coverUrl) .into(iv_sing_logo); // 标记已绑定当前歌曲 isBoundToCurrentSong = true; // 更新播放按钮为“正在播放” updatePlayButtonIcon(); // 开始进度条更新 startUpdatingProgress(); // 发送 EventBus 事件 boolean currentlyPlaying = playerManager.isPlaying(); PlayStatusUpdateEvent event = new PlayStatusUpdateEvent( song.getCover(), song.getTitle(), song.getSinger(), currentlyPlaying ); EventBus.getDefault().post(event); // 发送事件 // Toast 提示 // ToastUtil.showShortToast("播放: " + title); updateFavoriteState(); PlayHistoryManager.getInstance(this).addPlayRecord(song); } private void updateFavoriteState() { if (musicUrl == null) { iv_tj.setImageResource(R.mipmap.img_tj); isCurrentSongFavorite = false; return; } isCurrentSongFavorite = favoriteManager.isFavorite(musicUrl); iv_tj.setImageResource(isCurrentSongFavorite ? R.mipmap.img_tj_u : R.mipmap.img_tj); } private void showRecentPlayDialog() { // 创建 BottomSheetDialog BottomSheetDialog dialog = new BottomSheetDialog(this); // 绑定布局 View contentView = getLayoutInflater().inflate(R.layout.dialog_recent_play, null); dialog.setContentView(contentView); // 找控件 TextView tvTitle = contentView.findViewById(R.id.tv_title); RecyclerView rvRecent = contentView.findViewById(R.id.rv_recent); // 加载数据 PlayHistoryManager historyManager = PlayHistoryManager.getInstance(this); List<MusicBean.DataBean> historyList = historyManager.getHistoryList(); tvTitle.setText("最近播放 (" + historyList.size() + ")"); // 设置适配器 RecentPlayAdapter adapter = new RecentPlayAdapter(); rvRecent.setLayoutManager(new LinearLayoutManager(this)); rvRecent.setAdapter(adapter); adapter.setData(historyList); if (musicUrl != null) { adapter.setCurrentPlayingSong(musicUrl); // 入当前播放的 musicUrl } // 设置点击事件 adapter.setOnItemClickListener((song, position) -> { // 跳转到该歌曲的歌词页 playMusicAtPositionFromHistory(song); dialog.dismiss(); // 关闭弹窗 }); // 显示 dialog.show(); } private void playMusicAtPositionFromHistory(MusicBean.DataBean song) { // 查找当前 sourceList 中是否有这首歌 int pos = -1; if (sourceList != null) { for (int i = 0; i < sourceList.size(); i++) { if (sourceList.get(i).getMusic().equals(song.getMusic())) { pos = i; break; } } } // 如果没找到,默认为 0 或添加进临时播放? if (pos == -1) { // 可选择重新构造列表,或将它作为单曲播放 pos = 0; List<MusicBean.DataBean> temp = new ArrayList<>(); temp.add(song); sourceList = temp; totalSongCount = 1; } updateUIForNewSong(song, pos); playerManager.play(this, pos, song.getMusic()); // ToastUtil.showShortToast("正在播放:" + song.getTitle()); } } package com.weishitech.qichechangtingyinyue.bean; import java.util.ArrayList; import java.util.List; public class MusicCache { public static List<MusicBean.DataBean> getMainMusicList() { return mainMusicList; } private static List<MusicBean.DataBean> mainMusicList; public static void setMainMusicList(List<MusicBean.DataBean> list) { mainMusicList = new ArrayList<>(list); } public static MusicBean.DataBean getMusicAt(int position) { if (mainMusicList == null || position < 0 || position >= mainMusicList.size()) { return null; } return mainMusicList.get(position); } } MusicCache添加.getCurrentPlayingSong();
最新发布
12-06
package com.weishitech.qichechangtingyinyue.fragment.Adapter; import android.widget.ImageView; import androidx.annotation.NonNull; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.viewholder.BaseViewHolder; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.LCAppcation; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.utils.DisplayUtils; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import java.util.List; public class PrivateAdapter extends BaseQuickAdapter<MusicBean.DataBean, BaseViewHolder> { private int currentPlayingPosition = -1; private List<MusicBean.DataBean> currentListSnapshot; private MusicPlayerManager playerManager; private MusicPlayerManager.OnPlaybackStateChangedListener playbackListener; public PrivateAdapter() { super(R.layout.private_adapter); // 初始化播放器 playerManager = MusicPlayerManager.getInstance(); // 创建监听器(只处理相关事件) playbackListener = new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { if ("private".equals(playerManager.getCurrentPlaylistTag())) { int idx = playerManager.getCurrentExternalIndex(); updatePlayingPosition(idx, true); } } @Override public void onPaused() { if ("private".equals(playerManager.getCurrentPlaylistTag())) { int idx = playerManager.getCurrentExternalIndex(); updatePlayingPosition(idx, false); } } @Override public void onCompletion() { // 播放完成时清除状态(可选) updatePlayingPosition(currentPlayingPosition, false); } @Override public void onError(String errorMsg) { updatePlayingPosition(currentPlayingPosition, false); } }; // 注册监听(注意:不要重复注册) playerManager.setOnPlaybackStateChangedListener(playbackListener); } public void setList(List<MusicBean.DataBean> list) { super.setList(list); // 保存一份引用,供点击时使用 this.currentListSnapshot = list; } @Override protected void convert(@NonNull BaseViewHolder holder, MusicBean.DataBean dataBean) { holder.setText(R.id.tv_song_name, dataBean.getTitle()); holder.setText(R.id.tv_sing_name, dataBean.getSinger()); holder.setText(R.id.tv_tj, "之手 推荐-" + dataBean.getTitle()); ImageView coverView = holder.getView(R.id.iv_sing_logo); ImageView playBtn = holder.getView(R.id.iv_song_start); Glide.with(getContext()) .load(dataBean.getCover()) .error(R.mipmap.img_home_sing) .transform(new RoundedCorners(DisplayUtils.dp2px(getContext(), 8f))) .into(coverView); int position = getItemPosition(dataBean); // 核心修改:实时判断是否为当前播放项 if (isItemActive(position)) { playBtn.setImageResource(R.mipmap.img_item_zt); // 暂停图标 } else { playBtn.setImageResource(R.mipmap.img_item_bf); // 播放图标 } // 点击事件:根据当前状态决定行为 playBtn.setOnClickListener(v -> { MusicPlayerManager playerManager = MusicPlayerManager.getInstance(); boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "private".equals(playerManager.getCurrentPlaylistTag()); int currentIdx = playerManager.getCurrentExternalIndex(); int currentPosition = getItemPosition(dataBean); if (isPlaying && isFromThisList && currentIdx == currentPosition) { // 当前这首歌正在播放 → 暂停 playerManager.pause(); ToastUtil.showShortToast("已暂停"); // ✅ 关键:必须立即刷新当前 item notifyItemChanged(currentPosition); } else { // 播放这首歌曲 if (currentListSnapshot == null || currentPosition < 0 || currentPosition >= currentListSnapshot.size()) { ToastUtil.showShortToast("歌曲无效"); return; } playerManager.playFromExternalList( LCAppcation.getInstance(), currentListSnapshot, currentPosition, "private" ); playerManager.setPlayingFromPrivate(true); ToastUtil.showShortToast("播放: " + dataBean.getTitle()); // ✅ 播放新歌时刷新上一首这一首 notifyItemChanged(this.currentPlayingPosition); notifyItemChanged(currentPosition); } }); } // 外部调用:更新当前播放哪一首 public void updatePlayingPosition(int position, boolean isPlaying) { int oldPos = this.currentPlayingPosition; // 如果位置没变,只是状态变了(比如暂停/继续) if (oldPos == position) { if ((isPlaying && isItemActive(position)) || (!isPlaying && !isItemActive(position))) { // 状态一致,无需刷新 return; } } // 更新状态 this.currentPlayingPosition = isPlaying ? position : -1; // 刷新新旧两项 notifyItemChanged(oldPos); notifyItemChanged(position); } // 播放停止或退出时清空状态 public void clearPlayingState() { int oldPos = this.currentPlayingPosition; this.currentPlayingPosition = -1; notifyItemChanged(oldPos); } // 自定义接口 public interface OnItemClickListener { void onItemClick(int position, MusicBean.DataBean dataBean); } private OnItemClickListener onItemClickListener; public void setOnItemClickListener(OnItemClickListener listener) { this.onItemClickListener = listener; } private boolean isItemActive(int position) { MusicPlayerManager manager = MusicPlayerManager.getInstance(); return manager.isPlaying() && "private".equals(manager.getCurrentPlaylistTag()) && manager.getCurrentExternalIndex() == position; } } package com.weishitech.qichechangtingyinyue.fragment.home; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.hfd.common.base.BaseActivity; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import com.weishitech.qichechangtingyinyue.utils.OnMultiClickListener; public class LyricsActivity extends BaseActivity { // UI Views TextView tv_back, tv_song_name, tv_sing_name, tv_start_time, tv_end_time; ImageView iv_sing_logo, iv_tj, iv_gd, iv_xh, iv_sys, iv_bf, iv_xys, iv_zjbf; SeekBar seekbar; private boolean isSingleLoop = false; // 单曲循环开关 // 播放管理器 private MusicPlayerManager playerManager; private boolean isBoundToCurrentSong = false; // 是否已绑定当前歌曲 // 数据接收字段 private String title, singer, coverUrl, musicUrl; private int songPosition,totalSongCount; // 进度更新 private final Handler handler = new Handler(); private final Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (playerManager != null && playerManager.isPlaying()) { int currentPosition = playerManager.getCurrentPosition(); int duration = playerManager.getDuration(); if (duration > 0) { seekbar.setMax(duration); seekbar.setProgress(currentPosition); // 更新时间文本(格式 mm:ss) tv_start_time.setText(formatTime(currentPosition)); tv_end_time.setText(formatTime(duration)); } } handler.postDelayed(this, 1000); // 每秒更新一次 } }; @Override protected int setLayout() { return R.layout.activity_lyrics; } @Override protected void setView() { tv_back = fvbi(R.id.tv_back); iv_sing_logo = fvbi(R.id.iv_sing_logo); tv_song_name = fvbi(R.id.tv_song_name); tv_sing_name = fvbi(R.id.tv_sing_name); iv_tj = fvbi(R.id.iv_tj); iv_gd = fvbi(R.id.iv_gd); seekbar = fvbi(R.id.seekbar); tv_start_time = fvbi(R.id.tv_start_time); tv_end_time = fvbi(R.id.tv_end_time); iv_xh = fvbi(R.id.iv_xh); iv_sys = fvbi(R.id.iv_sys); iv_bf = fvbi(R.id.iv_bf); iv_xys = fvbi(R.id.iv_xys); iv_zjbf = fvbi(R.id.iv_zjbf); } @Override protected void setData() { Bundle bundle = getIntent().getExtras(); if (bundle != null) { title = bundle.getString("title"); singer = bundle.getString("singer"); coverUrl = bundle.getString("cover_url"); musicUrl = bundle.getString("music_url"); songPosition = bundle.getInt("position", -1); totalSongCount = bundle.getInt("total_count", 0); tv_song_name.setText(title); tv_sing_name.setText(singer); Glide.with(this) .load(coverUrl) .transform(new CircleCrop()) .into(iv_sing_logo); } // 初始化播放器 //使用单例 playerManager = MusicPlayerManager.getInstance(); // 注册播放状态监听 setupPlaybackListener(); // 绑定当前歌曲(检查是否已在播放) bindToCurrentSong(); } @Override protected void setClick() { tv_back.setOnClickListener(v -> finish()); iv_sys.setOnClickListener(v -> { if (songPosition <= 0) { ToastUtil.showShortToast("当前已是第一首"); return; } playMusicAtPosition(songPosition - 1); }); iv_xh.setOnClickListener(v -> { isSingleLoop = !isSingleLoop; if (isSingleLoop) { ToastUtil.showShortToast("已开启单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); // 假设有这个资源 } else { ToastUtil.showShortToast("已关闭单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); } }); iv_xys.setOnClickListener(v -> { if (songPosition >= totalSongCount - 1) { ToastUtil.showShortToast("当前已是最后一首"); return; } playMusicAtPosition(songPosition + 1); }); // 播放/暂停按钮 iv_bf.setOnClickListener(v -> { if (!isBoundToCurrentSong) { ToastUtil.showShortToast("暂无歌曲信息"); return; } if (playerManager.isPlaying()) { playerManager.pause(); } else { playerManager.resume(); } updatePlayButtonIcon(); }); // SeekBar 拖动控制 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { tv_start_time.setText(formatTime(progress)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 用户开始拖动 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 用户停止拖动,跳转到指定位置 if (playerManager != null && isBoundToCurrentSong) { playerManager.seekTo(seekbar.getProgress()); } } }); } private void bindToCurrentSong() { if (musicUrl == null || title == null) return; boolean isPlaying = playerManager.isPlaying(); int currentPos = playerManager.getCurrentPlayingPosition(); // 判断是否就是当前正在播放的歌曲 if (isPlaying && currentPos == songPosition) { // 是同一首歌 → 直接同步状态 isBoundToCurrentSong = true; updatePlayButtonIcon(); // 显示“暂停” startUpdatingProgress(); // 开始更新进度条 } else { // 不是当前播放的 → 准备播放这首 playerManager.play(this, songPosition, musicUrl); isBoundToCurrentSong = true; updatePlayButtonIcon(); // 默认播放中 startUpdatingProgress(); } } private void setupPlaybackListener() { playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { if (position == songPosition) { runOnUiThread(() -> { updatePlayButtonIcon(); startUpdatingProgress(); }); } else { // 播放的是其他位置的歌曲 → 当前页面应暂停状态 runOnUiThread(() -> { stopUpdatingProgress(); iv_bf.setImageResource(R.mipmap.img_gc_bf); // 显示播放图标 }); } } @Override public void onPaused() { runOnUiThread(() -> { updatePlayButtonIcon(); stopUpdatingProgress(); }); } @Override public void onCompletion() { runOnUiThread(() -> { // 停止当前进度更新 stopUpdatingProgress(); seekbar.setProgress(0); tv_start_time.setText("00:00"); if (isSingleLoop) { // 重新播放当前歌曲 playerManager.play(LyricsActivity.this, songPosition, musicUrl); startUpdatingProgress(); updatePlayButtonIcon(); } else { // 自动播放下一首 int nextPosition = songPosition + 1; if (nextPosition < totalSongCount) { playMusicAtPosition(nextPosition); } else { // 已到最后 → 可选:循环播放第一首 or 提示 ToastUtil.showShortToast("已播放完毕"); updatePlayButtonIcon(); // 显示为暂停状态 // 如果你想循环回第一首,取消下面注释 playMusicAtPosition(0); } } }); } @Override public void onError(String errorMsg) { runOnUiThread(() -> { ToastUtil.showShortToast("播放出错:" + errorMsg); updatePlayButtonIcon(); stopUpdatingProgress(); }); } }); } private void updatePlayButtonIcon() { if (playerManager.isPlaying()) { iv_bf.setImageResource(R.mipmap.img_gc_zt); // 暂停图标 } else { iv_bf.setImageResource(R.mipmap.img_gc_bf); // 播放图标 } } private void startUpdatingProgress() { stopUpdatingProgress(); // 防止重复 handler.postDelayed(updateProgressRunnable, 0); } private void stopUpdatingProgress() { handler.removeCallbacks(updateProgressRunnable); } @Override public void onResume() { super.onResume(); // 页面可见时尝试恢复状态 if (isBoundToCurrentSong) { updatePlayButtonIcon(); } } @Override protected void onPause() { super.onPause(); // 可选:不移除监听,让后台也能播放 } @Override protected void onDestroy() { stopUpdatingProgress(); // 注意:不要 release() playerManager,否则其他页面会中断 // playerManager.release(); ❌ 不要在这里释放 super.onDestroy(); } // 时间格式化工具 private String formatTime(int milliseconds) { int seconds = milliseconds / 1000; int minutes = seconds / 60; seconds = seconds % 60; return String.format("%02d:%02d", minutes, seconds); } private void playMusicAtPosition(int pos) { // 使用 MusicCache 判断边界(替代 musicDataList) if (pos < 0 || pos >= totalSongCount) { return; // 越界防护 } MusicBean.DataBean song = MusicCache.getMusicAt(pos); if (song == null) { ToastUtil.showShortToast("歌曲数据异常"); return; } // 播放指定位置的音乐 playerManager.play(this, pos, song.getMusic()); // 更新界面 updateUIForNewSong(song, pos); } /** * 播放新歌时更新界面内部状态 */ private void updateUIForNewSong(MusicBean.DataBean song, int position) { // 更新成员变量 this.title = song.getTitle(); this.singer = song.getSinger(); this.coverUrl = song.getCover(); this.musicUrl = song.getMusic(); this.songPosition = position; // 更新 UI 显示 tv_song_name.setText(title); tv_sing_name.setText(singer); if (isDestroyed() || isFinishing()) return; Glide.with(this) .load(coverUrl) .transform(new CircleCrop()) .into(iv_sing_logo); // 标记已绑定当前歌曲 isBoundToCurrentSong = true; // 更新播放按钮为“正在播放” updatePlayButtonIcon(); // 开始进度条更新 startUpdatingProgress(); // 可选:Toast 提示 ToastUtil.showShortToast("播放: " + title); } } 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.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.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; 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.R; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; 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.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 isUserAuthorizedPlayback = false; // 用户是否已授权播放(点击/滑动) private boolean isMainPlaybackActive = false; // 是否由主流程控制播放状态 private int lastPlayedPosition = -1; // 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; @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()); // 默认显示蓝色“播放”图标 } @Override protected void initClick() { // 搜索跳转 iv_ss.setOnClickListener(v -> toClass(SearchActivity.class)); // 播放/暂停按钮 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 }); //私人音乐播放按钮点击 sr_start.setOnClickListener(v -> playPrivateFirstSong()); //轻音乐播放按钮点击 qy_start.setOnClickListener(v -> playQingyinFirstSong()); //小众音乐播放按钮点击 xz_start.setOnClickListener(v -> playXiaoZhongFirstSong()); relative1.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { if (privateSongList == null || privateSongList.isEmpty()) { ToastUtil.showShortToast("暂无数据"); return; } 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; } 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; } 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); updateExternalPlayButtons(); // 同步顶部按钮 } } 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() { if (!playerManager.isPlayingFromPrivate()) { playNextSong(); } else { // 外部列表播放完成 → 尝试播放下一首 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); } } 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(); } 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) -> { // 创建 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(); // 设置点击事件:点击 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); //轻音乐 // 确保 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); //小众音乐 // 确保 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); } 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); isUserAuthorizedPlayback = true; // 关键:只有完成首次布局后才允许自动播放 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()); ToastUtil.showShortToast("播放: " + bean.getTitle()); }); } private void playNextSong() { int nextPos = playerManager.getCurrentPlayingPosition() + 1; if (nextPos < musicDataList.size()) { playMusicAtPosition(nextPos); scrollToTriggerPosition(nextPos, rv); } else { ToastUtil.showShortToast("已播放完全部歌曲"); } } 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 center = (lm.getDecoratedLeft(view) + lm.getDecoratedRight(view)) / 2; int targetX = DisplayUtils.dp2px(requireContext(), 50f); return targetX - center; } @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; // Fragment 已 detach,不执行 boolean isPlaying = playerManager.isPlaying(); themeManager.applyThemeTo(line, relative, iv_bf, isPlaying); } /** * 更新主播放按钮图标(根据实际播放状态) */ private void updatePlayButtonIcon() { if (!isAdded()) return; boolean isPlaying = playerManager.isPlaying(); 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); // 开始旋转 } } /** * 将所有外部播放按钮重置为“播放”状态(UI 层) */ private void resetAllExternalButtons() { sr_start.setImageResource(R.mipmap.img_bf); qy_start.setImageResource(R.mipmap.img_bf); xz_start.setImageResource(R.mipmap.img_bf); } /** * 播放私人专属歌单 */ private void playPrivateFirstSong() { if (privateSongList == null || privateSongList.isEmpty()) { ToastUtil.showShortToast("暂无私人歌曲"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "private".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放本列表 → 暂停,并将按钮改为“播放” if (isPlaying && isFromThisList) { playerManager.pause(); sr_start.setImageResource(R.mipmap.img_bf); // 主动改为“播放” ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停本列表(tag 匹配但未播放)→ 继续播放 if (!isPlaying && isFromThisList) { playerManager.resume(); sr_start.setImageResource(R.mipmap.img_zt); // 主动改为“暂停” privateAdapter.updatePlayingPosition(playerManager.getCurrentExternalIndex(), true); ToastUtil.showShortToast("继续播放: " + privateSongList.get(playerManager.getCurrentExternalIndex()).getTitle()); return; } // ★★★ 新播放:不是本列表 → 先重置所有按钮 resetAllExternalButtons(); // 开始新播放 playerManager.playFromExternalList(requireContext(), privateSongList, 0, "private"); playerManager.setPlayingFromPrivate(true); // 更新 UI privateAdapter.updatePlayingPosition(0, true); sr_start.setImageResource(R.mipmap.img_zt); // 设为“暂停” ToastUtil.showShortToast("播放私人歌曲: " + privateSongList.get(0).getTitle()); updatePlayButtonIcon(); // iv_bf 变成“暂停”图标 } /** * 播放轻音乐歌单 */ private void playQingyinFirstSong() { if (qySongList == null || qySongList.isEmpty()) { ToastUtil.showShortToast("暂无轻音乐"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "qingyin".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放本列表 → 暂停,并将按钮改为“播放” if (isPlaying && isFromThisList) { playerManager.pause(); qy_start.setImageResource(R.mipmap.img_bf); // ✅ 主动改为“播放” ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停本列表 → 继续播放,按钮变“暂停” if (!isPlaying && isFromThisList) { playerManager.resume(); qy_start.setImageResource(R.mipmap.img_zt); // ✅ 主动改为“暂停” ToastUtil.showShortToast("继续播放: " + qySongList.get(0).getTitle()); return; } // ★★★ 新播放:不是本列表 → 先重置所有按钮 resetAllExternalButtons(); // 开始播放 playerManager.playFromExternalList(requireContext(), qySongList, 0, "qingyin"); playerManager.setPlayingFromPrivate(true); // 更新 UI qy_start.setImageResource(R.mipmap.img_zt); // 设为“暂停” rotationHelper.stopRotation(); MusicBean.DataBean firstSong = qySongList.get(0); ToastUtil.showShortToast("播放轻音乐: " + firstSong.getTitle()); updatePlayButtonIcon(); // iv_bf 变成“暂停”图标 } /** * 播放小众歌单 */ private void playXiaoZhongFirstSong() { if (xzSongList == null || xzSongList.isEmpty()) { ToastUtil.showShortToast("暂无小众歌曲"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "xiaozhong".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放本列表 → 暂停 if (isPlaying && isFromThisList) { playerManager.pause(); xz_start.setImageResource(R.mipmap.img_bf); ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停本列表 → 继续播放 if (!isPlaying && isFromThisList) { playerManager.resume(); xz_start.setImageResource(R.mipmap.img_zt); ToastUtil.showShortToast("继续播放: " + xzSongList.get(0).getTitle()); return; } // 新播放 → 重置所有按钮 resetAllExternalButtons(); // 开始播放 playerManager.playFromExternalList(requireContext(), xzSongList, 0, "xiaozhong"); playerManager.setPlayingFromPrivate(true); // 更新 UI xz_start.setImageResource(R.mipmap.img_zt); rotationHelper.stopRotation(); ToastUtil.showShortToast("播放小众歌曲: " + xzSongList.get(0).getTitle()); updatePlayButtonIcon(); // iv_bf 变成“暂停”图标 } /** * 根据当前播放状态来源,同步更新所有外部播放按钮的图标 */ private void updateExternalPlayButtons() { boolean isPlaying = playerManager.isPlaying(); String currentTag = playerManager.getCurrentPlaylistTag(); // 私人专属 if (isPlaying && "private".equals(currentTag)) { sr_start.setImageResource(R.mipmap.img_zt); } else { sr_start.setImageResource(R.mipmap.img_bf); } // 轻音乐 if (isPlaying && "qingyin".equals(currentTag)) { qy_start.setImageResource(R.mipmap.img_zt); } else { qy_start.setImageResource(R.mipmap.img_bf); } // 小众音乐 if (isPlaying && "xiaozhong".equals(currentTag)) { xz_start.setImageResource(R.mipmap.img_zt); } else { xz_start.setImageResource(R.mipmap.img_bf); } } @Override public void onDestroy() { // playerManager.release(); rotationHelper.stopRotation(); super.onDestroy(); } @Override public void onResume() { super.onResume(); // 1. 更新主按钮图标 updatePlayButtonIcon(); // 2. 应用主题 applyCurrentTheme(); // 3. 如果正在播放,尝试同步到当前播放项 if (playerManager.isPlaying()) { int currentPos = playerManager.getCurrentPlayingPosition(); // 只有来自主列表的才做滚动旋转 if (!playerManager.isPlayingFromPrivate()) { // 假设 isPlayingFromPrivate 表示非主列表 syncToCurrentPlayingItem(currentPos); } } } /** * 滚动并高亮当前正在播放的歌曲 */ 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); // 等待滚动接近完成 } }在不动原有逻辑代码,修改当我 songTopAdapter.setOnItemClickListener((点击这个跳转到activity页面播放songTopAdapter歌曲,返回fragment,在activity页面歌曲还在播放的情况下再在PrivateAdapter适配器点击playBtn播放音乐,歌曲正常播放,但是按钮状态没变成暂停状态,还是播放状态,还有当我点击playBtn播放音乐frgment页面的iv_bf按钮状态应该变回暂停状态但是他没变
12-05
package com.weishitech.qichechangtingyinyue.fragment.home; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.hfd.common.base.BaseActivity; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.bean.FavoriteManager; import com.weishitech.qichechangtingyinyue.bean.MusicBean; import com.weishitech.qichechangtingyinyue.bean.MusicCache; import com.weishitech.qichechangtingyinyue.bean.PlayHistoryManager; import com.weishitech.qichechangtingyinyue.bean.SharedMusicViewModel; import com.weishitech.qichechangtingyinyue.fragment.Adapter.RecentPlayAdapter; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import java.util.ArrayList; import java.util.List; public class LyricsActivity extends BaseActivity { // UI Views TextView tv_back, tv_song_name, tv_sing_name, tv_start_time, tv_end_time; ImageView iv_sing_logo, iv_tj, iv_gd, iv_xh, iv_sys, iv_bf, iv_xys, iv_zjbf; SeekBar seekbar; private boolean fromSearch = false; private boolean isSingleLoop = false; // 单曲循环开关 private FavoriteManager favoriteManager; private boolean isCurrentSongFavorite = false; // 声明 ViewModel private SharedMusicViewModel sharedViewModel; // 播放管理器 private MusicPlayerManager playerManager; private boolean isBoundToCurrentSong = false; // 是否已绑定当前歌曲 // 数据接收字段 private String title, singer, coverUrl, musicUrl; private int songPosition,totalSongCount; // 进度更新 private final Handler handler = new Handler(); private final Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (playerManager != null && playerManager.isPlaying()) { int currentPosition = playerManager.getCurrentPosition(); int duration = playerManager.getDuration(); if (duration > 0) { seekbar.setMax(duration); seekbar.setProgress(currentPosition); // 更新时间文本(格式 mm:ss) tv_start_time.setText(formatTime(currentPosition)); tv_end_time.setText(formatTime(duration)); } } handler.postDelayed(this, 1000); // 每秒更新一次 } }; private List<MusicBean.DataBean> sourceList; @Override protected int setLayout() { return R.layout.activity_lyrics; } @Override protected void setView() { tv_back = fvbi(R.id.tv_back); iv_sing_logo = fvbi(R.id.iv_sing_logo); tv_song_name = fvbi(R.id.tv_song_name); tv_sing_name = fvbi(R.id.tv_sing_name); iv_tj = fvbi(R.id.iv_tj); iv_gd = fvbi(R.id.iv_gd); seekbar = fvbi(R.id.seekbar); tv_start_time = fvbi(R.id.tv_start_time); tv_end_time = fvbi(R.id.tv_end_time); iv_xh = fvbi(R.id.iv_xh); iv_sys = fvbi(R.id.iv_sys); iv_bf = fvbi(R.id.iv_bf); iv_xys = fvbi(R.id.iv_xys); iv_zjbf = fvbi(R.id.iv_zjbf); } @Override protected void setData() { Bundle bundle = getIntent().getExtras(); if (bundle != null) { title = bundle.getString("title"); singer = bundle.getString("singer"); coverUrl = bundle.getString("cover_url"); musicUrl = bundle.getString("music_url"); songPosition = bundle.getInt("position", -1); totalSongCount = bundle.getInt("total_count", 0); fromSearch = bundle.getBoolean("from_search", false); // 接收来源标记 // 接收来源列表(关键!) if (bundle.containsKey("source_list")) { sourceList = (List<MusicBean.DataBean>) bundle.getSerializable("source_list"); totalSongCount = sourceList.size(); // 再次确认长度 } if (songPosition < 0 || songPosition >= totalSongCount) { ToastUtil.showShortToast("歌曲位置无效"); finish(); return; } tv_song_name.setText(title); tv_sing_name.setText(singer); Glide.with(this) .load(coverUrl) .into(iv_sing_logo); } // 初始化播放器 //使用单例 playerManager = MusicPlayerManager.getInstance(); // 注册播放状态监听 setupPlaybackListener(); // 绑定当前歌曲(检查是否已在播放) bindToCurrentSong(); // 初始化收藏管理器 favoriteManager = FavoriteManager.getInstance(this); updateFavoriteState(); // 更新按钮状态 // 初始化 ViewModel sharedViewModel = new ViewModelProvider(this).get(SharedMusicViewModel.class); // 只要进入页面,就视为“播放此歌”,记录历史 if (title != null && musicUrl != null && coverUrl != null) { MusicBean.DataBean currentSong = new MusicBean.DataBean(); currentSong.setTitle(title); currentSong.setSinger(singer); currentSong.setCover(coverUrl); currentSong.setMusic(musicUrl); currentSong.setSongTime(formatTime(playerManager.getDuration())); // 可选 //记录播放历史 PlayHistoryManager.getInstance(this).addPlayRecord(currentSong); } } @Override protected void setClick() { tv_back.setOnClickListener(v -> finish()); iv_sys.setOnClickListener(v -> { if (songPosition <= 0) { ToastUtil.showShortToast("当前已是第一首"); return; } playMusicAtPosition(songPosition - 1); }); iv_xh.setOnClickListener(v -> { isSingleLoop = !isSingleLoop; if (isSingleLoop) { ToastUtil.showShortToast("已开启单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); // 假设有这个资源 } else { ToastUtil.showShortToast("已关闭单曲循环"); iv_xh.setImageResource(R.mipmap.img_xh); } }); iv_xys.setOnClickListener(v -> { if (songPosition >= totalSongCount - 1) { ToastUtil.showShortToast("当前已是最后一首"); return; } playMusicAtPosition(songPosition + 1); }); iv_tj.setOnClickListener(v -> { if (title == null || musicUrl == null) { ToastUtil.showShortToast("歌曲信息不完整"); return; } MusicBean.DataBean currentSong = new MusicBean.DataBean(); currentSong.setTitle(title); currentSong.setSinger(singer); currentSong.setCover(coverUrl); currentSong.setMusic(musicUrl); currentSong.setSongTime(formatTime(playerManager.getDuration())); // 可选 if (isCurrentSongFavorite) { // 已收藏 → 取消收藏 favoriteManager.removeFromFavorites(musicUrl); iv_tj.setImageResource(R.mipmap.img_tj); // 未收藏图标 ToastUtil.showShortToast("已取消收藏"); } else { // 未收藏 → 添加收藏 favoriteManager.addToFavorites(currentSong); iv_tj.setImageResource(R.mipmap.img_tj_u); // 已收藏图标 ToastUtil.showShortToast("已添加到我喜欢"); } isCurrentSongFavorite = !isCurrentSongFavorite; //通知所有页面,收藏列表已改变 List<MusicBean.DataBean> newList = favoriteManager.getFavoriteList(); sharedViewModel.notifyFavoriteChanged(newList); }); iv_zjbf.setOnClickListener(v -> showRecentPlayDialog()); // 播放/暂停按钮 iv_bf.setOnClickListener(v -> { if (!isBoundToCurrentSong) { ToastUtil.showShortToast("暂无歌曲信息"); return; } if (playerManager.isPlaying()) { playerManager.pause(); } else { playerManager.resume(); } updatePlayButtonIcon(); }); // SeekBar 拖动控制 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { tv_start_time.setText(formatTime(progress)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 用户开始拖动 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 用户停止拖动,跳转到指定位置 if (playerManager != null && isBoundToCurrentSong) { playerManager.seekTo(seekbar.getProgress()); } } }); } private void bindToCurrentSong() { if (musicUrl == null || title == null) return; boolean isPlaying = playerManager.isPlaying(); int currentPos = playerManager.getCurrentPlayingPosition(); // 判断是否就是当前正在播放的歌曲 if (isPlaying && currentPos == songPosition) { // 是同一首歌 → 直接同步状态 isBoundToCurrentSong = true; updatePlayButtonIcon(); // 显示“暂停” startUpdatingProgress(); // 开始更新进度条 } else { // 不是当前播放的 → 准备播放这首 playerManager.play(this, songPosition, musicUrl); isBoundToCurrentSong = true; updatePlayButtonIcon(); // 默认播放中 startUpdatingProgress(); } } private void setupPlaybackListener() { playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { if (position == songPosition) { runOnUiThread(() -> { updatePlayButtonIcon(); startUpdatingProgress(); }); } else { // 播放的是其他位置的歌曲 → 当前页面应暂停状态 runOnUiThread(() -> { stopUpdatingProgress(); iv_bf.setImageResource(R.mipmap.img_gc_bf); // 显示播放图标 }); } } @Override public void onPaused() { runOnUiThread(() -> { updatePlayButtonIcon(); stopUpdatingProgress(); }); } @Override public void onCompletion() { runOnUiThread(() -> { // 停止当前进度更新 stopUpdatingProgress(); seekbar.setProgress(0); tv_start_time.setText("00:00"); if (isSingleLoop) { // 重新播放当前歌曲 playerManager.play(LyricsActivity.this, songPosition, musicUrl); startUpdatingProgress(); updatePlayButtonIcon(); } else { // 自动播放下一首 int nextPosition = songPosition + 1; if (nextPosition < totalSongCount) { playMusicAtPosition(nextPosition); } else { // 已到最后 → 可选:循环播放第一首 or 提示 ToastUtil.showShortToast("已播放完毕"); updatePlayButtonIcon(); // 显示为暂停状态 // 如果你想循环回第一首,取消下面注释 playMusicAtPosition(0); } } }); } @Override public void onError(String errorMsg) { runOnUiThread(() -> { // ToastUtil.showShortToast("播放出错:" + errorMsg); updatePlayButtonIcon(); stopUpdatingProgress(); }); } }); } private void updatePlayButtonIcon() { if (playerManager.isPlaying()) { iv_bf.setImageResource(R.mipmap.img_gc_zt); // 暂停图标 } else { iv_bf.setImageResource(R.mipmap.img_gc_bf); // 播放图标 } } private void startUpdatingProgress() { stopUpdatingProgress(); // 防止重复 handler.postDelayed(updateProgressRunnable, 0); } private void stopUpdatingProgress() { handler.removeCallbacks(updateProgressRunnable); } @Override public void onResume() { super.onResume(); // 页面可见时尝试恢复状态 if (isBoundToCurrentSong) { updatePlayButtonIcon(); } } @Override protected void onPause() { super.onPause(); // 可选:不移除监听,让后台也能播放 } @Override protected void onDestroy() { stopUpdatingProgress(); // 注意:不要 release() playerManager,否则其他页面会中断 // playerManager.release(); ❌ 不要在这里释放 super.onDestroy(); } // 时间格式化工具 private String formatTime(int milliseconds) { int seconds = milliseconds / 1000; int minutes = seconds / 60; seconds = seconds % 60; return String.format("%02d:%02d", minutes, seconds); } private void playMusicAtPosition(int pos) { // 使用 MusicCache 判断边界(替代 musicDataList) if (pos < 0 || pos >= totalSongCount) { return; // 越界防护 } MusicBean.DataBean song; if (sourceList != null && pos < sourceList.size()) { song = sourceList.get(pos); } else { // 回退到主列表(兼容主列表播放) song = MusicCache.getMusicAt(pos); } // 播放指定位置的音乐 playerManager.play(this, pos, song.getMusic()); // 更新界面 updateUIForNewSong(song, pos); } /** * 播放新歌时更新界面内部状态 */ private void updateUIForNewSong(MusicBean.DataBean song, int position) { // 更新成员变量 this.title = song.getTitle(); this.singer = song.getSinger(); this.coverUrl = song.getCover(); this.musicUrl = song.getMusic(); this.songPosition = position; // 更新 UI 显示 tv_song_name.setText(title); tv_sing_name.setText(singer); if (isDestroyed() || isFinishing()) return; Glide.with(this) .load(coverUrl) .into(iv_sing_logo); // 标记已绑定当前歌曲 isBoundToCurrentSong = true; // 更新播放按钮为“正在播放” updatePlayButtonIcon(); // 开始进度条更新 startUpdatingProgress(); // Toast 提示 // ToastUtil.showShortToast("播放: " + title); updateFavoriteState(); PlayHistoryManager.getInstance(this).addPlayRecord(song); } private void updateFavoriteState() { if (musicUrl == null) { iv_tj.setImageResource(R.mipmap.img_tj); isCurrentSongFavorite = false; return; } isCurrentSongFavorite = favoriteManager.isFavorite(musicUrl); iv_tj.setImageResource(isCurrentSongFavorite ? R.mipmap.img_tj_u : R.mipmap.img_tj); } private void showRecentPlayDialog() { // 创建 BottomSheetDialog BottomSheetDialog dialog = new BottomSheetDialog(this); // 绑定布局 View contentView = getLayoutInflater().inflate(R.layout.dialog_recent_play, null); dialog.setContentView(contentView); // 找控件 TextView tvTitle = contentView.findViewById(R.id.tv_title); RecyclerView rvRecent = contentView.findViewById(R.id.rv_recent); // 加载数据 PlayHistoryManager historyManager = PlayHistoryManager.getInstance(this); List<MusicBean.DataBean> historyList = historyManager.getHistoryList(); tvTitle.setText("最近播放 (" + historyList.size() + ")"); // 设置适配器 RecentPlayAdapter adapter = new RecentPlayAdapter(); rvRecent.setLayoutManager(new LinearLayoutManager(this)); rvRecent.setAdapter(adapter); adapter.setData(historyList); if (musicUrl != null) { adapter.setCurrentPlayingSong(musicUrl); // 入当前播放的 musicUrl } // 设置点击事件 adapter.setOnItemClickListener((song, position) -> { // 跳转到该歌曲的歌词页 playMusicAtPositionFromHistory(song); dialog.dismiss(); // 关闭弹窗 }); // 显示 dialog.show(); } private void playMusicAtPositionFromHistory(MusicBean.DataBean song) { // 查找当前 sourceList 中是否有这首歌 int pos = -1; if (sourceList != null) { for (int i = 0; i < sourceList.size(); i++) { if (sourceList.get(i).getMusic().equals(song.getMusic())) { pos = i; break; } } } // 如果没找到,默认为 0 或添加进临时播放? if (pos == -1) { // 可选择重新构造列表,或将它作为单曲播放 pos = 0; List<MusicBean.DataBean> temp = new ArrayList<>(); temp.add(song); sourceList = temp; totalSongCount = 1; } updateUIForNewSong(song, pos); playerManager.play(this, pos, song.getMusic()); // ToastUtil.showShortToast("正在播放:" + song.getTitle()); } } package com.weishitech.qichechangtingyinyue; import android.annotation.SuppressLint; import android.view.View; import android.widget.ImageView; import androidx.fragment.app.Fragment; import com.umeng.commonsdk.UMConfigure; import com.weishitech.qichechangtingyinyue.adtakubase.activity.BaseBindActivity; import com.weishitech.qichechangtingyinyue.adtakubase.inter.insert.IAdInsertView; import com.weishitech.qichechangtingyinyue.adtakubase.inter.nativ.IAdNativeView; import com.weishitech.qichechangtingyinyue.databinding.ActivityMainBinding; import com.weishitech.qichechangtingyinyue.fragment.Adapter.NavigationFragmentAdapter; import com.weishitech.qichechangtingyinyue.fragment.specail.SpecialFragment; import com.weishitech.qichechangtingyinyue.fragment.home.HomeFragment; import com.weishitech.qichechangtingyinyue.fragment.lilv.LiLvFragment; import com.weishitech.qichechangtingyinyue.fragment.tools.ToolsFragment; import com.weishitech.qichechangtingyinyue.fragment.wode.WoDeFragment; import java.util.ArrayList; import java.util.List; public class MainActivity extends BaseBindActivity<ActivityMainBinding> implements View.OnClickListener,IAdInsertView, IAdNativeView { private ImageView imgCurrent; //其中定义了四个Fragment,放入ArrayList中 ArrayList<Fragment> fragments = new ArrayList<>(); //五个fragments添加,暂时使用TempFragment页面做页面简单展示 HomeFragment homeFragment; LiLvFragment liLvFragment; SpecialFragment specialFragment; //WeatherFragment weatherFragment; ToolsFragment toolsFragment; WoDeFragment woDeFragment; //int index = 0;//标记当前页码 private List<AppAdEnum> mAdEnumList; @Override protected void init() { // SDK预初始化函数不会采集设备信息,也不会向友盟后台上报数据。 // preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验 UMConfigure.preInit(getApplication(), LCAppcation.umengKey, LCAppcation.channelName); //初始化组件化基础库, 所有友盟业务SDK都必须调用此初始化接口。 //建议在宿主App的Application.onCreate函数中调用基础组件库初始化函数。 UMConfigure.init(getApplication(), LCAppcation.umengKey, LCAppcation.channelName, UMConfigure.DEVICE_TYPE_PHONE, ""); /** *设置组件化的Log开关 *参数: boolean 默认为false,如需查看LOG设置为true */ UMConfigure.setLogEnabled(BuildConfig.DEBUG); mBinding.include.tabNavigationBottomRili.setOnClickListener(this); mBinding.include.tabNavigationBottomLilv.setOnClickListener(this); mBinding.include.tabNavigationBottomSpecail.setOnClickListener(this); mBinding.include.tabNavigationBottomPssb.setOnClickListener(this); mBinding.include.tabNavigationBottomWode.setOnClickListener(this); //默认选中日历 mBinding.include.imgRili.setSelected(true); mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.tab_select)); imgCurrent = mBinding.include.imgRili; //设置不可滑动 mBinding.idViewpager.setUserInputEnabled(false); homeFragment = new HomeFragment(); liLvFragment = new LiLvFragment(); specialFragment = new SpecialFragment(); // toolsFragment = new ToolsFragment(); woDeFragment = new WoDeFragment(); fragments.add(homeFragment); fragments.add(liLvFragment); fragments.add(specialFragment); // fragments.add(toolsFragment); fragments.add(woDeFragment); //装配NavigationFrameworkAdapter适配器 NavigationFragmentAdapter pagerAdapter = new NavigationFragmentAdapter(getSupportFragmentManager(), getLifecycle(), fragments); //绑定适配器 mBinding.idViewpager.setAdapter(pagerAdapter); if (mAdEnumList == null) { mAdEnumList = new ArrayList<>(); } mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB1); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB2); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB3); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB4); mAdEnumList.add(AppAdEnum.AD_INTERSTITIAL_TAB5); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB1); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB2); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB3); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB4); mAdEnumList.add(AppAdEnum.AD_NATIVE_TAB5); setTextColor(0); } //页面切换方法,已经含两种情况,滑动点击切换 @SuppressLint("NonConstantResourceId") private void changeTab(int position) { imgCurrent.setSelected(false); //在android中使用switch case语句可能会出现报错冒红现象,请看最后的注意事项,可以解决这个问题 switch (position) { case R.id.tab_navigation_bottom_rili: //点击图片后,切换页面 mBinding.idViewpager.setCurrentItem(0,false); setTextColor(0); case 0: //滑动到第一个界面(索引为0)触发被选中效果,即切换图标(从黑→绿) //imgWeChat.setSelected(true)这部分功能请看后面的tab_navigation__bottom部分 mBinding.include.imgRili.setSelected(true); imgCurrent = mBinding.include.imgRili; break; case R.id.tab_navigation_bottom_lilv: mBinding.idViewpager.setCurrentItem(1,false); setTextColor(1); case 1: mBinding.include.imgLilv.setSelected(true); imgCurrent = mBinding.include.imgLilv; break; case R.id.tab_navigation_bottom_specail: mBinding.idViewpager.setCurrentItem(2,false); setTextColor(2); case 2: mBinding.include.imgSpecail.setSelected(true); imgCurrent = mBinding.include.imgSpecail; break; case R.id.tab_navigation_bottom_pssb: mBinding.idViewpager.setCurrentItem(3,false); setTextColor(3); case 3: mBinding.include.imgPssb.setSelected(true); imgCurrent = mBinding.include.imgPssb; break; case R.id.tab_navigation_bottom_wode: mBinding.idViewpager.setCurrentItem(4,false); setTextColor(4); case 4: mBinding.include.imgWode.setSelected(true); imgCurrent = mBinding.include.imgWode; break; } } private void setTextColor(int index){ initInsert(mAdEnumList.get(index)); initNative(mAdEnumList.get(index+fragments.size())); mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvLilv.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvSpecail.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvPssb.setTextColor(getResources().getColor(R.color.text_tab)); mBinding.include.tvWode.setTextColor(getResources().getColor(R.color.text_tab)); switch (index){ case 0: mBinding.include.tvRili.setTextColor(getResources().getColor(R.color.tab_select)); break; case 1: mBinding.include.tvLilv.setTextColor(getResources().getColor(R.color.tab_select)); break; case 2: mBinding.include.tvSpecail.setTextColor(getResources().getColor(R.color.tab_select)); break; case 3: mBinding.include.tvPssb.setTextColor(getResources().getColor(R.color.tab_select)); break; case 4: mBinding.include.tvWode.setTextColor(getResources().getColor(R.color.tab_select)); break; } } // 两次点击按钮之间的点击间隔不能少于1000毫秒 private static final long MIN_CLICK_DELAY_TIME = 500; private static long lastClickTime; //点击导航栏时,将图片的ID入changeTab,触发切换页面事件 @Override public void onClick(View v) { long curClickTime = System.currentTimeMillis(); if((curClickTime - lastClickTime) >= MIN_CLICK_DELAY_TIME) { // 超过点击间隔后再将lastClickTime重置为当前点击时间 lastClickTime = curClickTime; changeTab(v.getId()); } } /** * 跳转到保值fragment * */ public void JumpToPrice() { imgCurrent.setSelected(false); mBinding.include.tvSpecail.setSelected(true); imgCurrent = mBinding.include.imgSpecail; setTextColor(2); mBinding.idViewpager.setCurrentItem(2,false); } }我想把LyricsActivity正在播放歌曲的封面图到MainActivity怎么修改
12-06
package com.weishitech.qichechangtingyinyue.fragment.home; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.hfd.common.base.BaseActivity; import com.hfd.common.util.ToastUtil; import com.weishitech.qichechangtingyinyue.R; import com.weishitech.qichechangtingyinyue.utils.MusicPlayerManager; import com.weishitech.qichechangtingyinyue.utils.OnMultiClickListener; public class LyricsActivity extends BaseActivity { // UI Views TextView tv_back, tv_song_name, tv_sing_name, tv_start_time, tv_end_time; ImageView iv_sing_logo, iv_tj, iv_gd, iv_xh, iv_sys, iv_bf, iv_xys, iv_zjbf; SeekBar seekbar; // 播放管理器 private MusicPlayerManager playerManager; private boolean isBoundToCurrentSong = false; // 是否已绑定当前歌曲 // 数据接收字段 private String title, singer, coverUrl, musicUrl; private int songPosition; // 进度更新 private final Handler handler = new Handler(); private final Runnable updateProgressRunnable = new Runnable() { @Override public void run() { if (playerManager != null && playerManager.isPlaying()) { int currentPosition = playerManager.getCurrentPosition(); int duration = playerManager.getDuration(); if (duration > 0) { seekbar.setMax(duration); seekbar.setProgress(currentPosition); // 更新时间文本(格式 mm:ss) tv_start_time.setText(formatTime(currentPosition)); tv_end_time.setText(formatTime(duration)); } } handler.postDelayed(this, 1000); // 每秒更新一次 } }; @Override protected int setLayout() { return R.layout.activity_lyrics; } @Override protected void setView() { tv_back = fvbi(R.id.tv_back); iv_sing_logo = fvbi(R.id.iv_sing_logo); tv_song_name = fvbi(R.id.tv_song_name); tv_sing_name = fvbi(R.id.tv_sing_name); iv_tj = fvbi(R.id.iv_tj); iv_gd = fvbi(R.id.iv_gd); seekbar = fvbi(R.id.seekbar); tv_start_time = fvbi(R.id.tv_start_time); tv_end_time = fvbi(R.id.tv_end_time); iv_xh = fvbi(R.id.iv_xh); iv_sys = fvbi(R.id.iv_sys); iv_bf = fvbi(R.id.iv_bf); iv_xys = fvbi(R.id.iv_xys); iv_zjbf = fvbi(R.id.iv_zjbf); } @Override protected void setData() { Bundle bundle = getIntent().getExtras(); if (bundle != null) { title = bundle.getString("title"); singer = bundle.getString("singer"); coverUrl = bundle.getString("cover_url"); musicUrl = bundle.getString("music_url"); songPosition = bundle.getInt("position", -1); tv_song_name.setText(title); tv_sing_name.setText(singer); Glide.with(this) .load(coverUrl) .transform(new CircleCrop()) .into(iv_sing_logo); } // 初始化播放器 //使用单例 playerManager = MusicPlayerManager.getInstance(); // 注册播放状态监听 setupPlaybackListener(); // 绑定当前歌曲(检查是否已在播放) bindToCurrentSong(); } @Override protected void setClick() { tv_back.setOnClickListener(v -> finish()); // 播放/暂停按钮 iv_bf.setOnClickListener(v -> { if (!isBoundToCurrentSong) { ToastUtil.showShortToast("暂无歌曲信息"); return; } if (playerManager.isPlaying()) { playerManager.pause(); } else { playerManager.resume(); } updatePlayButtonIcon(); }); // SeekBar 拖动控制 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { tv_start_time.setText(formatTime(progress)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 用户开始拖动 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 用户停止拖动,跳转到指定位置 if (playerManager != null && isBoundToCurrentSong) { playerManager.seekTo(seekbar.getProgress()); } } }); } private void bindToCurrentSong() { if (musicUrl == null || title == null) return; boolean isPlaying = playerManager.isPlaying(); int currentPos = playerManager.getCurrentPlayingPosition(); // 判断是否就是当前正在播放的歌曲 if (isPlaying && currentPos == songPosition) { // 是同一首歌 → 直接同步状态 isBoundToCurrentSong = true; updatePlayButtonIcon(); // 显示“暂停” startUpdatingProgress(); // 开始更新进度条 } else { // 不是当前播放的 → 准备播放这首 playerManager.play(this, songPosition, musicUrl); isBoundToCurrentSong = true; updatePlayButtonIcon(); // 默认播放中 startUpdatingProgress(); } } private void setupPlaybackListener() { playerManager.setOnPlaybackStateChangedListener(new MusicPlayerManager.OnPlaybackStateChangedListener() { @Override public void onPlaying(int position) { if (position == songPosition) { runOnUiThread(() -> { updatePlayButtonIcon(); startUpdatingProgress(); }); } } @Override public void onPaused() { runOnUiThread(() -> { updatePlayButtonIcon(); stopUpdatingProgress(); }); } @Override public void onCompletion() { runOnUiThread(() -> { updatePlayButtonIcon(); stopUpdatingProgress(); seekbar.setProgress(0); tv_start_time.setText("00:00"); }); } @Override public void onError(String errorMsg) { runOnUiThread(() -> { ToastUtil.showShortToast("播放出错:" + errorMsg); updatePlayButtonIcon(); stopUpdatingProgress(); }); } }); } private void updatePlayButtonIcon() { if (playerManager.isPlaying()) { iv_bf.setImageResource(R.mipmap.img_lan_zt); // 暂停图标 } else { iv_bf.setImageResource(R.mipmap.img_lan_bf); // 播放图标 } } private void startUpdatingProgress() { stopUpdatingProgress(); // 防止重复 handler.postDelayed(updateProgressRunnable, 0); } private void stopUpdatingProgress() { handler.removeCallbacks(updateProgressRunnable); } @Override public void onResume() { super.onResume(); // 页面可见时尝试恢复状态 if (isBoundToCurrentSong) { updatePlayButtonIcon(); } } @Override protected void onPause() { super.onPause(); // 可选:不移除监听,让后台也能播放 } @Override protected void onDestroy() { stopUpdatingProgress(); // 注意:不要 release() playerManager,否则其他页面会中断 // playerManager.release(); ❌ 不要在这里释放 super.onDestroy(); } // 时间格式化工具 private String formatTime(int milliseconds) { int seconds = milliseconds / 1000; int minutes = seconds / 60; seconds = seconds % 60; return String.format("%02d:%02d", minutes, seconds); } } 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.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.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; 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.R; import com.weishitech.qichechangtingyinyue.bean.MusicBean; 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.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 isUserAuthorizedPlayback = false; // 用户是否已授权播放(点击/滑动) private boolean isMainPlaybackActive = false; // 是否由主流程控制播放状态 private int lastPlayedPosition = -1; // 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; @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()); // 默认显示蓝色“播放”图标 } @Override protected void initClick() { // 搜索跳转 iv_ss.setOnClickListener(v -> toClass(SearchActivity.class)); // 播放/暂停按钮 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 }); //私人音乐播放按钮点击 sr_start.setOnClickListener(v -> playPrivateFirstSong()); //轻音乐播放按钮点击 qy_start.setOnClickListener(v -> playQingyinFirstSong()); //小众音乐播放按钮点击 xz_start.setOnClickListener(v -> playXiaoZhongFirstSong()); relative1.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { if (privateSongList == null || privateSongList.isEmpty()) { ToastUtil.showShortToast("暂无数据"); return; } 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; } 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; } 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) { updatePlayButtonIcon(); startRotationForCurrentItem(position); } @Override public void onPaused() { updatePlayButtonIcon(); rotationHelper.stopRotation(); } @Override public void onCompletion() { // 来自主列表 → 播放下一首主歌 if (!playerManager.isPlayingFromPrivate()) { playNextSong(); return; } // 来自外部歌单 → 尝试播放下一首 boolean hasNext = playerManager.playNextInExternalList(); if (!hasNext) { ToastUtil.showShortToast("当前歌单已播放完毕"); updateStartButtonIcons(); // 所有按钮恢复“播放”图标 } } @Override public void onError(String errorMsg) { ToastUtil.showShortToast(errorMsg); updatePlayButtonIcon(); } }); } 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(); setupMusicRecyclerView(); } 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) -> { // 创建 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); // 跳转到 LyricsActivity toClass(LyricsActivity.class, bundle); }); //私人音乐适配器 // 从第三个元素(索引=2)开始,取最多20首歌曲 int start = 2; // 第三个元素的索引 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 privateAdapter = new PrivateAdapter(); // 设置横向 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); //轻音乐 // 确保 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); //小众音乐 // 确保 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); } 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); isUserAuthorizedPlayback = true; // 🔥 关键:只有完成首次布局后才允许自动播放 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()); ToastUtil.showShortToast("播放: " + bean.getTitle()); }); } private void playNextSong() { int nextPos = playerManager.getCurrentPlayingPosition() + 1; if (nextPos < musicDataList.size()) { playMusicAtPosition(nextPos); scrollToTriggerPosition(nextPos, rv); } else { ToastUtil.showShortToast("已播放完全部歌曲"); } } 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 center = (lm.getDecoratedLeft(view) + lm.getDecoratedRight(view)) / 2; int targetX = DisplayUtils.dp2px(requireContext(), 50f); return targetX - center; } @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; // Fragment 已 detach,不执行 boolean isPlaying = playerManager.isPlaying(); themeManager.applyThemeTo(line, relative, iv_bf, isPlaying); } private void updatePlayButtonIcon() { if (!isAdded()) return; // 如果正在播放私人歌单,则主按钮不响应 if (playerManager.isPlayingFromPrivate()) { iv_bf.setImageResource(themeManager.getPlayIconRes()); return; } // 否则:根据实际播放状态更新图标 boolean isPlaying = playerManager.isPlaying(); iv_bf.setImageResource(isPlaying ? themeManager.getPauseIconRes() : themeManager.getPlayIconRes()); } private void startRotationForCurrentItem(int position) { rotationHelper.stopRotation(); // 先停止任何正在进行的动画 RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(position); if (vh != null) { ImageView coverView = vh.itemView.findViewById(R.id.iv_song_logo); if (coverView != null) { rotationHelper.startRotation(coverView); } } } /** * 更新所有外部播放按钮为“播放”状态 */ private void updateStartButtonIcons() { sr_start.setImageResource(R.mipmap.img_lan_bf); qy_start.setImageResource(R.mipmap.img_lan_bf); xz_start.setImageResource(R.mipmap.img_lan_bf); } /** * 播放私人专属歌单 */ private void playPrivateFirstSong() { if (privateSongList == null || privateSongList.isEmpty()) { ToastUtil.showShortToast("暂无私人歌曲"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "private".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放该列表中的任意一首 → 暂停 if (isPlaying && isFromThisList) { playerManager.pause(); sr_start.setImageResource(R.mipmap.img_lan_bf); ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停,且属于该列表 → 恢复(不重新 prepare) if (!isPlaying && isFromThisList) { playerManager.resume(); sr_start.setImageResource(R.mipmap.img_lan_zt); int currentIndex = playerManager.getCurrentExternalIndex(); MusicBean.DataBean currentSong = privateSongList.get(currentIndex); ToastUtil.showShortToast("继续播放: " + currentSong.getTitle()); return; } // 否则:首次播放 or 切换到新列表 → 从 index=0 开始 playerManager.playFromExternalList(requireContext(), privateSongList, 0, "private"); playerManager.setPlayingFromPrivate(true); sr_start.setImageResource(R.mipmap.img_lan_zt); rotationHelper.stopRotation(); MusicBean.DataBean firstSong = privateSongList.get(0); ToastUtil.showShortToast("播放私人歌曲: " + firstSong.getTitle()); } private void playQingyinFirstSong() { if (qySongList == null || qySongList.isEmpty()) { ToastUtil.showShortToast("暂无私人歌曲"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "private".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放该列表中的任意一首 → 暂停 if (isPlaying && isFromThisList) { playerManager.pause(); qy_start.setImageResource(R.mipmap.img_lan_bf); ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停,且属于该列表 → 恢复(不重新 prepare) if (!isPlaying && isFromThisList) { playerManager.resume(); qy_start.setImageResource(R.mipmap.img_lan_zt); return; } // 否则:首次播放 or 切换到新列表 → 从 index=0 开始 playerManager.playFromExternalList(requireContext(), qySongList, 0, "private"); playerManager.setPlayingFromPrivate(true); qy_start.setImageResource(R.mipmap.img_lan_zt); rotationHelper.stopRotation(); MusicBean.DataBean firstSong = qySongList.get(0); ToastUtil.showShortToast("播放轻音歌曲: " + firstSong.getTitle()); } private void playXiaoZhongFirstSong() { if (xzSongList == null || xzSongList.isEmpty()) { ToastUtil.showShortToast("暂无私人歌曲"); return; } boolean isPlaying = playerManager.isPlaying(); boolean isFromThisList = "private".equals(playerManager.getCurrentPlaylistTag()); // 如果正在播放该列表中的任意一首 → 暂停 if (isPlaying && isFromThisList) { playerManager.pause(); xz_start.setImageResource(R.mipmap.img_lan_bf); ToastUtil.showShortToast("已暂停"); return; } // 如果已暂停,且属于该列表 → 恢复(不重新 prepare) if (!isPlaying && isFromThisList) { playerManager.resume(); xz_start.setImageResource(R.mipmap.img_lan_zt); int currentIndex = playerManager.getCurrentExternalIndex(); MusicBean.DataBean currentSong = xzSongList.get(currentIndex); ToastUtil.showShortToast("继续播放: " + currentSong.getTitle()); return; } // 否则:首次播放 or 切换到新列表 → 从 index=0 开始 playerManager.playFromExternalList(requireContext(), xzSongList, 0, "private"); playerManager.setPlayingFromPrivate(true); xz_start.setImageResource(R.mipmap.img_lan_zt); rotationHelper.stopRotation(); MusicBean.DataBean firstSong = xzSongList.get(0); ToastUtil.showShortToast("播放小众歌曲: " + firstSong.getTitle()); } @Override public void onDestroy() { // playerManager.release(); rotationHelper.stopRotation(); super.onDestroy(); } } 这是这两个的完整页面代码你看看怎么修改
12-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值