MediaController positioning over VideoView
I have a VideoView that takes up the top half of the Activity in portrait orientation with the bottom half of the screen showing some images and text. I am playing a rtsp video stream in the video view when the Activity starts. I have attached a MediaController to the VideoView via the following code:
MediaController controller = new MediaController(this);
controller.setAnchorView(this.videoView);
controller.setMediaPlayer(this.videoView);
this.videoView.setMediaController(controller);
When I tap the VideoView to bring up the MediaController on the screen I expected the playback controls to appear overlaying the bottom area of the VideoView (the bottom of the MediaController even with the bottom of the VideoView). Instead the MediaController pops up lower down on the screen, overlaying some of the graphics and text I have below the VideoView.
Are there some additional steps I need to take to get the MediaController to appear where I want it to on the 开发者_如何学JAVAscreen?
Setting the anchor view will only work if the videoview size is known - it will not be upon init. But you can do something like this:
video.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
/*
* add media controller
*/
mc = new MediaController(YourActivity.this);
video.setMediaController(mc);
/*
* and set its position on screen
*/
mc.setAnchorView(video);
}
});
}
});
I found really easy solution.
Just wrap the videoView in a FrameLayout then you can add the MediaController to that FrameLayout from code, like this:
MediaController mc = new MediaController(context);
videoView.setMediaController(mc);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.BOTTOM;
mc.setLayoutParams(lp);
((ViewGroup) mc.getParent()).removeView(mc);
((FrameLayout) findViewById(R.id.videoViewWrapper)).addView(mc);
EDIT: since I posted this answer I ran into a lot of issues with getting it to hide and with controlling its size so what I ended up doing was I just created my own layout with controls that I could animate and work with without headaches
I encounter the same problem recently, using setAnchorView(videoView) will set the controller fully under VideoView instead hovering on the bottom area of it. My VideoView is one third screen in upper area, so the controller end up covering whatever View under VideoView.
Below is the way I end up doing it without writing full-blown custom controller (only overriding onSizeChanged
of MediaController to move anchor up) :
Use FrameLayout as an anchor for MediaContoller, wrap it up together with VideoView as below :
<RelativeLayout
android:id="@+id/videoLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.3"
android:layout_gravity="center"
android:background="#000000">
<VideoView
android:id="@+id/videoView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<FrameLayout android:id="@+id/controllerAnchor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
Create custom MediaController that will move FrameLayout up (with MediaController that is anchored to it will follow) when its size changed :
public class MyMediaController extends MediaController
{
private FrameLayout anchorView;
public MyMediaController(Context context, FrameLayout anchorView)
{
super(context);
this.anchorView = anchorView;
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
{
super.onSizeChanged(xNew, yNew, xOld, yOld);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) anchorView.getLayoutParams();
lp.setMargins(0, 0, 0, yNew);
anchorView.setLayoutParams(lp);
anchorView.requestLayout();
}
}
Use the custom controller above in place of the standard one and then anchor it to the FrameLayout :
protected void onCreate(Bundle savedInstanceState)
{
//...
videoView = (VideoView) findViewById(R.id.videoView1);
videoController = new MyMediaController(this, (FrameLayout) findViewById(R.id.controllerAnchor));
videoView.setMediaController(videoController);
//...
}
public void onPrepared(MediaPlayer mp)
{
videoView.start();
FrameLayout controllerAnchor = (FrameLayout) findViewById(R.id.controllerAnchor);
videoController.setAnchorView(controllerAnchor);
}
I use this code to solve it.
mediaController.setPadding(0, 0, 0, px);
to set the mediacontroller view to the position you want. Hope this help you.
Try setAnchorView()
-- by my reading of the source code, the MediaController
will appear at the bottom of whatever the anchor view is.
Put your video view inside a linear layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hp.videoplayer.MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<VideoView
android:layout_width="300dp"
android:layout_height="180dp"
android:id="@+id/player"
android:layout_marginTop="40dp"
android:layout_centerHorizontal="true"/>
</LinearLayout>
</RelativeLayout>
//It work good with me
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<VideoView
android:id="@+id/videoview"
android:layout_width="640dp"
android:layout_height="400dp"
android:layout_centerInParent="true" >
</VideoView>
<FrameLayout
android:id="@+id/videoViewWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
</FrameLayout>
</RelativeLayout>
package com.example.videoview;
import android.app.Activity;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.MediaController;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.Toast;
import android.widget.VideoView;
public class MainActivity extends Activity {
// private String path = "http://clips.vorwaerts-gmbh.de/VfE_html5.mp4";
private String path = "http://2387227f13276d2e8940-fbe0b8d9df729a57ca0a851a69d15ebb.r55.cf1.rackcdn.com/hero_2012_demo.mp4";
private VideoView mVideoView;
MediaController mc;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mVideoView != null)
return;
/**
* TODO: Set the path variable to a streaming video URL or a local media
* file path.
*/
mVideoView = (VideoView) findViewById(R.id.videoview);
mVideoView.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MainActivity.this, "The End", Toast.LENGTH_LONG)
.show();
}
});
if (path == "") {
// Tell the user to provide a media file URL/path.
Toast.makeText(
MainActivity.this,
"Please edit MainActivity, and set path"
+ " variable to your media file URL/path",
Toast.LENGTH_LONG).show();
} else {
/*
* Alternatively,for streaming media you can use
* mVideoView.setVideoURI(Uri.parse(path));
*/
mVideoView.setVideoPath(path);
mVideoView
.setMediaController(new MediaController(MainActivity.this));
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp,
int width, int height) {
/*
* add media controller
*/
mc = new MediaController(MainActivity.this);
mVideoView.setMediaController(mc);
/*
* and set its position on screen
*/
mc.setAnchorView(mVideoView);
((ViewGroup) mc.getParent()).removeView(mc);
((FrameLayout) findViewById(R.id.videoViewWrapper))
.addView(mc);
mc.setVisibility(View.INVISIBLE);
}
});
mVideoView.start();
}
});
mVideoView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if (mc != null) {
mc.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mc.setVisibility(View.INVISIBLE);
}
}, 2000);
}
return false;
}
});
}
}
private RelativeLayout.LayoutParams paramsNotFullscreen, paramsFullscreen;
/**
* handle with the configChanges attribute in your manifest
*/
@Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
if (paramsFullscreen == null) {
paramsNotFullscreen = (RelativeLayout.LayoutParams) mVideoView
.getLayoutParams();
paramsFullscreen = new LayoutParams(paramsNotFullscreen);
paramsFullscreen.setMargins(0, 0, 0, 0);
paramsFullscreen.height = ViewGroup.LayoutParams.MATCH_PARENT;
paramsFullscreen.width = ViewGroup.LayoutParams.MATCH_PARENT;
paramsFullscreen.addRule(RelativeLayout.CENTER_IN_PARENT);
paramsFullscreen.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
paramsFullscreen.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
paramsFullscreen.addRule(RelativeLayout.ALIGN_PARENT_TOP);
paramsFullscreen.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
}
// To fullscreen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
mVideoView.setLayoutParams(paramsFullscreen);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
mVideoView.setLayoutParams(paramsNotFullscreen);
}
}
@Override
protected void onPause() {
if (mVideoView.isPlaying()) {
mVideoView.pause();
}
super.onPause();
}
@Override
public void onBackPressed() {
if (mVideoView != null) {
mVideoView.stopPlayback();
}
finish();
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.videoview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.videoview.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:theme="@android:style/Theme.Dialog" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I did it by wrapping the VideoView
inside a LinearView
such that the LinearView
has layout_width="match_parent"
so that it always stretches to the extent of the screen but layout_height="wrap_content"
so that the height of the linear view is always fixed to the height of the content. This way when the video plays the controls are always positioned with the VideoView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".DisplayClipActivity">
<VideoView android:id="@+id/episode_clip"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
and the code for the Activity:
// create media controller
val mediaController = MediaController(this@DisplayClipActivity)
mediaController.setAnchorView(videoView)
mediaController.setMediaPlayer(videoView)
// video view
videoView.setVideoURI(uri)
videoView.setMediaController(mediaController)
videoView.start()
this is the first time I answer a question in stackoverflow, I only insert a VideoView inside a FrameLayout with same measures both. MediaController will be at the bottom of the FrameLayout. This worked for me:
main_activity.XML:
<FrameLayout
android:id="@+id/frame_layout_video"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="400dp">
<VideoView
android:id="@+id/video_select"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:adjustViewBounds="true"
android:clickable="true"
android:scaleType="centerCrop"
/>
</FrameLayout>
MainActivity.java:
@Override
public void onClick(View v) {
int i = v.getId();
if(i == R.id.select_video){
selectVideo();
}
private void selectVideo(){
//this code is to get videos from gallery:
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.addCategory(Intent.CATEGORY_OPENABLE);
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("video/*");
startActivityForResult(galleryIntent, GALLERY_REQUEST);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(mVideo);
//mVideo is the VideoView where I insert the video
mVideo.setMediaController(mediaController);
mVideo.pause();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
mVideoUri = data.getData();
mVideo.setVideoURI(mVideoUri);
mVideo.start();
}
}
}
With java 8:
videoView.setOnPreparedListener(mediaPlayer ->
mediaPlayer.setOnVideoSizeChangedListener(
(player, width, height) -> {
MediaController controller = new MediaController(YourActivity.this);
videoView.setMediaController(controller);
controller.setAnchorView(videoView);
}
)
);
精彩评论