基于android的网络音乐播放器-播放控制界面(九)

到这里我们的音乐播放器已经有了播放,收藏,搜索网络音乐并下载(包括多线程断点下载)等基本功能,下面将开发播放界面——实现音乐播放的控制-上/下一首,播放/暂停,循环控制,专辑图片的加载,歌词的加载和解析并支持滑动改变进度。这些实现主要在一个类里-PlayMusicActivity.java

package com.sprd.easymusic;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.Request.Method;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.sprd.easymusic.fragment.NetFragment;
import com.sprd.easymusic.myview.LrcView;
import com.sprd.easymusic.service.MusicService;
import com.sprd.easymusic.util.BitmapUtil;
import com.sprd.easymusic.util.DownloadUtil;
import com.sprd.easymusic.util.LrcLine;
import com.sprd.easymusic.util.StringUtil;

import android.app.ActionBar;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class PlayMusicActivity extends Activity implements MusicService.Watcher {
    private static final String TAG = "PlayMusicActivity";
    /**
     * 发送音乐播放控制的广播给MianActivity,音乐的控制统一交给MainActivity管理
     * 下一首,暂停,上一首,播放,继续播放
     */
    private static final String ACTION_NEXT_SONG = "action.nextsong";
    private static final String ACTION_PAUSE = "action.pause";
    private static final String ACTION_PRE_SONG = "action.presong";
    private static final String ACTION_PLAY_SONG = "action.playsong";
    private static final String ACTION_CONTINUE_PLAYING_SONG = "action.continueplaying";
    /**
     * 接收广播,下载歌词完成,下载专辑图片完成,更新播放状态
     */
    private static final String ACTION_DOWNLOADLRC_SUCCESS = "action_downloadlrc_success";
    private static final String ACTION_DOWNLOADPIC_SUCCESS = "action_downloadpic_success";
    private static final String ACTION_UPDATE_PLAYSTATE = "action.update.playstate";
    /**
     * 上一首,播放/暂停,下一首,专辑图片, 循环
     */
    private ImageView pre, playAndPause, next, albumPic, cycleView;
    /**
     * 音乐标题,歌手,时长,已播放时长
     */
    private TextView title, artist, duration, playedTimeView;
    //加载歌词
    private TextView loadLrc;
    //歌词View--自定义View
    private LrcView lrcView;
    //进度条
    private SeekBar seekBar;
    //表征当前播放状态
    private boolean isPlaying;
    //表征暂停键是否按下,若为true则下次点击播放为继续播放,和isPlaying不冲突
    private boolean pause;
    //音乐播放器后台服务
    private MusicService musicService;
    private Context mContext;
    //当前播放音乐的标题和歌手和时长
    private String currentMusicTitle, currentMusicArtist;
    private int currentMusicDuration;
    //播放界面专辑图片的动画-旋转
    private Animation playAnimation;
    //当前播放的进度
    private int currentProgress;
    private Handler myHandler;
    private static final int UPDATE_PROGRESS = 1;
    //添加网络请求队列
    private RequestQueue mQueue;
    //搜索歌词的API
    public static final String lrcApi = "http://geci.me/api/lyric/";
    //歌词下载的URL和网络响应
    private String lrcUrl;
    private String lrcResponse;
    //缓存专辑图片,避免每次从本地或网络加载
    private Map<String, SoftReference<Bitmap>> playImageCacheMap = new HashMap<String, SoftReference<Bitmap>>();
    //当前歌词是否正在展示
    private boolean showLrc = false;
    //循环控制切换对应的图片资源
    private int[] cycleViewResource;


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.play);
        mContext = this;
        //绑定服务并获得musicService的引用
        bindToService();
        cycleViewResource = new int[] {R.drawable.cycle_list, R.drawable.cycle_single, R.drawable.cycle_random};
        pre = (ImageView) findViewById(R.id.pre);
        pre.setOnClickListener(musicClickListener);
        playAndPause = (ImageView) findViewById(R.id.playAndpause);
        playAndPause.setOnClickListener(musicClickListener);
        next = (ImageView) findViewById(R.id.next);
        next.setOnClickListener(musicClickListener);
        albumPic = (ImageView) findViewById(R.id.lrcpic);
        title = (TextView) findViewById(R.id.title);
        artist = (TextView) findViewById(R.id.artist);
        duration = (TextView) findViewById(R.id.duration);
        playedTimeView = (TextView) findViewById(R.id.playedtime);
        lrcView = (LrcView) findViewById(R.id.lrcview);
        loadLrc = (TextView) findViewById(R.id.loadlrc);
        loadLrc.setOnClickListener(musicClickListener);
        cycleView = (ImageView) findViewById(R.id.cycleview);
        cycleView.setOnClickListener(musicClickListener);
        mQueue = Volley.newRequestQueue(mContext);
        playAnimation = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
        seekBar = (SeekBar) findViewById(R.id.musicProgress);
        seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {//手动滑动进度条时的监听
                    changeProgressFromUser(progress);//通知后台musicService改变播放进度
                    //歌词信息跳转进度
                    lrcView.checkLrcTime(StringUtil.formatDuration(progress), progress - currentProgress);
                }
            }

            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            public void onStopTrackingTouch(SeekBar seekBar) {

            }

        });
        myHandler = new Handler() {
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case UPDATE_PROGRESS://更新播放进度
                    int progress = (Integer)msg.obj;
                    seekBar.setProgress(progress);
                    String playedTime = StringUtil.formatDuration(progress);
                    playedTimeView.setText(playedTime);
                    lrcView.checkLrcTime(playedTime, 1);
                    Log.d(TAG, "update progress success!");
                    break;
                default:
                    break;
                }
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_DOWNLOADLRC_SUCCESS);
        filter.addAction(ACTION_DOWNLOADPIC_SUCCESS);
        filter.addAction(ACTION_UPDATE_PLAYSTATE);
        mContext.registerReceiver(updateReceiver, filter);
    }

    // 绑定服务时的ServiceConnection参数
        private ServiceConnection conn = new ServiceConnection() {

            // 绑定成功后该方法回调,并获得服务端IBinder的引用
            public void onServiceConnected(ComponentName name, IBinder service) {
                // 通过获得的IBinder获取PlayMusicService的引用
                musicService = ((MusicService.MusicBinder) service).getService();
                musicService.addWatcher(PlayMusicActivity.this);
                //Toast.makeText(mContext, "onServiceConnected:musicService", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d(TAG, "onServiceDisconnected:musicService");
            }

        };

        // 绑定服务MusicService
        private void bindToService() {
            bindService(new Intent(mContext,
                    com.sprd.easymusic.service.MusicService.class), conn,
                    Service.BIND_AUTO_CREATE);
        }

    //后台播放服务改变播放进度
    public void changeProgressFromUser(int progress) {
        musicService.changePlayProgress(progress);
    }

    protected void onStart() {
        updataPlayState();
        super.onStart();
    }



    protected void onDestroy() {
        musicService = null;
        this.unbindService(conn);
        this.unregisterReceiver(updateReceiver);
        super.onDestroy();
    }

    //更新播放状态
    private void updataPlayState() {
        Log.d(TAG, "updataPlayState");
        currentMusicTitle = MainActivity.currentMusicTitle;
        currentMusicArtist = MainActivity.currentMusicArtist;
        currentMusicDuration = (int) MainActivity.currentMusicDuration;
        isPlaying = MainActivity.isPlaying;
        pause = MainActivity.pause;
        seekBar.setMax((int)currentMusicDuration);
        title.setText(currentMusicTitle);
        artist.setText(currentMusicArtist);
        duration.setText(StringUtil.formatDuration(currentMusicDuration));
        if (isPlaying) {
            playAndPause.setImageResource(android.R.drawable.ic_media_pause);
            albumPic.startAnimation(playAnimation);
        } else {
            playAndPause.setImageResource(android.R.drawable.ic_media_play);
            albumPic.clearAnimation();
        }
        showAlbumPic();
        showLrc();
    }

    //控制音乐的播放转交给MianActivity
    private void changeMusicState(Intent intent) {
        Log.d(TAG, "changeMusicState:action = " + intent.getAction());
        this.sendBroadcast(intent);
    }

    private OnClickListener musicClickListener = new OnClickListener() {
        public void onClick(View v) {
            if (v == pre) {//上一首
                isPlaying = true;
                pause = false;
                showLrc = false;
                Intent intent = new Intent(ACTION_PRE_SONG);
                changeMusicState(intent);
            } else if (v == playAndPause) {//播放或者暂停
                if (pause) {//如果点击过暂停,下一次点击播放应当是继续播放
                    isPlaying = true;
                    pause = false;
                    Intent intent = new Intent(ACTION_CONTINUE_PLAYING_SONG);
                    changeMusicState(intent);
                    return;
                }
                if (isPlaying) {//当前播放状态点击暂停
                    isPlaying = false;
                    pause = true;
                    Intent intent = new Intent(ACTION_PAUSE);
                    changeMusicState(intent);
                } else {//首次点击播放键,此时isPlaying和pause均为false
                    isPlaying = true;
                    Intent intent = new Intent(ACTION_PLAY_SONG);
                    changeMusicState(intent);
                }
            } else if (v == next) {//下一首
                isPlaying = true;
                pause = false;
                showLrc = false;
                Intent intent = new Intent(ACTION_NEXT_SONG);
                changeMusicState(intent);
            } else if (v == loadLrc) {//加载歌词
                showLrc = true;
                String  localUrl = getLocalPath(0);
                File file = new File( localUrl);
                if (file.exists()) {
                    showLrc();
                    return;
                }
                searchLrc(currentMusicTitle, currentMusicArtist);
            } else if (v == cycleView) {//切换循环模式
                MainActivity.cycle += 1;
                if (MainActivity.cycle > 3) MainActivity.cycle = 1;
                cycleView.setImageResource(cycleViewResource[MainActivity.cycle-1]);
            }
        }

    };

    //搜索歌词
    private void searchLrc(String title, String artist) {
        String searchTitle = null;
        String searchArtist = null;
        Log.d(TAG, currentMusicTitle + currentMusicArtist);
        try {
            searchTitle = URLEncoder.encode(StringUtil.removeReg(currentMusicTitle, null), "UTF-8");
            searchArtist = URLEncoder.encode(StringUtil.removeReg(currentMusicArtist, null), "UTF-8");
            Log.d(TAG, searchTitle + searchArtist);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String url = lrcApi + searchTitle + "/" + searchArtist;
        if (searchTitle.indexOf("+")>=0 || searchArtist.indexOf("+")>=0) {
            url = url.replace('+', ' ');
        }
        Log.d(TAG, "url = " + url );
        StringRequest stringRequest = new StringRequest(Method.GET,url,  
                new Response.Listener<String>() {  
                    @Override  
                    public void onResponse(String response) {
                        Log.d(TAG, "response = " + response); 
                        //搜索歌词得到的响应
                        lrcResponse = response;          
                        analysisLrcUrl();
                    }  
                }, 
                new Response.ErrorListener() {  
                    @Override  
                    public void onErrorResponse(VolleyError error) {
                        Log.e(TAG, error.getMessage(), error);  
                        Toast.makeText(PlayMusicActivity.this, "加载失败!", 300).show();
                    }  
                });
        mQueue.add(stringRequest);  
    }

    //搜索专辑图片
    private void searchAlbumPic(String title, String artist) {
        Toast.makeText(mContext, "搜索专辑图片...", 300).show();
        //有些歌名和歌手信息中可能会携带些非原始的特殊符号需要去掉,比如《》.,之类的
        String ti = StringUtil.removeReg(title, null);
        String ar = StringUtil.removeReg(artist, null);
        Log.d(TAG, "searchAlbumPic:ti = " + ti + " ar = " + ar); 
        //启动查询歌词的异步任务
        new NetFragment().new SearchMusicTask(ti, ar, mContext).execute(NetFragment.getRealUrl(title));
    }

    //从响应中分离出歌词下载的URL
    private void analysisLrcUrl() {

        try {
            JSONObject jo = new JSONObject(lrcResponse);
            JSONArray result = jo.getJSONArray("result");
            JSONObject firstResult = result.getJSONObject(0);
            String lrc = firstResult.getString("lrc");
            lrcUrl = lrc;
            downloadLrc(lrcUrl);
            Log.d(TAG, "lrc = " + lrc);
        } catch (JSONException e) {
            e.printStackTrace();
            Toast.makeText(PlayMusicActivity.this, "抱歉,未搜索到歌词!", 300).show();
        }
    }

    //下载歌词
    private void downloadLrc(String lrcUrl) {
        final String musicLrc = lrcUrl;
        Toast.makeText(mContext, "正在下载歌词,请稍候...", 300).show();
        String  localFile = getLocalPath(0);
        File file = new File(localFile);
        //开启一个线程下载歌词
        DownloadUtil lrcUtil = new DownloadUtil(musicLrc, localFile, mContext, 1);
        musicService.downloadMusic(lrcUtil);
    }

    //下载专辑图片
    public void downloadAlbumPic(String albumPicUrl) {
        if (albumPicUrl == null) {
            Toast.makeText(mContext, "未搜索到匹配图片", 300).show();
            albumPic.setImageResource(R.drawable.rotate);
            return;
        }
        final String musicAlbumPic = albumPicUrl;
        //Toast.makeText(mContext, "正在下载专辑图片,请稍候...", 300).show();
        String localFile = getLocalPath(1);
        File file = new File(localFile);
        //开启两个线程下载专辑图片
        DownloadUtil albumPicUtil = new DownloadUtil(musicAlbumPic, localFile, mContext, 2);
        musicService.downloadMusic(albumPicUtil);
    }

    //显示歌词
    protected void showLrc() {
        if (!showLrc) {
            lrcView.setLrcList(null);
            lrcView.setCurrentLrcIndex(0);
            lrcView.setVisibility(View.GONE);
            loadLrc.setVisibility(View.VISIBLE);
            return;
        }
        String  localFile = getLocalPath(0);
        File file = new File(localFile);
        if (!file.exists()) return;
        //歌词的解析只需传进去一个歌词文件路径,自定义view-lrcView内部已经封装好
        lrcView.loadLrc(localFile);
        loadLrc.setVisibility(View.INVISIBLE);
    }

    //显示专辑图片
    private void showAlbumPic() {
        //首先从缓存中查询是否已加载有该专辑图片
        if (playImageCacheMap != null) {
            Log.d(TAG, "playImageCacheMap.size = " + playImageCacheMap.size());
            SoftReference<Bitmap> sBitmap = 
                    playImageCacheMap.get(currentMusicTitle+currentMusicArtist);
            if (sBitmap != null) {
                Bitmap bitmap = sBitmap.get();
                if (bitmap != null) {
                    albumPic.setImageBitmap(bitmap);
                    Log.d(TAG, "get image from ImageCacheMap");
                    return;
                } else {
                    playImageCacheMap.remove(currentMusicTitle+currentMusicArtist);
                }
            }
        }

        //如果缓存中还未存入该专辑图片或者已经被回收,从本地加载并添加到缓存
        final String  localFile = getLocalPath(1);
        File file = new File(localFile);
        if (file.exists()) {
            myHandler.post(new Runnable() {
                public void run() {
                    Bitmap bitmap = BitmapFactory.decodeFile(localFile);
                    //int size = Math.min(lrcPic.getWidth(), lrcPic.getHeight());
                    //Bitmap bitmap = BitmapUtil.getScropBitmap(localFile, size, size);
                    playImageCacheMap.put(currentMusicTitle + currentMusicArtist, new SoftReference<Bitmap>(bitmap));
                    Log.d(TAG, "add bitmap to ImageCacheMap, bytes = " + bitmap.getByteCount());
                    albumPic.setImageBitmap(bitmap);
                }
            });
            return;
        }
        //如果缓存和本地均没有专辑图片则从网络中搜索并加载
        searchAlbumPic(currentMusicTitle, currentMusicArtist);
    }

    //获取本地文件路径,type为0表示歌词路径,为1表示专辑图片路径
    private String getLocalPath(int type) {
        String result = null;
        MainActivity.createFileDir();
        if (type == 0) {
            result = MainActivity.downloadedPath
                    + "/lrc/"+ currentMusicTitle + "-" + currentMusicArtist + ".lrc";
        } else {
            result = MainActivity.downloadedPath 
            + "/album/"+ currentMusicTitle + "-" + currentMusicArtist + ".jpg";
        }

        return result;
    }

    @Override
    public void update(int currentProgress) {
        this.currentProgress = currentProgress;
        myHandler.sendMessage(myHandler.obtainMessage(UPDATE_PROGRESS, currentProgress));
    }

    private BroadcastReceiver updateReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_DOWNLOADLRC_SUCCESS)) {
                Toast.makeText(mContext, "下载歌词成功!", 100).show();
                showLrc();
            } else if (intent.getAction().equals(ACTION_DOWNLOADPIC_SUCCESS)) {
                Toast.makeText(mContext, "下载专辑图片成功!", 100).show();
                showAlbumPic();
            } else if (intent.getAction().equals(ACTION_UPDATE_PLAYSTATE)) {
                boolean autoChange = intent.getBooleanExtra("autoChange", false);
                if (autoChange) showLrc = !autoChange;
                updataPlayState();
            }
        }

    };

}

