Android MediaController 在 VideoView 上的定位
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3686729/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MediaController positioning over VideoView
提问by Mark B
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:
我有一个 VideoView,它以纵向占据 Activity 的上半部分,屏幕的下半部分显示一些图像和文本。当活动开始时,我正在视频视图中播放 rtsp 视频流。我已通过以下代码将 MediaController 附加到 VideoView:
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.
当我点击 VideoView 以在屏幕上显示 MediaController 时,我希望播放控件出现在 VideoView 的底部区域(MediaController 的底部甚至与 VideoView 的底部)。相反,MediaController 在屏幕下方弹出,覆盖我在 VideoView 下方的一些图形和文本。
Are there some additional steps I need to take to get the MediaController to appear where I want it to on the screen?
我是否需要采取一些额外的步骤才能让 MediaController 出现在我希望它出现在屏幕上的位置?
采纳答案by CommonsWare
Frankly, I'd just write my own controller. In fact, I did once.
坦率地说,我只是编写自己的控制器。事实上,我做过一次。
That being said, try setAnchorView()
-- by my reading of the source code, the MediaController
will appear at the bottom of whatever the anchor view is.
话虽如此,尝试setAnchorView()
- 通过我阅读源代码,MediaController
无论锚视图是什么,都将出现在底部。
回答by bk138
Setting the anchor view will only work if the videoview size is known - it will notbe 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);
}
});
}
});
回答by bughi
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:
只需将 videoView 包装在 FrameLayout 中,然后您就可以从代码中将 MediaController 添加到该 FrameLayout 中,如下所示:
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
编辑:自从我发布了这个答案后,我在隐藏它和控制它的大小方面遇到了很多问题,所以我最终做的是我只是用控件创建了自己的布局,我可以使用这些控件来制作动画和使用而不会头疼
回答by Hafiz
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.
我最近遇到了同样的问题,使用 setAnchorView(videoView) 会将控制器完全设置在 VideoView 下,而不是悬停在它的底部区域。我的 VideoView 是上部区域的三分之一屏幕,因此控制器最终覆盖了 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) :
下面是我在没有编写完整的自定义控制器的情况下完成它的方式(仅覆盖onSizeChanged
MediaController 以向上移动锚点):
Use FrameLayout as an anchor for MediaContoller, wrap it up together with VideoView as below :
使用 FrameLayout 作为 MediaContoller 的锚点,将其与 VideoView 包装在一起,如下所示:
<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 :
创建自定义 MediaController ,当它的大小改变时,它将向上移动 FrameLayout (与锚定到它的 MediaController 将跟随):
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 :
使用上面的自定义控制器代替标准控制器,然后将其锚定到 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);
}
回答by Rongan
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.
将 mediacontroller 视图设置为您想要的位置。希望这对你有帮助。
回答by Anh Duy
//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>
回答by Vishnu Priyaa
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>
回答by Humberto2991
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:
这是我第一次在 stackoverflow 中回答问题,我只在 FrameLayout 中插入一个 VideoView ,并且两者都具有相同的度量。MediaController 将位于 FrameLayout 的底部。这对我有用:
main_activity.XML:
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:
主活动.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();
}
}
}
回答by Sasha Shpota
With java 8:
使用Java 8:
videoView.setOnPreparedListener(mediaPlayer ->
mediaPlayer.setOnVideoSizeChangedListener(
(player, width, height) -> {
MediaController controller = new MediaController(YourActivity.this);
videoView.setMediaController(controller);
controller.setAnchorView(videoView);
}
)
);
回答by Stefan Zhelyazkov
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.
我通过包装做到了VideoView
一个内LinearView
,使得LinearView
具有layout_width="match_parent"
这样它总是一直延伸到屏幕的程度,但layout_height="wrap_content"
以使线性视图的高度始终是固定到所述内容的高度。这样,当视频播放时,控件始终与 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()