• 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();
    
    			}
    		}
    
    	}
    
    }
    

      

  • 相关阅读:
    Java设计模式(十二) 策略模式
    Java设计模式(二) 工厂方法模式
    Java设计模式(一) 简单工厂模式不简单
    Kafka设计解析(四)- Kafka Consumer设计解析
    Kafka设计解析(三)- Kafka High Availability (下)
    Kafka设计解析(二)- Kafka High Availability (上)
    Spark 灰度发布在十万级节点上的成功实践 CI CD
    Spark SQL / Catalyst 内部原理 与 RBO
    Java进阶(七)正确理解Thread Local的原理与适用场景
    Kafka设计解析(八)- Exactly Once语义与事务机制原理
  • 原文地址:https://www.cnblogs.com/wjtaigwh/p/4960301.html
Copyright © 2020-2023  润新知