手机影音项目笔记(三)---音乐播放的处理

本文介绍了一个简单的音乐播放器应用程序的设计与实现过程。包括音乐列表的展示、音乐播放控制及服务的启动、播放进度同步和歌词滚动等功能。文章还涉及了自定义布局的通知栏设计。


音乐列表的适配器

public class AudioListAdapter extends CursorAdapter {

    public AudioListAdapter(Context context, Cursor c) {
        super(context, c);
    }

    public AudioListAdapter(Context context, Cursor c, boolean autoRequery) {
        super(context, c, autoRequery);
    }

    public AudioListAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);
    }

    @Override
    // 创建新的View,并初始化ViewHolder
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = View.inflate(context, R.layout.audio_item,null);
        ViewHolder holder = new ViewHolder();

        holder.tv_title = (TextView) view.findViewById(R.id.audio_item_tv_title);
        holder.tv_artist = (TextView) view.findViewById(R.id.audio_item_tv_artist);

        view.setTag(holder);
        return view;
    }

    @Override
    // 填充界面。cursor已经被移动到要获取数据的行
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();

        // 获取数据
        String title = cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME));
        title = StringUtils.formatTitle(title);
        String artist = cursor.getString(cursor.getColumnIndex(Media.ARTIST));

        // 填充内容
        holder.tv_title.setText(title);
        holder.tv_artist.setText(artist);
    }

    private class ViewHolder{
        TextView tv_title,tv_artist;
    }
}



音乐列表的fragment

public class AudioListFragment extends BaseFragment {

    private ListView listView;
    private AudioListAdapter mAdapter;

    @Override
    protected int getLayoutId() {
        return R.layout.fragment_audio_list;
    }

    @Override
    protected void initView() {
        listView = (ListView) findViewById(R.id.listview);
    }

    @Override
    protected void initListener() {

        mAdapter = new AudioListAdapter(getActivity(), null);
        listView.setAdapter(mAdapter);
        listView.setOnItemClickListener(new OnAudioItemClickListener());
    }

    @Override
    protected void initData() {
        // 获取音频数据
        ContentResolver resolver = getActivity().getContentResolver();
//        Cursor cursor = resolver.query(Media.EXTERNAL_CONTENT_URI, new String[]{Media.DATA, Media.DISPLAY_NAME, Media.ARTIST, Media._ID}, null, null, null);
//        CursorUtils.printCursor(cursor);
//        mAdapter.swapCursor(cursor);
        // 子线程查询数据库
        AsyncQueryHandler asyncQueryHandler = new MyAsyncQueryHandler(resolver);
        asyncQueryHandler.startQuery(0, mAdapter,Media.EXTERNAL_CONTENT_URI, new String[]{Media.DATA, Media.DISPLAY_NAME, Media.ARTIST, Media._ID}, null, null, null);
    }

    @Override
    protected void processClick(View v) {

    }

    private class OnAudioItemClickListener implements AdapterView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // 获取数据
            Cursor cursor = (Cursor) mAdapter.getItem(position);
            ArrayList<AudioItem> audioItems = AudioItem.parserListFromCursor(cursor);

            // 跳转到播放界面
            Intent intent = new Intent(getActivity(), AudioPlayerActivity.class);
            intent.putExtra("audioItems",audioItems);
            intent.putExtra("position",position);
            startActivity(intent);
        }
    }
}
AudioPlayeractivity

public class AudioPlayerActivity extends BaseActivity {

