音乐播放器的实现(四)—— 歌曲列表、顺序播放、单曲循环、随机播放、自动下一曲

前言:
上一篇简单的实现了算是顺序播放的上一曲和下一曲,这篇加上播放模式(顺序播放、单曲循环、随机播放),再优化上/下一曲,同时显示所有歌曲的列表,并能点击播放对应的歌曲音频。

先看下最终效果:

列表循环ifelse python 列表循环和随机播放_mplayer


具体操作

一、首先,我们还是先完善UI面板:

1、在上一篇的基础上,新建一个按钮Button命名为pModeImage,Button的图片用来显示播放模式对应的图片(文本可以删掉);

2、准备三张图片放入Project面板中的Resources文件夹下的Sprite文件夹中(可根据自己需求放置,但一定要在Resources文件夹下,当然后台代码对应的路径也要更改),分别命名为:stright、circle和random;

3、新建一个Scroll View,用来显示歌曲的列表,在content下新建一个Button,用来点击播放对应歌曲。在content上添加布局组件,调整相关参数,使Button大小位置合适,最后把该Button拖至Project面板中形成一个预制体,存放在Prefab文件夹中,再删掉或隐藏掉content下的Button按钮。

最终效果如下图所示:

列表循环ifelse python 列表循环和随机播放_c#_02


二、核心代码

1、相对上一篇,我把播放音频的方法独立了出来,方便调用。

/// <summary>
    /// 播放索引为index的音频
    /// </summary>
    /// <param name="index">音频索引</param>
    void playMusic(int index)
    {
        aus.clip = auc[index];          //音频播放器的音频为aus数组中索引对应的音频
        slid.value = 0;                 //初始化进度条
        aus.time = 0;                   //初始化音乐的播放时间(从头开始播)
        aus.Play();                     //播放音频
    }

2、音乐列表

实例化每个音频按钮,形成音乐列表,该方法在Start()中调用,即开始运行时就形成歌曲列表。(其中

item为上面制作的Button预制体。)

列表循环ifelse python 列表循环和随机播放_列表循环ifelse python_03

列表循环ifelse python 列表循环和随机播放_c#_04

public GameObject item;         //要实例化的列表按钮对象,即Button预制体
    private GameObject it;          //实例化出的列表音频按钮
    void initItem()//音频列表
    {
        List<GameObject> L = new List<GameObject>();//列表L

        for (int i = 0; i < auc.Length; i++)
        {
            it = Instantiate(item);                 //实例化音频列表的各个按钮
            //设置父节点为Scroll View下的content
            it.transform.SetParent(GameObject.Find("Content").transform, false);
            //音频名
            string[] name = auc[i].name.Split('-');
            //连接音频名,序号、名字、作者
            it.transform.Find("Text").GetComponent<Text>().text = string.Format("<size=18>{0}  {1}--</size>" + "<size=18>{2}</size>", i + 1, name[0], name[1]);
            //把每个按钮放入列表L
            L.Add(it);
        }
        GameObject[] g = new GameObject[L.Count];   //数组g,长度等于列表L 的长度
        L.CopyTo(g);                                //把列表L的内容复制到数组g中
        //给每个音频按钮加上监听,点击即播放对应音频
        foreach(GameObject gob in g)
        {
            gob.GetComponent<Button>().onClick.AddListener(delegate
            {
                index = Array.IndexOf(g, gob);		//获取当前点击的按钮在数组g中的索引
                playMusic(index);                   //播放音频
            });
        }
    }

效果如下图所示:

列表循环ifelse python 列表循环和随机播放_列表循环ifelse python_05


3、播放模式

(1)枚举出顺序播放、单曲循环、随机播放这三个模式:

public enum playMode
    {
        stright,//列表循环
        circle1,//单曲循环
        random  //随机播放
    }
    private playMode playM = playMode.stright;          //初始是顺序播放
    private GameObject pModeImage;                      //播放模式的图片切换

在Start()中调用:

void initPlayMode()//初始化播放模式
    {
        //找到名为pModeImage的按钮
        pModeImage = GameObject.Find("pModeImage");
        //给它添加监听(调用PlayMode方法,来切换播放模式)
        pModeImage.GetComponent<Button>().onClick.AddListener(PlayMode);
    }

以下为PlayMode()方法:

//变量t,初始值为1
    int t = 1;
    /// <summary>
    /// 播放模式
    /// </summary>
    public void PlayMode()
    {
        t++;
        if (t == 1)
        {
            //播放模式为顺序播放
            playM = playMode.stright;
            //上传顺序播放对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/stright");
        }
        if(t==2)
        {
            //播放模式为单曲循环
            playM = playMode.circle1;
            //上传单曲循环对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/circle");
        }
        if(t==3)
        {
            //播放模式为随机播放
            playM = playMode.random;
            //上传速记播放对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/random");
            //初始化t
            t = 0;
        }
    }