其中StringUtil是字符串处理工具类:

package com.sprd.easymusic.util;

import android.media.MediaPlayer;

public class StringUtil {

    // 将音乐时长-毫秒转换为00:00格式
    public static String formatDuration(long dur) {
        long totalSecond = dur / 1000;
        String minute = totalSecond / 60 + "";
        if (minute.length() < 2)
            minute = "0" + minute;
        String second = totalSecond % 60 + "";
        if (second.length() < 2)
            second = "0" + second;
        return minute + ":" + second;
    }

    public static String removeReg(String source, String reg) {
        if (reg!= null) {
            return source.replaceAll(reg, "");
        }
        //保留中文和英文字符
        return source.replaceAll("[^a-zA-Z \u4e00-\u9fa5]", "");
    }

    public static String getMusicDuration(String url) {
        int duration = 0;
        MediaPlayer mp = null;
        try {
            mp = new MediaPlayer();
            mp.reset();
            mp.setDataSource(url);
            mp.prepare();
            duration = mp.getDuration();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mp.release();
        }
        return formatDuration(duration);

    }

    public static long getMusicLongDuration(String url) {
        long duration = 0;
        MediaPlayer mp = null;
        try {
            mp = new MediaPlayer();
            mp.reset();
            mp.setDataSource(url);
            mp.prepare();
            duration = mp.getDuration();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mp.release();
        }
        return duration;

    }

}

