【问题标题】:MediaController positioning over VideoViewMediaController 在 VideoView 上的定位
【发布时间】:2010-09-10 17:15:59
【问题描述】:

我有一个 VideoView,它以纵向占据 Activity 的上半部分,屏幕的下半部分显示一些图像和文本。 Activity 启动时,我正在视频视图中播放 rtsp 视频流。我已通过以下代码将 MediaController 附加到 VideoView:

    MediaController controller = new MediaController(this);
    controller.setAnchorView(this.videoView);
    controller.setMediaPlayer(this.videoView);
    this.videoView.setMediaController(controller);

当我点击 VideoView 以在屏幕上调出 MediaController 时,我希望播放控件会出现在 VideoView 的底部区域(MediaController 的底部甚至与 VideoView 的底部)。相反,MediaController 在屏幕下方弹出,覆盖了我在 VideoView 下方的一些图形和文本。

是否需要采取一些额外的步骤才能让 MediaController 出现在我希望它出现在屏幕上的位置?

【问题讨论】:

标签: android


【解决方案1】:

只有在 videoview 大小已知的情况下才能设置锚视图 - 它不会在初始化时。但你可以这样做:

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

【讨论】:

  • 一旦视图准备好开始调用 setAnchorView() 是有意义的。即从 onPrepared() 调用
  • setAnchorView(video) 使用 VideoView 的父级来覆盖媒体控件。如果您有固定高度的视频,请确保将其放在框架布局中,以便媒体控件位于视频顶部。
  • @Prakash 这就是我要找的东西……你的评论就是我所需要的……非常感谢。
  • 这行得通,谢谢。就我而言,更多的上下文:
【解决方案2】:

我找到了非常简单的解决方案。

只需将 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);

编辑:自从我发布了这个答案后,我遇到了很多关于让它隐藏和控制它的大小的问题,所以我最终做的是我只是用我可以动画和使用的控件创建了自己的布局头疼

【讨论】:

  • 不错,但是为什么mediaController的搜索栏会在一段时间后不更新?
  • 你的回答对我有用,将视频视图放在一个框架中是一个聪明的主意,谢谢
【解决方案3】:

我最近遇到了同样的问题,使用 setAnchorView(videoView) 会将控制器完全设置在 VideoView 下,而不是悬停在它的底部区域。我的 VideoView 是上部区域的三分之一屏幕,因此控制器最终会覆盖 VideoView 下的任何 View。

以下是我最终在不编写成熟的自定义控制器的情况下完成它的方式(仅覆盖 MediaController 的 onSizeChanged 以向上移动锚点):

使用 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>

创建自定义 MediaController,当 FrameLayout 的大小发生变化时,它将向上移动 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();
    }       
}

使用上面的自定义控制器代替标准控制器,然后将其锚定到 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);                
}

【讨论】:

    【解决方案4】:

    我用这段代码来解决它。

    mediaController.setPadding(0, 0, 0, px);
    

    将媒体控制器视图设置到您想要的位置。 希望对您有所帮助。

    【讨论】:

    • px 是一个 int 类型变量,它是距离屏幕底部的像素数。
    • 设置填充将扩展 MediaController 视图,因此您将无法获取其下方任何内容的输入事件。最好设置边距。
    • @bk138 它是自己的窗口,所以你仍然不会。
    【解决方案5】:

    试试setAnchorView()——通过阅读源代码,MediaController 将出现在锚视图的底部。

    【讨论】:

    • 我迫切地想弄清楚这一点。我昨天发布了一个关于扩展 MediaController 的问题:stackoverflow.com/questions/7881272/…。我查看了您的 github 代码,但无法弄清楚。我想我需要重写 setAnchorView 方法,这样我就可以开始将 MediaController 放在我喜欢的任何地方。他们是一种让它“浮动”并以这种方式定位的方法吗?
    • 我想在视频中添加贴纸,我已经发布了一个详细的问题stackoverflow.com/questions/43963522/…,我的问题是获取用户输入,正如 commonsware 所说,相对于覆盖图像(位置,比例,旋转)和背景视频
    • @PratikButaniAndroidDev:在这一点上,我建议使用更现代的解决方案,例如 ExoPlayer,而不是VideoVidew
    • 没关系,我使用的是ExoPlayer,但根据问题,由于死链接,您的答案没有答案
    • 这个答案没有帮助,OP 问题显示他已经在使用 setAnchorView() 并且链接已损坏。
    【解决方案6】:

    将您的视频视图放在线性布局中

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

    【讨论】:

      【解决方案7】:
          //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>
      

      【讨论】:

      • 如果您有任何问题,请告诉我
      【解决方案8】:

      我通过将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>
      

      以及活动的代码:

      // create media controller
      val mediaController = MediaController(this@DisplayClipActivity)
      mediaController.setAnchorView(videoView)
      mediaController.setMediaPlayer(videoView)
      
      // video view
      videoView.setVideoURI(uri)
      videoView.setMediaController(mediaController)
      videoView.start()
      

      【讨论】:

        【解决方案9】:

        这是我第一次在 stackoverflow 中回答问题,我只在 FrameLayout 中插入了一个 VideoView,两者都具有相同的度量。 MediaController 将位于 FrameLayout 的底部。这对我有用:

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

        【讨论】:

          【解决方案10】:

          使用 java 8

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-09
            • 1970-01-01
            • 2017-09-23
            • 1970-01-01
            • 1970-01-01
            • 2021-12-14
            • 1970-01-01
            相关资源
            最近更新 更多