    private static final int MSG_UPDATE_POSITION = 0;
    private static final int MSG_ROLLING_LYRICS = 1;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_UPDATE_POSITION:
                    startUpdatePosition();
                    break;
                case MSG_ROLLING_LYRICS:
                    startRollingLyrics();
                    break;
            }
        }
    };

    private AudioServiceConnection conn;
    private AudioService.AudioBinder mAudioBinder;
    private ImageView iv_pause;
    private AudioReceiver audioReceiver;
    private TextView tv_title;
    private TextView tv_artist;
    private ImageView iv_wave;
    private TextView tv_position;
    private SeekBar sk_position;
    private ImageView iv_pre;
    private ImageView iv_next;
    private ImageView iv_playmode;
    private LyricsView lyricsView;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_audio_player;
    }

    @Override
    protected void initView() {
        // 顶部面板
        tv_title = (TextView) findViewById(R.id.audio_tv_title);

        // 中间部分
        tv_artist = (TextView) findViewById(R.id.audio_tv_artist);
        iv_wave = (ImageView) findViewById(R.id.audio_iv_wave);
        lyricsView = (LyricsView) findViewById(R.id.audio_lyricsview);

        // 底部部分
        tv_position = (TextView) findViewById(R.id.audio_tv_position);
        sk_position = (SeekBar) findViewById(R.id.audio_sk_position);
        iv_pause = (ImageView) findViewById(R.id.audio_iv_pause);
        iv_pre = (ImageView) findViewById(R.id.audio_iv_pre);
        iv_next = (ImageView) findViewById(R.id.audio_iv_next);
        iv_playmode = (ImageView) findViewById(R.id.audio_iv_playmode);
    }

    @Override
    protected void initListener() {
        iv_pause.setOnClickListener(this);
        iv_pre.setOnClickListener(this);
        iv_next.setOnClickListener(this);
        iv_playmode.setOnClickListener(this);

        sk_position.setOnSeekBarChangeListener(new OnAudioSeekBarChangeListener());

        // 注册广播
        IntentFilter filter = new IntentFilter("com.itheima.onPrepared");
        audioReceiver = new AudioReceiver();
        registerReceiver(audioReceiver, filter);
    }

    @Override
    protected void initData() {
        // 将数据转交给后台服务
        Intent intent = new Intent(getIntent());
        intent.setClass(this, AudioService.class);
        startService(intent);
        conn = new AudioServiceConnection();
        bindService(intent, conn, BIND_AUTO_CREATE);

        // 开启示波器动画
        AnimationDrawable wave_anim = (AnimationDrawable) iv_wave.getDrawable();
        wave_anim.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
        unregisterReceiver(audioReceiver);
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    protected void processClick(View v) {
        switch (v.getId()){
            case R.id.audio_iv_pause:
                switchPauseStatus();
                break;
            case R.id.audio_iv_pre:
                playPre();
                break;
            case R.id.audio_iv_next:
                playNext();
                break;
            case R.id.audio_iv_playmode:
                switchPlayMode();
                break;
        }
    }

    // 依次切换播放模式
    private void switchPlayMode() {
        mAudioBinder.switchPlayMode();

        updatePlayModeBtn();
    }

    // 根据当前的播放模式,切换使用的图片
    private void updatePlayModeBtn() {
        switch (mAudioBinder.getPlayMode()){
            case AudioService.PLAYMODE_ALLREPEAT:
                iv_playmode.setImageResource(R.drawable.audio_playmode_allrepeat_selector);
                break;
            case AudioService.PLAYMODE_SINGLEREPEAT:
                iv_playmode.setImageResource(R.drawable.audio_playmode_singlerepeat_selector);
                break;
            case AudioService.PLAYMODE_RANDOM:
                iv_playmode.setImageResource(R.drawable.audio_playmode_random_selector);
                break;
        }
    }

    // 播放上一曲
    private void playPre() {
        mAudioBinder.playPre();
    }

    // 播放下一曲
    private void playNext() {
        mAudioBinder.playNext();
    }

    // 切换播放状态
    private void switchPauseStatus() {
        mAudioBinder.switchPasueStatus();

        updatePauseBtn();
    }

    // 更新暂停按钮的图片
    private void updatePauseBtn() {
        if (mAudioBinder.isPlaying()){
            // 正在播放
            iv_pause.setImageResource(R.drawable.audio_pause_selector);
        }else{
            // 暂停状态
            iv_pause.setImageResource(R.drawable.audio_play_selector);
        }
    }

    // 更新播放进度,并稍后再次更新
    private void startUpdatePosition() {
        int duration = mAudioBinder.getDuration();
        int position = mAudioBinder.getCurrentPosition();
        CharSequence duraionStr = StringUtils.formatTime(duration);
        CharSequence positionStr = StringUtils.formatTime(position);
        tv_position.setText(positionStr +" / "+duraionStr);

        sk_position.setMax(duration);
        sk_position.setProgress(position);

        // 发送延迟消息
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_POSITION,500);
    }

    // 使用当前播放进度更新歌词高亮行,并稍后再次更新
    private void startRollingLyrics() {
        lyricsView.computeCenterIndex(mAudioBinder.getCurrentPosition(),mAudioBinder.getDuration());

        // 发送消息,再次滚动歌词
        mHandler.sendEmptyMessage(MSG_ROLLING_LYRICS);
    }

    //这个广播是用来接收 从服务返回的数据的
    private class AudioReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("com.itheima.onPrepared".equals(action)){
                // 音乐准备完毕,开始播放
                updatePauseBtn();

                // 获取正在播放的歌曲
                AudioItem audioItem = (AudioItem) intent.getSerializableExtra("audioItem");
                logE("AudioReceiver.onReceive,item="+audioItem);

                // 更新歌曲信息
                tv_title.setText(audioItem.getTitle());
                tv_artist.setText(audioItem.getArtist());

                // 开启进度更新
                startUpdatePosition();

                // 更新播放模式
                updatePlayModeBtn();

                // 开始滚动歌词
//                File lyricsFile = new File(Environment.getExternalStorageDirectory(),"Download/audio/"+audioItem.getTitle()+".lrc");
                File lyricsFile = LyricsLoader.loadFile(audioItem.getTitle());
                lyricsView.setLyricsFile(lyricsFile);
                startRollingLyrics();
            }
        }
    }

    private class AudioServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mAudioBinder = (AudioService.AudioBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    private class OnAudioSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            // 不是用户发起的变化,则不处理
            if (!fromUser){
                return;
            }

            // 跳转播放进度
            mAudioBinder.seekTo(progress);
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    }
}

