Android中使用SurfaceView+MediaPlayer+自定义的MediaController实现自定义的视屏播放器
效果图如下:
(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(); } } } }