Android中使用SurfaceView+MediaPlayer+自定义的MediaController实现自定义的视屏播放器

时间:2015-11-12 21:50:38   收藏:0   阅读:8556

效果图如下:

技术分享

(PS本来是要给大家穿gif动态图的,无奈太大了,没法上传)

功能实现:暂停,播放,快进,快退,全屏,退出全屏,等基本功能

实现的思路:

    在主布局中放置一个SurfaceView,在SurfaceView中放置一个MediaPlayer ,在其下方自定义一个MediaController,不过也不能称之为MediaController,使用的是PupupWindow来实现的,在PupupWindow布局中放置几个textView,Button,最重要的使我们的SeekBar控件,创建一个定时器,当用户触摸屏幕时,让其popupWindow显示5秒的时间,具体实现可以看代码(主程序的代码有点多,耐心点看啊)

主布局activity_main.xml文件

<RelativeLayout 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"
    tools:context=".MainActivity" >

    <SurfaceView 
        android:layout_width="match_parent"
        android:layout_height="260dp"
        android:id="@+id/surfaceView_main"
        />

    <ImageView
        android:onClick="clickButton"
        android:id="@+id/imageView_main_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:src="@drawable/ic_launcher" />
  
</RelativeLayout>

  popupwindow.xml的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bottom_layout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:orientation="horizontal"
    android:background="@drawable/voip_toast_bg"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    android:weightSum="10" >

    <ImageView
        android:id="@+id/imageView_play"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:layout_weight="1"
        android:src="@drawable/video_btn_on" />


    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="5.0"
        android:max="100"
        android:maxHeight="5dp"
        android:minHeight="5dp"
        android:layout_marginLeft="5dp"
        android:progress="0"
        android:thumbOffset="0dp" />
    
    

    <TextView
        android:id="@+id/textView_playtime"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1.3"
        android:gravity="center"
        android:text="00:00"
        android:textColor="@android:color/white"
        android:textSize="12sp" />
    
    <TextView
        android:id="@+id/textView_playtime"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="0.2"
        android:gravity="center"
        android:text="/"
        android:textColor="@android:color/white"
        android:textSize="12sp" />
    
    <TextView
        android:id="@+id/textView_totaltime"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1.3"
        android:gravity="center"
        android:text="00:00"
        android:textColor="@android:color/white"
        android:textSize="12sp" />

    <ImageView
        android:id="@+id/imageView_fullscreen"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:layout_weight="1"
        android:src="@drawable/video_full_screen" />

</LinearLayout>

  

主Activity中的代码:

package com.amy.day43_03_SurfaceViewMediaPlayer;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.R.integer;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.PopupWindow;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class MainActivity extends Activity {
	private final static String TAG = "MainActivity";
	private Context mContext = this;
	private SurfaceView surfaceView = null;
	private SurfaceHolder surfaceHolder = null;
	private MediaPlayer mediaPlayer = null;
	private ImageView imageView_main_show = null;
   
	// 自定义的控制条及其上的控件
	private View controllerView;
	private PopupWindow popupWindow;

	private ImageView imageView_play;
	private ImageView imageView_fullscreen;
	private SeekBar seekBar;
	private TextView textView_playTime;
	private TextView textView_duration;
	private String filePath = null;

	private float densityRatio = 1.0f; // 密度比值系数(密度比值:一英寸中像素点除以160)

	private Runnable r = new Runnable() {
		@Override
		public void run() {
			// 又回到了主线程
			showOrHiddenController();
		}
	};

	private MyVideoBroadcastReceiver receiver = null;

	// 设置定时器
	private Timer timer = null;
	private final static int WHAT = 0;
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case WHAT:
				if (mediaPlayer != null) {
					int currentPlayer = mediaPlayer.getCurrentPosition();
					if (currentPlayer > 0) {
						mediaPlayer.getCurrentPosition();
						textView_playTime.setText(formatTime(currentPlayer));

						// 让seekBar也跟随改变
						int progress = (int) ((currentPlayer / (float) mediaPlayer
								.getDuration()) * 100);

						seekBar.setProgress(progress);
					} else {
						textView_playTime.setText("00:00");
						seekBar.setProgress(0);
					}
				}

				break;

			default:
				break;
			}
		};
	};

	// 自动隐藏自定义播放器控制条的时间
	private static final int HIDDEN_TIME = 5000;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		initView();

		initMediaPlayer();

		initController();

		// 动态注册广播接受者
		receiver = new MyVideoBroadcastReceiver();
		registerReceiver(receiver, new IntentFilter(
				"com.amy.day43_03_SurfaceViewMediaPlayer"));
	}

	private String formatTime(long time) {
		SimpleDateFormat formatter = new SimpleDateFormat("mm:ss");
		return formatter.format(new Date(time));
	}

	private void initController() {

		controllerView = getLayoutInflater().inflate(
				R.layout.popupwindow_mediacontroller, null);

		// 初始化popopWindow
		popupWindow = new PopupWindow(controllerView,
				LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true);

		imageView_play = (ImageView) controllerView
				.findViewById(R.id.imageView_play);
		imageView_fullscreen = (ImageView) controllerView
				.findViewById(R.id.imageView_fullscreen);

		seekBar = (SeekBar) controllerView.findViewById(R.id.seekbar);

		textView_playTime = (TextView) controllerView
				.findViewById(R.id.textView_playtime);
		textView_duration = (TextView) controllerView
				.findViewById(R.id.textView_totaltime);

		seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			// 表示手指拖动seekbar完毕,手指离开屏幕会触发以下方法
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// 让计时器延时执行
				handler.postDelayed(r, HIDDEN_TIME);
			}

			// 在手指正在拖动seekBar,而手指未离开屏幕触发的方法
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// 让计时器取消计时
				handler.removeCallbacks(r);
			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				if (fromUser) {
					int playtime = progress * mediaPlayer.getDuration() / 100;
					mediaPlayer.seekTo(playtime);
				}

			}
		});

		// 点击播放的时候,判断是播放还是暂停
		imageView_play.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (imageView_main_show.getVisibility() == View.VISIBLE) {
					imageView_main_show.setVisibility(View.GONE);
				}

				if (mediaPlayer.isPlaying()) {
					mediaPlayer.pause();
					imageView_play.setImageResource(R.drawable.video_btn_down);
				} else {
					mediaPlayer.start();
					imageView_play.setImageResource(R.drawable.video_btn_on);

				}

			}
		});

		// 实现全屏和退出全屏(内容物横竖屏,不是屏幕的横竖屏)
		imageView_fullscreen.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
					setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
					imageView_fullscreen
							.setImageResource(R.drawable.video_full_screen);

					// 重新设置surfaceView的高度和宽度
					surfaceView.getLayoutParams().width = LayoutParams.MATCH_PARENT;
					surfaceView.getLayoutParams().height = (int) (260 * densityRatio);
				} else if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
					setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
					imageView_fullscreen
							.setImageResource(R.drawable.video_inner_screen);

					surfaceView.getLayoutParams().width = LayoutParams.MATCH_PARENT;
					surfaceView.getLayoutParams().height = LayoutParams.MATCH_PARENT;
				}

				surfaceView.setLayoutParams(surfaceView.getLayoutParams());
			}
		});
	}

	private void showOrHiddenController() {
		if (popupWindow.isShowing()) {
			popupWindow.dismiss();
		} else {
			// 将dp转换为px
			int controllerHeightPixel = (int) (densityRatio * 50);
			popupWindow.showAsDropDown(surfaceView, 0, -controllerHeightPixel);
			// 延时执行
			handler.postDelayed(r, HIDDEN_TIME);
		}
	}

	private void initMediaPlayer() {
		filePath = Environment.getExternalStoragePublicDirectory(
				Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
				+ File.separator + "myabc.mp4";

		Log.i("==main==",
				"==========="
						+ Environment.getExternalStoragePublicDirectory(
								Environment.DIRECTORY_DOWNLOADS)
								.getAbsolutePath());
		if (mediaPlayer == null) {
			// 1,创建MediaPlay对象
			mediaPlayer = new MediaPlayer();
			mediaPlayer.reset();
			try {
				mediaPlayer.setDataSource(filePath);
				mediaPlayer.prepare();
				// mediaPlayer.start();
				mediaPlayer.setLooping(false);
			} catch (IllegalStateException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		mediaPlayer.setOnPreparedListener(new OnPreparedListener() {

			@Override
			public void onPrepared(MediaPlayer mp) {
				// 表示准备完成,设置总的时长,使用时间格式化工具

				// String duration = mediaPlayer.getDuration() ;
				textView_duration.setText(formatTime(mediaPlayer.getDuration()));
				// 初始化定时器
				timer = new Timer();
				timer.schedule(new TimerTask() {

					@Override
					public void run() {
						handler.sendEmptyMessage(WHAT);
					}
				}, 0, 1000);
			}
		});

		mediaPlayer.setOnErrorListener(new OnErrorListener() {

			@Override
			public boolean onError(MediaPlayer mp, int what, int extra) {
				mp.reset();

				return false;
			}
		});

		mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

			@Override
			public void onCompletion(MediaPlayer mp) {
				// 发送广播,播放下一首歌曲

				Intent intent = new Intent();
				intent.setAction("com.amy.day43_03_SurfaceViewMediaPlayer");
				sendBroadcast(intent);
			}
		});
	}

	private void initView() {
		// TODO Auto-generated method stub
		densityRatio = getResources().getDisplayMetrics().density; // 表示获取真正的密度

		imageView_main_show = (ImageView) findViewById(R.id.imageView_main_play);
		surfaceView = (SurfaceView) findViewById(R.id.surfaceView_main);
		surfaceHolder = surfaceView.getHolder();

		surfaceHolder.addCallback(new Callback() {

			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				// TODO Auto-generated method stub
				if (mediaPlayer != null) {
					mediaPlayer.stop();
					mediaPlayer.release();
				}
			}

			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				// TODO Auto-generated method stub
				if (mediaPlayer != null) {

					mediaPlayer.setDisplay(surfaceHolder);
					// mediaPlayer.start() ;

				}

			}

			@Override
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
				// TODO Auto-generated method stub

			}
		});

		// 设置屏幕的触摸监听
		surfaceView.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// 表示在点击的瞬间就显示控制条
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					showOrHiddenController();
					break;

				default:
					break;
				}
				return true;
			}
		});
	}

	/**
	 * 设置控件的监听事件
	 * 
	 * @param v
	 */
	public void clickButton(View v) {
		switch (v.getId()) {
		case R.id.imageView_main_play:

			imageView_main_show.setVisibility(View.GONE);
			mediaPlayer.start();

			break;

		default:
			break;
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();

		unregisterReceiver(receiver);
		timer.cancel();

		if (mediaPlayer != null) {
			mediaPlayer.release();
			mediaPlayer = null;
		}

		handler.removeCallbacksAndMessages(null);
	}

	class MyVideoBroadcastReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent.getAction().equals(
					"com.amy.day43_03_SurfaceViewMediaPlayer")) {
				AlertDialog.Builder builder = new AlertDialog.Builder(context);
				builder.setIcon(R.drawable.ic_launcher)
						.setTitle("提示")
						.setMessage("视屏播放完毕,是否播放")
						.setNegativeButton("取消", null)
						.setPositiveButton("确定",
								new DialogInterface.OnClickListener() {

									@Override
									public void onClick(DialogInterface dialog,
											int which) {
										mediaPlayer.reset();
										try {
											mediaPlayer.setDataSource(filePath);
											mediaPlayer.prepare();
										} catch (Exception e) {
											// TODO Auto-generated catch block
											e.printStackTrace();
										}
										mediaPlayer.setLooping(false);

										mediaPlayer.start();
									}
								}).show();

			}
		}

	}

}

  

 

评论(1
zombie 2015-12-21 22:00:57
您好,最近也在搞播放器,博客里的代码我弄到自己工程里有多处报错,少几个布局文件。
能将这个代码发我一份吗 非常感谢。qq984547398
1
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!