音乐播放 需要开启服务

public class AudioService extends Service {

    private static final String TAG = "AudioService";

    public static final int PLAYMODE_ALLREPEAT = 0;
    public static final int PLAYMODE_SINGLEREPEAT = 1;
    public static final int PLAYMODE_RANDOM = 2;
    private int mPlayMode = PLAYMODE_ALLREPEAT;

    private static final int NOTIFY_PRE = 0;
    private static final int NOTIFY_NEXT = 1;
    private static final int NOTIFY_CONTENT = 2;
    private static final String NOTIFY_KEY = "notify_type";

    private AudioBinder mAudioBinder;
    private ArrayList<AudioItem> audioItems;
    private int position = -1;

    @Override
    public void onCreate() {
        super.onCreate();
        mAudioBinder = new AudioBinder();

        //获取播放模式
        SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
        mPlayMode = preferences.getInt("playmode", PLAYMODE_ALLREPEAT);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mAudioBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        int notifyType = intent.getIntExtra(NOTIFY_KEY, -1);
        if (notifyType!=-1){
            // 从通知栏打开的
            switch (notifyType){
                case NOTIFY_PRE:
                    mAudioBinder.playPre();
                    break;
                case NOTIFY_NEXT:
                    mAudioBinder.playNext();
                    break;
                case NOTIFY_CONTENT:
                    notifyUI();
                    break;
            }
        }else{
            // 从播放界面打开服务
            int position = intent.getIntExtra("position", -1);
            if (position != this.position){
                // 不同的歌曲
                this.position = position;
                audioItems = (ArrayList<AudioItem>) intent.getSerializableExtra("audioItems");

                // 播放选中的音乐
                mAudioBinder.playItem();
            }else{
                // 重复的歌曲
                notifyUI();
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    public class AudioBinder extends Binder {

        private class OnAudioPreparedListener implements MediaPlayer.OnPreparedListener {
            @Override
            // 资源准备完毕
            public void onPrepared(MediaPlayer mp) {
                // 开始播放
                mediaPlayer.start();

                // 显示通知
                showNotification();

                // 通知界面更新  通过发送广播的形式
                notifyUI();
            }
        }

        private class OnAudioCompletionListener implements MediaPlayer.OnCompletionListener {
            @Override
            // 播放结束
            public void onCompletion(MediaPlayer mp) {
                autoPlayNext();
            }
        }

        private MediaPlayer mediaPlayer;

        // 播放当前 position 指定的歌曲
        public void playItem(){

            // 验证数据可用性
            if (audioItems.size() == 0 || position == -1) {
                return ;
            }

            AudioItem audioItem = audioItems.get(position);
            LogUtils.e(TAG, "AudioService.onStartCommand,item=" + audioItem);

            // 播放音乐
            try {
                if (mediaPlayer!=null){
                    mediaPlayer.reset();
                }else {
                    mediaPlayer = new MediaPlayer();
                }

                mediaPlayer.setDataSource(audioItem.getPath());
                mediaPlayer.prepareAsync();
                mediaPlayer.setOnCompletionListener(new OnAudioCompletionListener());
                mediaPlayer.setOnPreparedListener(new OnAudioPreparedListener());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 切换播放状态
        public void switchPasueStatus() {
            if (mediaPlayer.isPlaying()){
                // 正在播放
                mediaPlayer.pause();
                cancelNotification();
            }else{
                // 暂停状态
                mediaPlayer.start();
                showNotification();
            }
        }

        // 如果返回 true 则说明歌曲正在播放
        public boolean isPlaying(){
            return mediaPlayer.isPlaying();
        }

        // 返回当前歌曲的总时长
        public int getDuration(){
            return mediaPlayer.getDuration();
        }

        // 返回当前歌曲的播放位置
        public int getCurrentPosition(){
            return mediaPlayer.getCurrentPosition();
        }

        // 跳转到指定毫秒值处播放
        public void seekTo(int msec){
            mediaPlayer.seekTo(msec);
        }

        // 播放上一曲
        public void playPre(){
            if (position!=0){
                position--;
                playItem();
            }else{
                Toast.makeText(AudioService.this, "已经是第一首了", Toast.LENGTH_SHORT).show();
            }
        }

        // 播放下一曲
        public void playNext(){
            if (position!=audioItems.size()-1){
                position++;
                playItem();
            }else{
                Toast.makeText(AudioService.this, "已经是最后一首了", Toast.LENGTH_SHORT).show();
            }
        }

        // 依次切换 列表循环、单曲循环、随机播放
        public void switchPlayMode(){
            switch (mPlayMode){
                case PLAYMODE_ALLREPEAT://循环播放 ---->单曲循环
                    mPlayMode = PLAYMODE_SINGLEREPEAT;
                    break;
                case PLAYMODE_SINGLEREPEAT://单曲循环 --->随机播放
                    mPlayMode = PLAYMODE_RANDOM;
                    break;
                case PLAYMODE_RANDOM:// 随机播放-----> 循环播放
                    mPlayMode = PLAYMODE_ALLREPEAT;
                    break;
            }

            LogUtils.e(TAG,"AudioBinder.switchPlayMode,playmode="+mPlayMode);
            // 保存播放模式到配置文件
            SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
            preferences.edit().putInt("playmode",mPlayMode).commit();
        }

        /** 返回当前使用的播放模式。 */
        public int getPlayMode(){
            return mPlayMode;
        }

        /**根据当前的播放模式,自动切换下一首歌*/
        private void autoPlayNext() {
            switch (mPlayMode){
                case PLAYMODE_ALLREPEAT:
                    // 列表循环,自动查找下一首歌播放。如果已经是最后一首歌,则回到第一首歌
                    if (position!=audioItems.size()-1){
                        position++;
                    }else{
                        position = 0;
                    }
                    break;
                case PLAYMODE_SINGLEREPEAT:
                    // 保持当前位置,重新播放即可
                    break;
                case PLAYMODE_RANDOM:
                    position = new Random().nextInt(audioItems.size());
                    break;
            }

            playItem();
        }
    }

    // 通知界面更新
    private void notifyUI() {
        // 获取当前播放的歌曲
        AudioItem audioItem = audioItems.get(position);

        // 通知界面更新
        Intent intent = new Intent("com.itheima.onPrepared");
        intent.putExtra("audioItem",audioItem);
        sendBroadcast(intent);
    }


    // 取消通知
    private void cancelNotification() {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(0);
    }

    // 显示通知
    private void showNotification() {
        // 创建通知对象
        Notification notification;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            // 小于Android 3.0的版本
            notification = getNotificationByOldApi();
        } else {
            // Notification notification = getNotificationByNewApi();
            notification = getCustomNotificationByNewApi();
        }

        // 显示通知
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.notify(0, notification);
    }

    // 使用新API来生成一个自定义布局的通知
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private Notification getCustomNotificationByNewApi() {
        Notification.Builder builder = new Notification.Builder(this);// 在 Android 3.0 以后才可用
        builder.setSmallIcon(R.mipmap.icon)
                .setTicker("正在播放:"+getCurrentItem().getTitle())
                .setContent(getRemoteViews())
                .setOngoing(true);

        return builder.getNotification();
    }

    // 使用新 API 来生成通知对象
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private Notification getNotificationByNewApi() {
        Notification.Builder builder = new Notification.Builder(this);// 在 Android 3.0 以后才可用
        builder.setSmallIcon(R.mipmap.icon)
                .setTicker("正在播放:"+getCurrentItem().getTitle())
                .setWhen(System.currentTimeMillis())
                .setContentTitle(getCurrentItem().getTitle())
                .setContentText(getCurrentItem().getArtist())
                .setContentIntent(getContentIntent())
                .setAutoCancel(true)// 点击后自动隐藏通知
                .setOngoing(true);

        return builder.getNotification();
    }

    @NonNull
    // 使用旧的API生成一个通知对象
    private Notification getNotificationByOldApi() {
        Notification notification = new Notification(R.mipmap.icon,"正在播放:"+getCurrentItem().getTitle(),System.currentTimeMillis());
       // notification.setLatestEventInfo(this,getCurrentItem().getTitle(),getCurrentItem().getArtist(),getContentIntent());// 该方法在 Android6.0 被删除
        notification.flags = Notification.FLAG_ONGOING_EVENT;
        return notification;
    }

    // 返回自定义通知使用的布局
    private RemoteViews getRemoteViews() {
        RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.audio_notify);

        // 设置文本
        remoteViews.setTextViewText(R.id.audio_notify_tv_title,getCurrentItem().getTitle());
        remoteViews.setTextViewText(R.id.audio_notify_tv_artist,getCurrentItem().getArtist());

        // 设置点击监听
        remoteViews.setOnClickPendingIntent(R.id.audio_notify_iv_pre,getPreIntent());
        remoteViews.setOnClickPendingIntent(R.id.audio_notify_iv_next,getNextIntent());
        remoteViews.setOnClickPendingIntent(R.id.audio_notify_layout,getContentIntent());

        return remoteViews;
    }

    // 返回上一曲的点击响应
    private PendingIntent getPreIntent() {
        Intent intent = new Intent(this,AudioService.class);
        intent.putExtra(NOTIFY_KEY, NOTIFY_PRE);

        return PendingIntent.getService(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
    }

    // 返回下一曲的点击响应
    private PendingIntent getNextIntent() {
        Intent intent = new Intent(this,AudioService.class);
        intent.putExtra(NOTIFY_KEY, NOTIFY_NEXT);

        return PendingIntent.getService(this,1,intent,PendingIntent.FLAG_UPDATE_CURRENT);
    }

    // 返回正文被点击时的响应intent
    private PendingIntent getContentIntent() {
        Intent intent = new Intent(this,AudioPlayerActivity.class);
        intent.putExtra(NOTIFY_KEY,NOTIFY_CONTENT);

        return PendingIntent.getActivity(this,2,intent,PendingIntent.FLAG_UPDATE_CURRENT);
    }

    private AudioItem getCurrentItem(){
        return audioItems.get(position);
    }
}
音乐数据的bean

public class AudioItem implements Serializable {

    private String title;
    private String artist;
    private String path;

    // 解析 cursor 当前行的数据
    public static AudioItem parserCursor(Cursor cursor) {
        AudioItem item = new AudioItem();
        // 健壮性检查
        if (cursor == null || cursor.getCount() == 0) {
            return item;
        }

        item.title = cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME));
        item.title = StringUtils.formatTitle(item.title);
        item.artist = cursor.getString(cursor.getColumnIndex(Media.ARTIST));
        item.path = cursor.getString(cursor.getColumnIndex(Media.DATA));

        return item;
    }

    public static ArrayList<AudioItem> parserListFromCursor(Cursor cursor) {
        ArrayList<AudioItem> audioItems = new ArrayList<>();
        // 健壮性检查
        if (cursor == null || cursor.getCount() == 0) {
            return audioItems;
        }

        cursor.moveToPosition(-1);// 移动到列表最前面再解析
        while (cursor.moveToNext()) {
            AudioItem videoItem = parserCursor(cursor);
            audioItems.add(videoItem);
        }

        return audioItems;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    public String toString() {
        return "AudioItem{" +
                "title='" + title + '\'' +
                ", artist='" + artist + '\'' +
                ", path='" + path + '\'' +
                '}';
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/base_bg"
    android:orientation="vertical"
    tools:context="com.itcast.mobileplayer91.ui.activity.AudioPlayerActivity">

    <include layout="@layout/activity_audio_player_top" />

    <include
        layout="@layout/activity_audio_player_middle"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <include layout="@layout/activity_audio_player_bottom" />

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@mipmap/base_titlebar_bg"
    android:orientation="vertical">

    <!--返回按钮-->
    <ImageView
        android:id="@id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/audio_back_selector" />

    <!--歌曲名-->
    <TextView
        android:id="@+id/audio_tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="歌曲名"
        android:textColor="@color/white"
        android:textSize="20sp" />

</RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--示波器-->
    <ImageView
        android:id="@+id/audio_iv_wave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:src="@drawable/audio_wave_anim" />

    <!--歌手名-->
    <TextView
        android:id="@+id/audio_tv_artist"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/audio_iv_wave"
        android:layout_centerHorizontal="true"
        android:text="歌手名"
        android:textColor="@color/white"
        android:textSize="16sp" />

    <!--歌词-->
    <com.itcast.mobileplayer91.lyrics.LyricsView
        android:id="@+id/audio_lyricsview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/audio_iv_wave" />

</RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="6dp">

    <!--播放进度-->
    <TextView
        android:id="@+id/audio_tv_position"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="00:00/00:00"
        android:textColor="@color/white"
        android:textSize="16sp" />

    <!--时间进度条-->
    <SeekBar
        android:id="@+id/audio_sk_position"
        style="@android:style/Widget.SeekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="6dp"
        android:layout_marginTop="6dp"
        android:progress="40"
        android:progressDrawable="@drawable/audio_seekbar_drawable"
        android:thumb="@mipmap/audio_seek_thumb"
        android:thumbOffset="0dp" />

    <!--控制按钮栏-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal">
        <!--播放顺序-->
        <ImageView
            android:id="@+id/audio_iv_playmode"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/audio_playmode_random_selector" />

        <!--上一曲-->
        <ImageView
            android:id="@+id/audio_iv_pre"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/audio_pre_selector" />

        <!--播放/暂停-->
        <ImageView
            android:id="@+id/audio_iv_pause"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/audio_play_selector" />

        <!--下一曲-->
        <ImageView
            android:id="@+id/audio_iv_next"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/audio_next_selector" />

        <!--播放列表-->
        <ImageView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/audio_playlist_selector" />
    </LinearLayout>

</LinearLayout>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值