(2)重新修改了LastMusic()和NextMusic()方法:
上一曲:

private void LastMusic()
    {
        if (playM == playMode.random)   //如果播放模式是随机播放
            randomRange();              //随机播放
        else
        {
            index--;                        //索引减一
            //若索引等于-1,即当前播放的音频是aus数组列表的第一首,则上一首应为aus数组列表的最后一首
            if (index == -1)
                index = auc.Length - 1;
            playMusic(index);
        }
        
    }

下一曲:

private void NextMusic()
    {
        if(playM==playMode.random)      //如果播放模式是随机播放
            randomRange();              //随机播放
        else
        {
            index++;                        //索引加一
            //若索引等于aus音频数组的长度,即当前播放的音频是最后一首,则下一首应为aus数组列表的第一首
            if (index == auc.Length)
                index = 0;
            playMusic(index);//播放音频
        }
        
    }

随机播放时调用的代码:

public  void  randomRange()//随机播放
    {
        int r = UnityEngine.Random.Range(0, auc.Length);//生成随机数(包含0,不包含auc.Length);
        
        if(index == r)                                      //如果随机数等于当前播放的音频的索引(避免播放同一首)
            r++;                                        //索引加一
        //若索引等于aus音频数组的长度,即当前播放的音频是最后一首,则下一首应为aus数组列表的第一首
        if (r == auc.Length)
            r = 0;
        playMusic(r);//播放音频
    }

4、自动播放下一曲
当进度条走到最后时,播放下一曲,若是单曲循环,则依旧播放当前的音频

void Slider()//当进度条走到最后时,播放下一曲
    {
        if (currentHour == clipHour && currentMinute == clipMinute && currentSecond == clipSecond)
        {
            if (playM == playMode.circle1)//如果播放模式是单曲循环,下一曲还是当前这首
                playMusic(index);
            else
                NextMusic();//下一曲
        }
    }

完整版代码:

DragSlider脚本不变。 Player脚本如下:

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Player: MonoBehaviour {
    public enum playMode
    {
        stright,//列表循环
        circle1,//单曲循环
        random  //随机播放
    }
    public Text musicName;          //显示歌曲的名字及歌手
    public Text nowTime;            //显示歌曲已播放的时间长度
    public Text allTime;            //显示当前歌曲的总时间长度
    public Slider slid;             //进度条
    public Transform buttons;       //按钮所在的集合体
    public AudioClip[] auc;         //存放歌曲的数组
    public AudioSource aus;         //音频播放器
    private int index;              //数组aus的索引

    private int currentHour, currentMinute, currentSecond;          //已播放的时间(时、分、秒)
    private int clipHour, clipMinute, clipSecond;                   //总时间(时、分、秒)

    private playMode playM=playMode.stright;                        //初始是顺序播放
    private GameObject pModeImage;                                  //播放模式的图片切换

    private GameObject vioce_butt, voice_text, voice_slid;          //音量按钮、音量数字、音量进度条
    int clickNum=0,value;//变量
    bool mouseIn;//鼠标进入

    public GameObject item;         //要实例化的列表按钮对象
    private GameObject it;          //实例化出的列表音频按钮

    public static Player _instance;
    void initItem()//音频列表
    {
        List<GameObject> L = new List<GameObject>();//列表L

        for (int i = 0; i < auc.Length; i++)
        {
            it = Instantiate(item);                 //实例化音频列表的各个按钮
            it.transform.SetParent(GameObject.Find("Content").transform, false);
            //音频名
            string[] name = auc[i].name.Split('-');
            //连接音频名,序号、名字、作者
            it.transform.Find("Text").GetComponent<Text>().text = string.Format("<size=18>{0}  {1}--</size>" + "<size=18>{2}</size>", i + 1, name[0], name[1]);
            //把每个按钮放入列表L
            L.Add(it);
        }
        GameObject[] g = new GameObject[L.Count];   //数组g,长度等于列表L 的长度
        L.CopyTo(g);                                //把列表L的内容复制到数组g中
        //给每个音频按钮加上监听,点击即播放对应音频
        foreach(GameObject gob in g)
        {
            gob.GetComponent<Button>().onClick.AddListener(delegate
            {
                index = Array.IndexOf(g, gob);
                playMusic(index);                   //播放音频
            });
        }
    }
    void initVoice()//初始化
    {
        vioce_butt = GameObject.Find("voice_button");
        voice_text = GameObject.Find("voice_text");
        voice_slid = GameObject.Find("voice_slider");
        //voice_slid.SetActive(false);                 //开始时声音进度条不显示(当鼠标放在音量按钮上时显示)
        voice_slid.GetComponent<Slider>().value = 20;//开始声音为20;
        //开始先调用一次,设置初始的音量大小
        voice();
        //给进度条添加监听,进度条的值改变即调用voice()方法
        voice_slid.GetComponent<Slider>().onValueChanged.AddListener(delegate { voice(); });
        //给声音按钮添加监听
        vioce_butt.GetComponent<Button>().onClick.AddListener(delegate
        {
            clickNum++;//点击按钮的次数
            if(clickNum==1)//1为打开静音,0为关闭静音
            {
                //打开音频播放器的静音
                aus.mute = true;
                //上传对应的静音的图片
                vioce_butt.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/voiceMute");
                //存下点击静音时的进度条的值
                value = (int)voice_slid.GetComponent<Slider>().value;
                //进度条的value值为0
                voice_slid.GetComponent<Slider>().value = 0;
            }
            else
            {
                //关闭音频播放器的静音
                aus.mute = false;
                //上传对应的不静音的图片
                vioce_butt.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/voice1");
                //进度条的值变为关闭静音前的值
                voice_slid.GetComponent<Slider>().value = value;
                //初始化点击次数
                clickNum = 0;
            }
        });

    }
    void initPlayMode()//初始化播放模式
    {
        //找到名为pModeImage的按钮
        pModeImage = GameObject.Find("pModeImage");
        //给它添加监听(调用PlayMode方法,来切换播放模式)
        pModeImage.GetComponent<Button>().onClick.AddListener(PlayMode);
    }

    
    void Start()
    {
        _instance = this;

        aus.Stop();                                                 //开始运行时不播放,点播放键才开始播放

        #region 注:该方式虽然可以直接达到拖动进度条就播放到进度条当前的音乐,但会产生滋滋啦啦的杂音,是因为进度条value变化,使之不断调用onValueChanged,从而让音乐的进度发生了变化,音乐前后颠倒,不断重叠
        ///
        /// 所以新建了个DragSlider脚本,挂在进度条上,来实现拖动播放的效果
        ///
        //slid.onValueChanged.AddListener(delegate
        //{
        //    //加上之后,避免拖动进度条到最后不松手时报错
        //    if (slid.value == 1)
        //        return;
        //    //给进度条添加事件监听,每当拖动进度条,歌曲从相应的位置播放
        //    aus.time = slid.value * aus.clip.length;
        //});
        #endregion

        foreach (Transform go in buttons)                           //遍历所有的操作按钮
        {
            go.GetComponent<Button>().onClick.AddListener(delegate  //根据按钮名给按钮添加事件监听
            {
                switch (go.name)
                {
                    case "lastM":       //点击“上一曲”按钮
                        LastMusic();
                        break;
                    case "pause":       //点击“暂停”按钮
                        Pause();
                        break;
                    case "play":        //点击“播放”按钮
                        Play();
                        break;
                    case "nextM":       //点击“下一曲”按钮
                        NextMusic();
                        break;
                }
            });
        }
        initItem();                                                 //音频列表
        initVoice();                                                //音量部分初始化
        initPlayMode();                                             //初始化播放模式
    }
    void Update () {
        //当前播放过的时间
        nowtime();
        //当前正在播放的音频的总时间
        alltime();
        //当前正在播放的音乐
        nowMusic();
        //单机左键,隐藏所有要隐藏的
        //setActiveFalse();
    }
    void nowtime()//当前播放过的时间
    {
        currentHour = (int)aus.time / 3600; //时
        currentMinute = (int)(aus.time - currentHour * 3600) / 60;//分
        currentSecond = (int)(aus.time - currentHour * 3600 - currentMinute * 60);//秒
                                                                                  
        //显示当前播放过的时间
        nowTime.text = string.Format("{0:D2}:{1:D2}:{2:D2} ",
            currentHour, currentMinute, currentSecond);
        //进度条变化
        //(之后更新版)如果当前没有拖拽进度条
        if(!DragSlider.isDrag)
            slid.value = aus.time / aus.clip.length;
    }
    /// <summary>
    /// 歌曲总时间
    /// </summary>
    void alltime()
    {
        //slid.value = 0;
        clipHour = (int)aus.clip.length / 3600;//时
        clipMinute = (int)(aus.clip.length - clipHour * 3600) / 60;//分
        clipSecond = (int)(aus.clip.length - clipHour * 3600 - clipMinute * 60);//秒
        //显示歌曲总时间
        allTime.text = string.Format("{0:D2}:{1:D2}:{2:D2}",
            clipHour, clipMinute, clipSecond);
    }
    /// <summary>
    /// 上一曲
    /// </summary>
    private void LastMusic()
    {
        if (playM == playMode.random)   //如果播放模式是随机播放
            randomRange();              //随机播放
        else
        {
            index--;                        //索引减一
            //若索引等于-1,即当前播放的音频是aus数组列表的第一首,则上一首应为aus数组列表的最后一首
            if (index == -1)
                index = auc.Length - 1;
            playMusic(index);
        }
        
    }
    private void Pause()                //暂停
    {
        aus.Pause();
    }
    private void Play()                 //播放
    {
        //如果当前正在播放,则返回
        if (aus.isPlaying)
            return;
        aus.Play();
    }
    /// <summary>
    /// 下一曲
    /// </summary>
    public void NextMusic()
    {
        if(playM==playMode.random)      //如果播放模式是随机播放
            randomRange();              //随机播放
        else
        {
            index++;                        //索引加一
            //若索引等于aus音频数组的长度,即当前播放的音频是最后一首,则下一首应为aus数组列表的第一首
            if (index == auc.Length)
                index = 0;
            playMusic(index);//播放音频
        }
        
    } 
    void nowMusic()                     //当前的音频
    {
        AudioClip clip = aus.clip;      //当前播放的音频
        string n = aus.clip.name;       //当前播放的音频的名字
        string[] na = n.Split('-');     //以“-”为分割点,把音频名分为若干部分

        //显示当前正在播放的歌曲的名字【歌曲名(默认字体,25号)+歌手名(默认字体,18号,红色)的形式】
        musicName.text = string.Format("<size=25>{0}</size>" + "\n<size=18><color=#FF0000FF>{1}</color></size>", na[0], na[1]);

        index = Array.IndexOf(auc, clip);//当前播放的音频在aus数组中的索引
        Slider();                        //当进度条走到最后时,播放下一曲
    }
    void Slider()//当进度条走到最后时,播放下一曲
    {
        if (currentHour == clipHour && currentMinute == clipMinute && currentSecond == clipSecond)
        {
            if (playM == playMode.circle1)//如果播放模式是单曲循环,下一曲还是当前这首
                playMusic(index);
            else
                NextMusic();//下一曲
        }
    }
    /// <summary>
    /// 播放索引为index的音频
    /// </summary>
    /// <param name="index">音频索引</param>
    void playMusic(int index)
    {
        aus.clip = auc[index];          //音频播放器的音频为aus数组中索引对应的音频
        slid.value = 0;                 //初始化进度条
        aus.time = 0;                   //初始化音乐的播放时间(从头开始播)
        aus.Play();                     //播放音频
    }

    //变量t
    int t = 1;
    /// <summary>
    /// 播放模式
    /// </summary>
    public void PlayMode()
    {
        t++;
        if (t == 1)
        {
            //播放模式为顺序播放
            playM = playMode.stright;
            //上传顺序播放对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/stright");
        }
        if(t==2)
        {
            //播放模式为单曲循环
            playM = playMode.circle1;
            //上传单曲循环对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/circle");
        }
        if(t==3)
        {
            //播放模式为随机播放
            playM = playMode.random;
            //上传速记播放对应的图片
            pModeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprite/random");
            //初始化t
            t = 0;
        }

    }
    //设置和显示音量大小
    void voice()
    {
        //把进度条最大值改为100,最小值为0
        //音频播放器的音量volume = 进度条的值 * 0.01f。(因为volume的范围为:0~1)
        aus.volume = voice_slid.GetComponent<Slider>().value * 0.01f;
        //音量的文本显示(为进度条的value值,value值是浮点型,这里显示成整型)
        voice_text.GetComponent<Text>().text = ((int)voice_slid.GetComponent<Slider>().value).ToString();
    }
    public  void voice_button(bool on)
    {
        if(on)
        {
            voice_slid.SetActive(true);
            mouseIn = true;
        }
        else
        {
            mouseIn = false;
            voice_slid.SetActive(false);
        } 
    }
    /// <summary>
    /// 单机左键,隐藏所有要隐藏的
    /// </summary>
    void setActiveFalse()
    {
        if(Input.GetMouseButtonDown(0))
        {
            if(mouseIn==false)
                voice_slid.SetActive(false);
        }
    }
  
    public  void  randomRange()//随机播放
    {
        int r = UnityEngine.Random.Range(0, auc.Length);//生成随机数(包含0,不包含auc.Length);
        
        if(index == r)                                      //如果随机数等于当前播放的音频的索引(避免播放同一首)
            r++;                                        //索引加一
        //若索引等于aus音频数组的长度,即当前播放的音频是最后一首,则下一首应为aus数组列表的第一首
        if (r == auc.Length)
            r = 0;
        playMusic(r);//播放音频
    }
    
}

代码备注的也比较详细