如何实现videoview全屏切换的动态布局全屏和半屏控制

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&&&&&videoview播放视频时,实现 双击 流畅进行横竖屏切换来实现全屏和小屏播放,时间不会改变,可快进
&videoview播放视频时,实现 双击 流畅进行横竖屏切换来实现全屏和小屏播放,时间不会改变,可快进
实现 双击 流畅进行横竖屏切换来实现全屏和小屏播放,时间不会改变,可快进
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
Q.为什么我点的下载下不了,但积分却被扣了
A. 由于下载人数众多,下载服务器做了并发的限制。若发现下载不了,请稍后再试,多次下载是不会重复扣分的。
Q.我的积分不多了,如何获取积分?
A. 获得积分,详细见。
完成任务获取积分。
论坛可用分兑换下载积分。
第一次绑定手机,将获得5个C币,C币可。
关注并绑定CSDNID,送10个下载分
下载资源意味着您已经同意遵守以下协议
资源的所有权益归上传用户所有
未经权益所有人同意,不得将资源中的内容挪作商业或盈利用途
CSDN下载频道仅提供交流平台,并不能对任何下载资源负责
下载资源中如有侵权或不适当内容,
本站不保证本站提供的资源的准确性,安全性和完整性,同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
移动开发下载排行
您当前C币:0&&&可兑换 0 下载积分
兑换下载分:&
消耗C币:0&
立即兑换&&
兑换成功你当前的下载分为 。前去下载资源
你下载资源过于频繁,请输入验证码
如何快速获得积分?
你已经下载过该资源,再次下载不需要扣除积分
videoview播放视频时,实现 双击 流畅进行横竖屏切换来实现全屏和小屏播放,时间不会改变,可快进
所需积分:1
剩余积分:0
扫描微信二维码精彩活动、课程更新抢先知
VIP会员,免积分下载
会员到期时间:日
剩余下载次数:1000
videoview播放视频时,实现 双击 流畅进行横竖屏切换来实现全屏和小屏播放,时间不会改变,可快进
剩余次数:&&&&有效期截止到:
你还不是VIP会员VIP会员享免积分 . 专属通道极速下载
VIP下载次数已满VIP会员享免积分 . 专属通道极速下载,请继续开通VIP会员
你的VIP会员已过期VIP会员享免积分 . 专属通道极速下载,请继续开通VIP会员如何实现videoview的动态布局全屏和半屏控制_百度知道18474人阅读
android(101)
& & 最近做一个app要用到视频的播放,毫无疑问的选择了VieoView,但是在使用的时候发现VideoView全屏的时候还是有些学问的。。。先不管那么多了,把可以实现全屏与指定大小页面的效果的解决方案记录下来好了。。。
& & 步骤1:
& & & 自定义一个VideoView,重写里面的onMeasure
& & &&package com.jone.jonevideo.
import android.content.C
import android.util.AttributeS
import android.widget.VideoV
public class MyVideoView extends VideoView {
public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
public MyVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
public MyVideoView(Context context) {
super(context);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
步骤2: 用一个布局来包裹你的VideoView & [以后我们会在代码中控制VideoView的父布局来实现切换大小]
&FrameLayout xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical& &
&RelativeLayout
android:layout_width=&match_parent&
android:layout_height=&match_parent& &
&com.jone.jonevideo.widget.MyVideoView
android:id=&@+id/audtoView&
android:layout_width=&match_parent&
android:layout_height=&match_parent& /&
&/RelativeLayout&
&LinearLayout
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:layout_gravity=&bottom& &
android:id=&@+id/audio_start&
style=&@style/layout_wrap_content&
android:text=&start_audio& /&
android:id=&@+id/audio_2_video&
style=&@style/layout_wrap_content&
android:text=&@string/switch_audio_2_vidwo& /&
android:id=&@+id/entry_list_audio&
style=&@style/layout_wrap_content&
android:text=&@string/entry_audio_list& /&
&/LinearLayout&
&/FrameLayout&
步骤3: 通过代码来设置全屏与否的切换
if(!fullscreen){//设置RelativeLayout的全屏模式
RelativeLayout.LayoutParams layoutParams=
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
mVideoView01.setLayoutParams(layoutParams);
fullscreen =//改变全屏/窗口的标记
}else{//设置RelativeLayout的窗口模式
RelativeLayout.LayoutParams lp=new
RelativeLayout.LayoutParams(320,240);
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
mVideoView01.setLayoutParams(lp);
fullscreen =//改变全屏/窗口的标记
这哥们写的挺详细。。我就参考了他的思路。。大家可以看看
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:369516次
积分:3998
积分:3998
排名:第5529名
原创:74篇
转载:32篇
评论:121条
(1)(1)(2)(1)(3)(2)(1)(3)(3)(5)(4)(1)(2)(1)(6)(2)(3)(3)(10)(3)(7)(3)(2)(3)(2)(13)(8)(4)(4)(2)(1)2489人阅读
Android知识总结(14)
因为直接使用系统vedioview,底部的MediaController布局有点不好看,尤其是进度条,不能实现办半屏与全屏的切换,自己网上看了下别人的资料,整理了下,做以笔记;初学者,勉强才实现这些功能,还有许多地方不明白。
看下效果:
& & & & & & & & &&
1,MediaController.java.直接复制下系统源码的MediaController,来进行修改,就两个地方,一个布局相关的修改,以及进度条ProgressBar的修改,然后就 是添加了半屏与全屏的切换接口。
* Copyright (C) 2006 The Android Open Source Project
* Licensed under the Apache License, Version 2.0 (the &License&);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &AS IS& BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
com.example.
import java.util.F
import java.util.L
import android.annotation.SuppressL
import android.annotation.TargetA
import android.content.C
import android.graphics.PixelF
import android.media.AudioM
import android.os.B
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.H
import android.os.M
import android.util.AttributeS
import android.util.L
import android.view.G
import android.view.KeyE
import android.view.LayoutI
import android.view.MotionE
import android.view.V
import android.view.ViewG
import android.view.W
import android.view.WindowM
import android.view.accessibility.AccessibilityE
import android.view.accessibility.AccessibilityNodeI
import android.widget.FrameL
import android.widget.ImageB
import android.widget.ProgressB
import android.widget.SeekB
import android.widget.SeekBar.OnSeekBarChangeL
import android.widget.TextV
* A view containing controls for a MediaPlayer. Typically contains the
* buttons like &Play/Pause&, &Rewind&, &Fast Forward& and a progress
* slider. It takes care of synchronizing the controls with the state
* of the MediaPlayer.
* The way to use this class is to instantiate it programatically.
* The MediaController will create a default set of controls
* and put them in a window floating above your application. Specifically,
* the controls will float above the view specified with setAnchorView().
* The window will disappear if left idle for three seconds and reappear
* when the user touches the anchor view.
* Functions like show() and hide() have no effect when MediaController
* is created in an xml layout.
* MediaController will hide and
* show the buttons according to these rules:
* &li& The &previous& and &next& buttons are hidden until setPrevNextListeners()
has been called
* &li& The &previous& and &next& buttons are visible but disabled if
setPrevNextListeners() was called with null listeners
* &li& The &rewind& and &fastforward& buttons are shown unless requested
otherwise by using the MediaController(Context, boolean) constructor
with the boolean set to false
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MediaController extends FrameLayout {
private MediaPlayerControl
private Context
private View
private View
private WindowManager
private Window
private View
private WindowManager.LayoutParams mDecorLayoutP
private ProgressBar
private TextView
mEndTime, mCurrentT
private boolean
private boolean
private static final int
sDefaultTimeout = 3000;
private static final int
FADE_OUT = 1;
private static final int
SHOW_PROGRESS = 2;
private boolean
private boolean
private boolean
mListenersS
private View.OnClickListener mNextListener, mPrevL
onClickIsFullScreenListener clickIsFullScreenL
StringBuilder
private ImageButton
private ImageButton
private ImageButton
private ImageButton
private ImageButton
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mContext =
mUseFastForward =
mFromXml =
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
public MediaController(Context context, boolean useFastForward) {
super(context);
mContext =
mUseFastForward = useFastF
initFloatingWindowLayout();
initFloatingWindow();
public MediaController(Context context) {
this(context, true);
private void initFloatingWindow() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
//这里得注意下,使用PolicyCompat替换原来的
mWindow = PolicyCompat.createWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
// Allocate and initialize the static parts of mDecorLayoutParams. Must
// also call updateFloatingWindowLayout() to fill in the dynamic parts
// (y and width) before mDecorLayoutParams can be used.
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void initFloatingWindowLayout() {
mDecorLayoutParams = new WindowManager.LayoutParams();
WindowManager.LayoutParams p = mDecorLayoutP
p.gravity = Gravity.TOP | Gravity.LEFT;
p.height = LayoutParams.WRAP_CONTENT;
p.format = PixelFormat.TRANSLUCENT;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
p.windowAnimations = 0; // android.R.style.DropDownAnimationD
// Update the dynamic parts of mDecorLayoutParams
// Must be called with mAnchor != NULL.
private void updateFloatingWindowLayout() {
int [] anchorPos = new int[2];
mAnchor.getLocationOnScreen(anchorPos);
// we need to know the size of the controller so we can properly position it
// within its space
mDecor.measure(MeasureSpec.makeMeasureSpec(mAnchor.getWidth(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(mAnchor.getHeight(), MeasureSpec.AT_MOST));
WindowManager.LayoutParams p = mDecorLayoutP
p.width = mAnchor.getWidth();
p.x = anchorPos[0] + (mAnchor.getWidth() - p.width) / 2;
p.y = anchorPos[1] + mAnchor.getHeight() - mDecor.getMeasuredHeight();
// This is called whenever mAnchor&#39;s layout bound changes
private OnLayoutChangeListener mLayoutChangeListener =
(VERSION.SDK_INT &= VERSION_CODES.HONEYCOMB) ?
new OnLayoutChangeListener() {
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight,
int oldBottom) {
updateFloatingWindowLayout();
if (mShowing) {
mWindowManager.updateViewLayout(mDecor, mDecorLayoutParams);
private OnTouchListener mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mShowing) {
private ImageButton mIsFullS
public void setMediaPlayer(MediaPlayerControl player) {
updatePausePlay();
* Set the view that acts as the anchor for the control view.
* This can for example be a VideoView, or your Activity&#39;s main view.
* When VideoView calls this method, it will use the VideoView&#39;s parent
* as the anchor.
* @param view The view to which to anchor the controller when it is visible.
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setAnchorView(View view) {
boolean hasOnLayoutChangeListener = (VERSION.SDK_INT &= VERSION_CODES.HONEYCOMB);
if (hasOnLayoutChangeListener && mAnchor != null) {
mAnchor.removeOnLayoutChangeListener(mLayoutChangeListener);
if (hasOnLayoutChangeListener && mAnchor != null) {
mAnchor.addOnLayoutChangeListener(mLayoutChangeListener);
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
removeAllViews();
//在这里更改底部布局,以及获取相应控件对象,进行操作,
//建议原布局中控件类型和名字不要改,免得在这里又得修改,保证原功能完整
//需要添加的控件,添加后做相应处理
mRoot = makeControllerView();
initControllerView(mRoot);
addView(mRoot, frameParams);
* Create the view that holds the widgets that control playback.
* Derived classes can override this to create their own.
* @return The controller view.
* @hide This doesn&#39;t work as advertised
protected View makeControllerView() {
//MediaControllerd 布局
LayoutInflater inflate = LayoutInflater.from(getContext());
return inflate.inflate(R.layout.media_controller, null);
private void initControllerView(View v) {
mPauseButton = (ImageButton) v.findViewById(R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
mRewButton = (ImageButton) v.findViewById(R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
// By default these are hidden. They will be enabled when setPrevNextListeners() is called
mNextButton = (ImageButton) v.findViewById(R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
mPrevButton = (ImageButton) v.findViewById(R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mP
seeker.setOnSeekBarChangeListener(mSeekListener);
mProgress.setMax(1000);
mEndTime = (TextView) v.findViewById(R.id.time);
mCurrentTime = (TextView) v.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
//对全屏半屏切换进行操作
mIsFullScreen = (ImageButton) v.findViewById(R.id.is_full_screen);
mIsFullScreen.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
clickIsFullScreenListener.setOnClickIsFullScreen();
installPrevNextListeners();
//全屏半屏切换接口
public interface onClickIsFullScreenListener{
public void setOnClickIsFullScreen();
public void setClickIsFullScreenListener(onClickIsFullScreenListener listener){
this.clickIsFullScreenListener=
* Show the controller on screen. It will go away
* automatically after 3 seconds of inactivity.
public void show() {
show(sDefaultTimeout);
* Disable pause or seek buttons if the stream cannot be paused or seeked.
* This requires the control interface to be a MediaPlayerControlExt
private void disableUnsupportedButtons() {
if (mPauseButton != null && !mPlayer.canPause()) {
mPauseButton.setEnabled(false);
if (mRewButton != null && !mPlayer.canSeekBackward()) {
mRewButton.setEnabled(false);
if (mFfwdButton != null && !mPlayer.canSeekForward()) {
mFfwdButton.setEnabled(false);
} catch (IncompatibleClassChangeError ex) {
// We were given an old version of the interface, that doesn&#39;t have
// the canPause/canSeekXYZ methods. This is OK, it just means we
// assume the media can be paused and seeked, and so we don&#39;t disable
// the buttons.
* Show the controller on screen. It will go away
* automatically after &#39;timeout&#39; milliseconds of inactivity.
* @param timeout The timeout in milliseconds. Use 0 to show
* the controller until hide() is called.
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
disableUnsupportedButtons();
updateFloatingWindowLayout();
mWindowManager.addView(mDecor, mDecorLayoutParams);
mShowing =
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true.
This happens, for example, if we&#39;re
// paused with the progress bar showing the user hits play.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
public boolean isShowing() {
* Remove the controller from the screen.
public void hide() {
if (mAnchor == null)
if (mShowing) {
mHandler.removeMessages(SHOW_PROGRESS);
mWindowManager.removeView(mDecor);
} catch (IllegalArgumentException ex) {
Log.w(&MediaController&, &already removed&);
mShowing =
@SuppressLint(&HandlerLeak&)
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case FADE_OUT:
case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
= totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours & 0) {
return mFormatter.format(&%d:%02d:%02d&, hours, minutes, seconds).toString();
return mFormatter.format(&%02d:%02d&, minutes, seconds).toString();
private int setProgress() {
if (mPlayer == null || mDragging) {
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration & 0) {
// use long to avoid overflow
long pos = 1000L * position /
mProgress.setProgress( (int) pos);
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
show(0); // show until hide is called
case MotionEvent.ACTION_UP:
show(sDefaultTimeout); // start timeout
case MotionEvent.ACTION_CANCEL:
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
final boolean uniqueDown = event.getRepeatCount() == 0
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (keyCode ==
KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|| keyCode == KeyEvent.KEYCODE_SPACE) {
if (uniqueDown) {
doPauseResume();
show(sDefaultTimeout);
if (mPauseButton != null) {
mPauseButton.requestFocus();
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (uniqueDown && !mPlayer.isPlaying()) {
mPlayer.start();
updatePausePlay();
show(sDefaultTimeout);
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (uniqueDown && mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
show(sDefaultTimeout);
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP
|| keyCode == KeyEvent.KEYCODE_VOLUME_MUTE
|| keyCode == KeyEvent.KEYCODE_CAMERA) {
// don&#39;t show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
if (uniqueDown) {
show(sDefaultTimeout);
return super.dispatchKeyEvent(event);
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
private void updatePausePlay() {
if (mRoot != null && mPauseButton != null)
updatePausePlay(mPlayer.isPlaying(), mPauseButton);
protected void updatePausePlay(boolean isPlaying, ImageButton pauseButton) {
if (isPlaying) {
pauseButton.setImageResource(R.drawable.vvc_ic_media_pause);
pauseButton.setImageResource(R.drawable.vvc_ic_media_play);
private void doPauseResume() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
mPlayer.start();
updatePausePlay();
// There are two scenarios that can trigger the seekbar listener to trigger:
// The first is the user using the touchpad to adjust the posititon of the
// seekbar&#39;s thumb. In this case onStartTrackingTouch is called followed by
// a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
// We&#39;re setting the field &mDragging& to true for the duration of the dragging
// session to avoid jumps in the position in case of ongoing playback.
// The second scenario involves the user operating the scroll ball, in this
// case there WON&#39;T BE onStartTrackingTouch/onStopTrackingTouch notifications,
// we will simply apply the updated position without suspending regular updates.
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
mDragging =
// By removing these pending progress messages we make sure
// that a) we won&#39;t update the progress while the user adjusts
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
mHandler.removeMessages(SHOW_PROGRESS);
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser) {
// We&#39;re not interested in programmatically generated changes to
// the progress bar&#39;s position.
long duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime( (int) newposition));
public void onStopTrackingTouch(SeekBar bar) {
mDragging =
setProgress();
updatePausePlay();
show(sDefaultTimeout);
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
if (mProgress != null) {
mProgress.setEnabled(enabled);
disableUnsupportedButtons();
super.setEnabled(enabled);
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(MediaController.class.getName());
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(MediaController.class.getName());
private View.OnClickListener mRewListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
private View.OnClickListener mFfwdListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos += 15000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
private void installPrevNextListeners() {
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null);
if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null);
public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
mNextListener =
mPrevListener =
mListenersSet =
if (mRoot != null) {
installPrevNextListeners();
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
if (mPrevButton != null && !mFromXml) {
mPrevButton.setVisibility(View.VISIBLE);
public interface MediaPlayerControl {
getDuration();
getCurrentPosition();
seekTo(int pos);
boolean isPlaying();
getBufferPercentage();
boolean canPause();
boolean canSeekBackward();
boolean canSeekForward();
* Get the audio session id for the player used by this VideoView. This can be used to
* apply audio effects to the audio track of a video.
* @return The audio session, or 0 if there was an error.
getAudioSessionId();
}2.PolicyCompat.java.自己在其他项目里拿过来的,不太清楚此具体和源码中的有个区别,除过个window有关;
com.example.
import java.lang.reflect.C
import java.lang.reflect.M
import android.content.C
import android.os.B
import android.view.W
public class PolicyCompat {
* Private constants
private static final String PHONE_WINDOW_CLASS_NAME
= &com.android.internal.policy.PhoneWindow&;
private static final String POLICY_MANAGER_CLASS_NAME = &com.android.internal.policy.PolicyManager&;
private PolicyCompat() {
* Private methods
private static Window createPhoneWindow(Context context) {
/* Find class */
Class&?& cls = Class.forName(PHONE_WINDOW_CLASS_NAME);
/* Get constructor */
Constructor c = cls.getConstructor(Context.class);
/* Create instance */
return (Window)c.newInstance(context);
catch (ClassNotFoundException e) {
throw new RuntimeException(PHONE_WINDOW_CLASS_NAME + & could not be loaded&, e);
catch (Exception e) {
throw new RuntimeException(PHONE_WINDOW_CLASS_NAME + & class could not be instantiated&, e);
private static Window makeNewWindow(Context context) {
/* Find class */
Class&?& cls = Class.forName(POLICY_MANAGER_CLASS_NAME);
/* Find method */
Method m = cls.getMethod(&makeNewWindow&, Context.class);
/* Invoke method */
return (Window)m.invoke(null, context);
catch (ClassNotFoundException e) {
throw new RuntimeException(POLICY_MANAGER_CLASS_NAME + & could not be loaded&, e);
catch (Exception e) {
throw new RuntimeException(POLICY_MANAGER_CLASS_NAME + &.makeNewWindow could not be invoked&, e);
* Public methods
public static Window createWindow(Context context) {
if (false)
return createPhoneWindow(context);
return makeNewWindow(context);
}3.VideoView.java,这个类,只是简单的把实现源码中MediaPlayerControl接口,修改为上面自己写的MediaController中的接口MediaPlayerControl即可,还有一处就是此类中onMeasure中注释掉那些解码大小的判断,直接采用当前默认大小,然后设置mSurfaceHolder.setFixedSize(width, height);这句若没写,全屏会失败,
* Copyright (C) 2006 The Android Open Source Project
* Licensed under the Apache License, Version 2.0 (the &License&);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &AS IS& BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
com.example.
import java.io.IOE
import java.lang.reflect.M
import java.util.M
import com.example.vedioviewcompat.MediaController.MediaPlayerC
import android.annotation.SuppressL
import android.annotation.TargetA
import android.content.C
import android.media.AudioM
import android.media.MediaP
import android.media.MediaPlayer.OnCompletionL
import android.media.MediaPlayer.OnErrorL
import android.media.MediaPlayer.OnInfoL
import android.net.U
import android.os.B
import android.util.AttributeS
import android.util.L
import android.view.KeyE
import android.view.MotionE
import android.view.SurfaceH
import android.view.SurfaceV
import android.view.V
import android.view.accessibility.AccessibilityE
import android.view.accessibility.AccessibilityNodeI
* Displays a video file.
The VideoView class
* can load images from various sources (such as resources or content
* providers), takes care of computing its measurement from the video so that
* it can be used in any layout manager, and provides various display options
* such as scaling and tinting.&p&
* &em&Note: VideoView does not retain its full state when going into the
* background.&/em&
In particular, it does not restore the current play state,
* play position, selected tracks, or any subtitle tracks added via
* {@link #addSubtitleSource addSubtitleSource()}.
Applications should
* save and restore these on their own in
* {@link android.app.Activity#onSaveInstanceState} and
* {@link android.app.Activity#onRestoreInstanceState}.&p&
* Also note that the audio session id (from {@link #getAudioSessionId}) may
* change from its previously returned value when the VideoView is restored.
@SuppressLint(&NewApi&)
public class VideoView extends SurfaceView implements MediaPlayerControl {
private String TAG = &VideoView&;
// settable by the client
private Uri
private Map&String, String& mH
// all possible internal states
private static final int STATE_ERROR
private static final int STATE_IDLE
private static final int STATE_PREPARING
private static final int STATE_PREPARED
private static final int STATE_PLAYING
private static final int STATE_PAUSED
private static final int STATE_PLAYBACK_COMPLETED = 5;
// mCurrentState is a VideoView object&#39;s current state.
// mTargetState is the state that a method caller intends to reach.
// For instance, regardless the VideoView object&#39;s current state,
// calling pause() intends to bring the object to a target state
// of STATE_PAUSED.
private int mCurrentState = STATE_IDLE;
private int mTargetState
= STATE_IDLE;
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder =
private MediaPlayer mMediaPlayer =
private int
private int
private int
private int
private int
private MediaController mMediaC
private OnCompletionListener mOnCompletionL
private MediaPlayer.OnPreparedListener mOnPreparedL
private int
mCurrentBufferP
private OnErrorListener mOnErrorL
private OnInfoListener
private int
mSeekWhenP
// recording the seek position while preparing
private boolean
private boolean
private boolean
public VideoView(Context context) {
super(context);
initVideoView();
public VideoView(Context context, AttributeSet attrs) {
super(context, attrs);
initVideoView();
public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initVideoView();
public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
initVideoView();
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i(&@@@@&, &onMeasure(& + MeasureSpec.toString(widthMeasureSpec) + &, &
+ MeasureSpec.toString(heightMeasureSpec) + &)&);
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth & 0 && mVideoHeight & 0) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecS
height = heightSpecS
// for compatibility, we adjust size based on aspect ratio
if ( mVideoWidth * height
& width * mVideoHeight ) {
//Log.i(&@@@&, &image too wide, correcting&);
width = height * mVideoWidth / mVideoH
} else if ( mVideoWidth * height
& width * mVideoHeight ) {
//Log.i(&@@@&, &image too tall, correcting&);
height = width * mVideoHeight / mVideoW
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecS
height = width * mVideoHeight / mVideoW
if (heightSpecMode == MeasureSpec.AT_MOST && height & heightSpecSize) {
// couldn&#39;t match aspect ratio within the constraints
height = heightSpecS
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecS
width = height * mVideoWidth / mVideoH
if (widthSpecMode == MeasureSpec.AT_MOST && width & widthSpecSize) {
// couldn&#39;t match aspect ratio within the constraints
width = widthSpecS
// neither the width nor the height are fixed, try to use actual video size
width = mVideoW
height = mVideoH
if (heightSpecMode == MeasureSpec.AT_MOST && height & heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecS
width = height * mVideoWidth / mVideoH
if (widthSpecMode == MeasureSpec.AT_MOST && width & widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecS
height = width * mVideoHeight / mVideoW
// no size yet, just adopt the given spec sizes
setMeasuredDimension(width, height);
if(mSurfaceHolder!=null)
mSurfaceHolder.setFixedSize(width, height);
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(VideoView.class.getName());
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(VideoView.class.getName());
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
return getDefaultSize(desiredSize, measureSpec);
@SuppressWarnings(&deprecation&)
private void initVideoView() {
mVideoWidth = 0;
mVideoHeight = 0;
getHolder().addCallback(mSHCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
mCurrentState = STATE_IDLE;
mTargetState
= STATE_IDLE;
* Sets video path.
* @param path the path of the video.
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
* Sets video URI.
* @param uri the URI of the video.
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
* Sets video URI using specific headers.
* @param uri
the URI of the video.
* @param headers the headers for the URI request.
Note that the cross domain redirection is allowed by default, but that can be
changed with key/value pairs through the headers parameter with
&android-allow-cross-domain-redirect& as the key and &0& or &1& as the value
to disallow or allow cross domain redirection.
public void setVideoURI(Uri uri, Map&String, String& headers) {
mHeaders =
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
invalidate();
public void stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer =
mCurrentState = STATE_IDLE;
mTargetState
= STATE_IDLE;
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
// not ready for playback just yet, will try again later
AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
// we shouldn&#39;t clear the target state, because somebody might have
// called start() previously
release(false);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mOnInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
Method m = MediaPlayer.class.getMethod(&setDataSource&, Context.class, Uri.class, Map.class);
m.setAccessible(true);
m.invoke(mMediaPlayer, getContext(), mUri, mHeaders);
} catch (Exception e) {
mMediaPlayer.setDataSource(getContext(), mUri);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
// we don&#39;t set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, &Unable to open content: & + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
} catch (IllegalArgumentException ex) {
Log.w(TAG, &Unable to open content: & + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
public void setMediaController(MediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
mMediaController =
attachMediaController();
private void attachMediaController() {
if (mMediaPlayer != null && mMediaController != null) {
mMediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ?
(View)this.getParent() :
mMediaController.setAnchorView(anchorView);
mMediaController.setEnabled(isInPlaybackState());
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
new MediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
requestLayout();
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
mCanPause = mCanSeekBack = mCanSeekForward =
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
if (mMediaController != null) {
mMediaController.setEnabled(true);
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
int seekToPosition = mSeekWhenP
// mSeekWhenPrepared may be changed after seekTo() call
if (seekToPosition != 0) {
seekTo(seekToPosition);
if (mVideoWidth != 0 && mVideoHeight != 0) {
//Log.i(&@@@@&, &video size: & + mVideoWidth +&/&+ mVideoHeight);
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
// We didn&#39;t actually change the size (it was already at the size
// we need), so we won&#39;t get a &surface changed& callback, so
// start the video here instead of in the callback.
if (mTargetState == STATE_PLAYING) {
if (mMediaController != null) {
mMediaController.show();
} else if (!isPlaying() &&
(seekToPosition != 0 || getCurrentPosition() & 0)) {
if (mMediaController != null) {
// Show the media controls when we&#39;re paused into a video and make &#39;em stick.
mMediaController.show(0);
// We don&#39;t know the video size yet, but should start anyway.
// The video size might be reported to us later.
if (mTargetState == STATE_PLAYING) {
private MediaPlayer.OnCompletionListener mCompletionListener =
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
Log.d(TAG, &Error: & + framework_err + &,& + impl_err);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
if (mMediaController != null) {
mMediaController.hide();
/* If an error handler has been supplied, use it and finish. */
if (mOnErrorListener != null) {
if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
new MediaPlayer.OnBufferingUpdateListener() {
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mCurrentBufferPercentage =
* Register a callback to be invoked when the media file
* is loaded and ready to go.
* @param l The callback that will be run
public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
mOnPreparedListener =
* Register a callback to be invoked when the end of a media file
* has been reached during playback.
* @param l The callback that will be run
public void setOnCompletionListener(OnCompletionListener l)
mOnCompletionListener =
* Register a callback to be invoked when an error occurs
* during playback or setup.
If no listener is specified,
* or if the listener returned false, VideoView will inform
* the user of any errors.
* @param l The callback that will be run
public void setOnErrorListener(OnErrorListener l)
mOnErrorListener =
* Register a callback to be invoked when an informational event
* occurs during playback or setup.
* @param l The callback that will be run
public void setOnInfoListener(OnInfoListener l) {
mOnInfoListener =
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
public void surfaceChanged(SurfaceHolder holder, int format,
int w, int h)
mSurfaceWidth =
mSurfaceHeight =
boolean isValidState =
(mTargetState == STATE_PLAYING);
boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
if (mMediaPlayer != null && isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0) {
seekTo(mSeekWhenPrepared);
public void surfaceCreated(SurfaceHolder holder)
mSurfaceHolder =
openVideo();
public void surfaceDestroyed(SurfaceHolder holder)
// after we return from this we can&#39;t use the surface any more
mSurfaceHolder =
if (mMediaController != null) mMediaController.hide();
release(true);
* release the media player in any state
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer =
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState
= STATE_IDLE;
public boolean onTouchEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
public boolean onTrackballEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public boolean onKeyDown(int keyCode, KeyEvent event)
boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
keyCode != KeyEvent.KEYCODE_MENU &&
keyCode != KeyEvent.KEYCODE_CALL &&
keyCode != KeyEvent.KEYCODE_ENDCALL;
if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
mMediaController.show();
mMediaController.hide();
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (!mMediaPlayer.isPlaying()) {
mMediaController.hide();
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (mMediaPlayer.isPlaying()) {
mMediaController.show();
toggleMediaControlsVisiblity();
return super.onKeyDown(keyCode, event);
private void toggleMediaControlsVisiblity() {
if (mMediaController.isShowing()) {
mMediaController.hide();
mMediaController.show();
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
mTargetState = STATE_PLAYING;
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
mTargetState = STATE_PAUSED;
public void suspend() {
release(false);
public void resume() {
openVideo();
public int getDuration() {
if (isInPlaybackState()) {
return mMediaPlayer.getDuration();
return -1;
public int getCurrentPosition() {
if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
public void seekTo(int msec) {
if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
mSeekWhenPrepared = 0;
mSeekWhenPrepared =
public boolean isPlaying() {
return isInPlaybackState() && mMediaPlayer.isPlaying();
public int getBufferPercentage() {
if (mMediaPlayer != null) {
return mCurrentBufferP
private boolean isInPlaybackState() {
return (mMediaPlayer != null &&
mCurrentState != STATE_ERROR &&
mCurrentState != STATE_IDLE &&
mCurrentState != STATE_PREPARING);
public boolean canPause() {
return mCanP
public boolean canSeekBackward() {
return mCanSeekB
public boolean canSeekForward() {
return mCanSeekF
public int getAudioSessionId() {
if (mAudioSession == 0) {
MediaPlayer foo = new MediaPlayer();
mAudioSession = foo.getAudioSessionId();
foo.release();
return mAudioS
}4相关布局,media_controller.xml这个布局就是视频播放底部的布局,我这里是直接调整了下,加了全屏半屏切换按钮,自己有相关业务需要,可以来修改此布局,建议源码之前有的控件若无需要就先隐藏,不要删除,否则又得去修改MediaController类,此处不粘贴了,下面有demo下载;
activity_main.xml这布局就是在具体操作类中,全屏半屏的播放界面看下布局
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical& &
&RelativeLayout
android:id=&@+id/toprl&
android:layout_width=&match_parent&
android:layout_height=&0dp&
android:layout_weight=&1& &
&com.example.vedioviewcompat.VideoView
android:id=&@+id/videoView&
android:layout_width=&match_parent&
android:layout_height=&match_parent& /&
&/RelativeLayout&
&RelativeLayout
android:id=&@+id/rl_dd&
android:layout_width=&match_parent&
android:layout_height=&0dp&
android:layout_weight=&2& &
android:id=&@+id/dd&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&555& /&
&/RelativeLayout&
&/LinearLayout&5.在MainActivity.java中实现视频的播放,以及全屏半屏的切换,切换是通过让视频横屏和竖屏,来控制改变VideoView布局相对父布局情况来实现的,
public class MainActivity extends Activity implements onClickIsFullScreenListener {
private MediaController mC
private boolean fullscreen=
private VideoV
private ProgressBar progressB
private RelativeLayout rlDD;
private RelativeLayout rlT
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
viv = (VideoView) findViewById(R.id.videoView);
rlDD=(RelativeLayout) findViewById(R.id.rl_dd);
progressBar=(ProgressBar) findViewById(R.id.progressBar1);
mController = new MediaController(this);
mController.setClickIsFullScreenListener(this);
viv.setMediaController(mController);
progressBar.setVisibility(View.VISIBLE);
viv.setVideoURI(Uri.parse(&android.resource://& + getPackageName()
+ &/& + R.raw.apple));
viv.requestFocus();
viv.start();
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return super.onTouchEvent(event);
public void setOnClickIsFullScreen() {
// TODO Auto-generated method stub
if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){//设置RelativeLayout的全屏模式
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
Log.e(&info&, &横屏&);
rlDD.setVisibility(View.GONE);
Log.e(&info&, &竖屏&);
rlDD.setVisibility(View.VISIBLE);
super.onConfigurationChanged(newConfig);
viv.refreshDrawableState();
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
本来想添加个视频加载ProgressBar,自己还没想出来,后续再整,
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:11384次
排名:千里之外
原创:26篇
(3)(2)(2)(3)(5)(9)(9)

我要回帖

更多关于 videoview 全屏按钮 的文章

 

随机推荐