搜索专辑图片的异步任务与网络音乐搜索的异步任务是同一个,在前面的章节中可以看到搜索歌曲时有保存专辑图片,只是没有拿来使用。

PlayMusicActivity.java的布局很简单,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/playlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/myshape"
    android:gravity="top"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="#ff0000" />

        <TextView
            android:id="@+id/artist"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="#00ff00" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="20" >

        <!--<ImageView
            android:id="@+id/lrcpic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="20dp"
            android:src="@drawable/rotate" />  -->
        <com.sprd.easymusic.myview.CircleImageView 
            android:id="@+id/lrcpic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="20dp"
            android:alpha="0.6"
            android:src="@drawable/rotate"/>

        <com.sprd.easymusic.myview.LrcView
            android:id="@+id/lrcview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="20dp"
            android:alpha="1.0"
            android:visibility="gone"/>
    </RelativeLayout>

    <TextView
        android:id="@+id/loadlrc"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_weight="4"
        android:gravity="center"
        android:text="查看歌词"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="#ff00ff" />

    <SeekBar
        android:id="@+id/musicProgress"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_marginBottom="10dp" />

    <LinearLayout
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/playedtime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_weight="4"
            android:text="00:00"
            android:textColor="#ffffff" />

        <TextView
            android:id="@+id/duration"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="4"
            android:gravity="right"
            android:textColor="#ffffff" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/controlarea"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="30dp"
        android:layout_weight="5"
        android:gravity="center"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/pre"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginLeft="30dp"
            android:src="@drawable/pre" />

        <ImageView
            android:id="@+id/playAndpause"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginLeft="50dp"
            android:background="#ffffff"
            android:src="@drawable/play" />

        <ImageView
            android:id="@+id/next"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginLeft="50dp"
            android:src="@drawable/next" />

        <ImageView
            android:id="@+id/cycleview"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginLeft="50dp"
            android:src="@drawable/cycle_list" />
    </LinearLayout>

</LinearLayout>

这是一个线性布局,从各个view的id就可以看出其作用了,这里也不多做解释了。
大概界面预览图如下(专辑图片eclipse显示有误):
PlayMusicActivity界面

音乐播放器已完成,下载地址:
Android音乐播放器

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值