MediaController Positioning - bind to VideoView

2019-04-05 11:14发布

问题:

There have been a lot of discussions about how to position a MediaController and most answers are to use the setAnchorView-Method. At the first glance this solution seems to work but in my case it doesn't.

According to this Post setAnchorView only acts as a reference for initial positioning of the MediaController, but actually creates a new floating Window on top.

So what I want is a MediaController that is really bound to a parent View (e.g. VideoView).

For example if you have a LinearLayout within a ScrollView and you have to scroll down to your VideoView where the MediaController is attached to, the MediaController should really be attached to this VideoView so that the MediaController scrolls along with the VideoView.

Another Use-Case where this problem accurs is discussed here, where the MediaController is used within a ViewPager.

So how to achieve such a behavior for a MediaController?

回答1:

I ended up by doing a dirty hack... i just manually attached the view to my videoView to achieve the wanted behavior:

public void onPrepared(MediaPlayer mp) {

                MediaController mc = new MediaController(videoView.getContext(), false);
                // set correct height
                RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoView.getLayoutParams();
                params.height =  mp.getVideoHeight();
                videoView.setLayoutParams(params);

                videoView.setMediaController(mc);
                pBar.setVisibility(View.GONE);
                mc.show(0);

                FrameLayout f = (FrameLayout) mc.getParent();
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                lp.addRule(RelativeLayout.ALIGN_BOTTOM, videoView.getId());

                ((LinearLayout) f.getParent()).removeView(f);
                ((RelativeLayout) videoView.getParent()).addView(f, lp);

                mc.setAnchorView(videoView);
            }

the problem with this solution is, that setting the anchorView doesn't have any effect and therefore tapping on the VideoView doesn't hide/show the MediaController as it's supposed to.

There definitly is a much better solution and hopefully someone can give me a hint!



回答2:

Just wanted to add to DERIIIFranz's answer. I used the same method to assign the media controller to the view I wanted and to get the Hide() and Show() functions to work properly I simply made my own MediaController class and overrode the Hide() and Show() methods as well as the isShowing property (I'm doing this in C# with Xamarin, so I don't know what issues you would have with Java).

I also added my own click listener on the VideoView to ensure that I could handle the Hide() and Show() events myself.

public class MyMediaController : MediaController
{
    private bool _isShowing { get; set; } = false;
    public override bool IsShowing { get { return _isShowing; } }

    public override void Show ()
    {
        base.Show();
        _isShowing = true;

        Native.ViewGroup parent = ((Native.ViewGroup)this.Parent);
        parent.Visibility = Native.ViewStates.Visible;
    }

    public override void Hide ()
    {
        base.Hide();
        _isShowing = false;

        Native.ViewGroup parent = ((Native.ViewGroup)this.Parent);
        parent.Visibility = Native.ViewStates.Gone;
    }
}


回答3:

To convert Jonathan Hockman's answer to Java and add it to DERIIIFranz's answer:

public class MyMediaController extends MediaController {

        public MyMediaController(Context context) {
                super(context);
        }

        public MyMediaController(Context context, boolean useFastForward) {
                super (context, useFastForward);
        }

        public MyMediaController(Context context, AttributeSet attrs) {
                super(context, attrs);
        }

        private boolean _isShowing = false;

        @Override
        public boolean isShowing() { return _isShowing; }

        @Override
        public void show() {
                super.show();
                _isShowing = true;

                ViewGroup parent = (ViewGroup) this.getParent();
                parent.setVisibility(View.VISIBLE);
        }

        @Override
        public void hide() {
                super.hide();
                _isShowing = false;

                ViewGroup parent = (ViewGroup) this.getParent();
                parent.setVisibility(View.GONE);
        }
}

For the videoView:

    public void onPrepared(MediaPlayer mediaPlayer) {
            MyMediaController mediaController = new MyMediaController(videoView.getContext(), false);

            RelativeLayout parentLayout = (RelativeLayout) videoView.getParent();
            RelativeLayout.LayoutParams parentParams = (RelativeLayout.LayoutParams) parentLayout.getLayoutParams();
            parentParams.height = this.getHeight();
            parentLayout.setLayoutParams(parentParams);

            FrameLayout frameLayout = (FrameLayout) mediaController.getParent();
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, this.getId());

            ((ViewGroup)frameLayout.getParent()).removeView(frameLayout);
            parentLayout.addView(frameLayout, layoutParams);

            mediaController.setAnchorView(this);
            mediaController.hide();

            videoView.setMediaController(mediaController);
    }