MediaController positioning over VideoView

Android

Android Problem Overview


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 screen?

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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

Solution 3 - Android

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

Solution 4 - Android

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.

Solution 5 - Android

Try setAnchorView() -- by my reading of the source code, the MediaController will appear at the bottom of whatever the anchor view is.

Solution 6 - Android

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>

Solution 7 - Android

    //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>

Solution 8 - Android

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()

Solution 9 - Android

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

Solution 10 - Android

With java 8:

videoView.setOnPreparedListener(mediaPlayer ->
    mediaPlayer.setOnVideoSizeChangedListener(
        (player, width, height) -> {
            MediaController controller = new MediaController(YourActivity.this);
            videoView.setMediaController(controller);
            controller.setAnchorView(videoView);
        }
    )
);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark BView Question on Stackoverflow
Solution 1 - Androidbk138View Answer on Stackoverflow
Solution 2 - AndroidbughiView Answer on Stackoverflow
Solution 3 - AndroidHafizView Answer on Stackoverflow
Solution 4 - AndroidRonganView Answer on Stackoverflow
Solution 5 - AndroidCommonsWareView Answer on Stackoverflow
Solution 6 - AndroidVishnu PriyaaView Answer on Stackoverflow
Solution 7 - AndroidAnh DuyView Answer on Stackoverflow
Solution 8 - AndroidStefan ZhelyazkovView Answer on Stackoverflow
Solution 9 - AndroidHumberto2991View Answer on Stackoverflow
Solution 10 - AndroidSasha ShpotaView Answer on Stackoverflow