Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 77050

Custom Renderer for Video View [Android] w/ Rotation

$
0
0

Hello All,

I'm looking for a bit of guidance or confirmation on a potential bug, I've exhausted all links on Google that I could find and have been spending a couple of days on this issue.

Here's what I'm attempting to achieve:

I want a video view to take up the top 1/4 of screen when in portrait mode then when you rotate the device into landscape mode the video view takes over into full screen mode; something like "Immersive" mode. Now I've found examples from Google and looked at Xamarin's bitbucket, but there seems be either an issue or something I'm missing in this ViewRenderer..

Below is the snippet of code found on THIS link for Xamarin's examples. The issue seems to be when I call this method the second time to 'toggle' it, nothing actually happens. It stays in the "immersive mode even though the Output reads "Turning immersive mode off".

`
public void ToggleHideyBar ()
{

        int uiOptions = (int)((MainActivity)this.Context).Window.DecorView.SystemUiVisibility;
        int newUiOptions = uiOptions;

        bool isImmersiveModeEnabled = ((uiOptions | (int)SystemUiFlags.ImmersiveSticky) == uiOptions);
        if (isImmersiveModeEnabled) {
            Log.Info ("", "Turning immersive mode mode off. ");
        } else {
            Log.Info ("", "Turning immersive mode mode on.");
        }


        newUiOptions ^= (int)SystemUiFlags.HideNavigation;
        newUiOptions ^= (int)SystemUiFlags.Fullscreen;
        newUiOptions ^= (int)SystemUiFlags.ImmersiveSticky;


        ((MainActivity)this.Context).Window.DecorView.SystemUiVisibility = (StatusBarVisibility)newUiOptions;

    }

protected override void OnAttachedToWindow ()
{
((Android.App.Activity)this.Context).Window.AddFlags(WindowManagerFlags.KeepScreenOn);

        ((Android.App.Activity)this.Context).Window.DecorView.SystemUiVisibilityChange += OnVisibilityChanged;// async (object sender, SystemUiVisibilityChangeEventArgs e) => ;


        base.OnAttachedToWindow ();
    }

private async void OnVisibilityChanged(object IntentSender, SystemUiVisibilityChangeEventArgs e)
{
if (e.Visibility == StatusBarVisibility.Visible) {

        }
    }

`

With the code above I've wired a method the SystemUiVisibilityChange event. Now when I first hit the "ToggleHideyBar" (rotating device sideways) this change method gets hit as it should because the actual value of "newUiOptions" is something like '4096'. Then when I rotate my device back to portrait "ToggleHideyBar" gets called again and the value of "newUiOptions" is set to 0. HOWEVER, the change method above does not get fired. I currently have the VideoView showing on the top 1/4 of the screen in portrait, then full screen (w/out restarting VideoView) or immerse mode. But when I rotate back to portrait the Navigation at the bottom and Action Bar at the top stay hidden.. Below is the entirety of the code that is at work, minus some specific code which I know isn't the issue:

`[assembly: ExportRendererAttribute(typeof(TwitchTvForms.Controls.VideoView), typeof(AndroidVideoView))]
namespace TwitchTvForms.Droid.Renderers
{
public class AndroidVideoView : ViewRenderer<TwitchTvForms.Controls.VideoView, Android.Widget.RelativeLayout>
{
private AudioManager audioManager;

    private FullScreenVideoView currentViewViewer;

    protected override void OnDetachedFromWindow()
    {
        ((Android.App.Activity)this.Context).Window.ClearFlags (WindowManagerFlags.KeepScreenOn);

        base.OnDetachedFromWindow();
    }

    protected override void OnAttachedToWindow ()
    {
        ((Android.App.Activity)this.Context).Window.AddFlags(WindowManagerFlags.KeepScreenOn);

        ((Android.App.Activity)this.Context).Window.DecorView.SystemUiVisibilityChange += OnVisibilityChanged;// async (object sender, SystemUiVisibilityChangeEventArgs e) => ;


        base.OnAttachedToWindow ();
    }



    private async void OnVisibilityChanged(object IntentSender, SystemUiVisibilityChangeEventArgs e)
    {
        if (e.Visibility == StatusBarVisibility.Visible) {
        }
    }


    protected override void OnElementChanged(ElementChangedEventArgs<Controls.VideoView> e)
    {
        base.OnElementChanged(e);

        var metrics = new DisplayMetrics();

        ((Android.App.Activity) this.Context).WindowManager.DefaultDisplay.GetMetrics(metrics);

    var rLayout = new global::Android.Widget.RelativeLayout(this.Context);

    rLayout.SetVerticalGravity (GravityFlags.Center);

    rLayout.LayoutParameters = new LayoutParams(LayoutParams.FillParent, LayoutParams.FillParent);

        currentViewViewer = GetVideoViewPlayer();

        rLayout.AddView(currentViewViewer);

        SetNativeControl(rLayout);
    }

public FullScreenVideoView GetVideoViewPlayer()
    {
        var vv = new FullScreenVideoView(this.Context);

        var lp =  new Android.Widget.RelativeLayout.LayoutParams (LayoutParams.WrapContent, LayoutParams.WrapContent);

        lp.AddRule (LayoutRules.AlignParentLeft);
        lp.AddRule (LayoutRules.AlignParentRight);

        lp.AddRule (LayoutRules.AlignParentBottom);

        lp.AddRule (LayoutRules.AlignParentTop);

        vv.LayoutParameters = lp;



        vv.Completion += CurrentViewViewerCompletion;

        vv.Touch += CurrentViewViewerTouch;            

        vv.SetVideoURI(Uri.Parse(this.Element.CurrentQuality.Uri));

        vv.Start();

        return vv;
    }  

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == TwitchTvForms.Controls.VideoView.CurrentQualityProperty.PropertyName) {
            currentViewViewer.SetVideoURI (Uri.Parse (this.Element.CurrentQuality.Uri));
        } else if (e.PropertyName == TwitchTvForms.Controls.VideoView.ControlOrientationProperty.PropertyName) {
            ToggleFullScreen ();
        }

    }   

    public void ToggleHideyBar ()
    {
        // BEGIN_INCLUDE (get_current_ui_flags)
        // The UI options currently enabled are represented by a bitfield.
        // getSystemUiVisibility() gives us that bitfield.
        int uiOptions = (int)((Android.App.Activity)this.Context).Window.DecorView.SystemUiVisibility;
        int newUiOptions = uiOptions;
        // END_INCLUDE (get_current_ui_flags)

        // BEGIN_INCLUDE (toggle_ui_flags)
        bool isImmersiveModeEnabled = ((uiOptions | (int)SystemUiFlags.ImmersiveSticky) == uiOptions);
        if (isImmersiveModeEnabled) {
            Log.Info ("", "Turning immersive mode mode off. ");
        } else {
            Log.Info ("", "Turning immersive mode mode on.");
        }

        // Immersive mode: Backward compatible to KitKat (API 19).
        // Note that this flag doesn't do anything by itself, it only augments the behavior
        // of HIDE_NAVIGATION and FLAG_FULLSCREEN.  For the purposes of this sample
        // all three flags are being toggled together.
        // This sample uses the "sticky" form of immersive mode, which will let the user swipe
        // the bars back in again, but will automatically make them disappear a few seconds later.
        newUiOptions ^= (int)SystemUiFlags.HideNavigation;
        newUiOptions ^= (int)SystemUiFlags.Fullscreen;
        newUiOptions ^= (int)SystemUiFlags.ImmersiveSticky;


        ((Android.App.Activity)this.Context).Window.DecorView.SystemUiVisibility = (StatusBarVisibility)newUiOptions;
        //END_INCLUDE (set_ui_flags)
    }
}

public class FullScreenVideoView : VideoView
{
public FullScreenVideoView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}

    public FullScreenVideoView(Context context) : base(context)
    {
    }

    public FullScreenVideoView(Context context, IAttributeSet attrs) : base(context, attrs)
    {
    }

    public FullScreenVideoView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
    }

    public FullScreenVideoView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
    {
    }

    private int GetStatusBarHeight()
    {
        var resourceId = this.Context.Resources.GetIdentifier("status_bar_height", "dimen", "android");

        if (resourceId > 0)
        {
            return Resources.GetDimensionPixelSize(resourceId);
        }

        return 0;
    }


    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure (widthMeasureSpec, heightMeasureSpec);
    }
}

}

namespace TwitchTvForms.Controls
{
public class VideoView : Frame
{

    public static BindableProperty QualityProperty = BindableProperty.Create<VideoView, TwitchVideoQuality[]>(a => a.Qualities,
        defaultValue: null,
        defaultBindingMode: BindingMode.TwoWay,
        propertyChanging: ((bindable, value, newValue) =>
        {
            var control = (VideoView)bindable;
            control.Qualities = newValue;
        }));

    public TwitchVideoQuality[] Qualities
    {
        get
        {
            return (TwitchVideoQuality[])
          GetValue(QualityProperty);
        }
        set
        {
            SetValue(QualityProperty, value);
        }
    }

    public static BindableProperty CurrentQualityProperty = BindableProperty.Create<VideoView, TwitchVideoQuality>(a => a.CurrentQuality,
        defaultValue: null,
        defaultBindingMode: BindingMode.TwoWay,
        propertyChanging: (bindable, value, newValue) =>
        {
            var control = (VideoView)bindable;
            control.CurrentQuality = newValue;
        }

        );

    public TwitchVideoQuality CurrentQuality
    {
        get { return (TwitchVideoQuality)GetValue(CurrentQualityProperty); }
        set { SetValue(CurrentQualityProperty, value); }
    }

    public static BindableProperty StreamTitleProperty = BindableProperty.Create<VideoView, string>(a => a.StreamTitle,
      defaultValue: "",
      defaultBindingMode: BindingMode.TwoWay,
      propertyChanging: (bindable, value, newValue) =>
      {
          var control = (VideoView)bindable;
          control.StreamTitle = newValue;
      }

      );

    public string StreamTitle
    {
        get { return (string)GetValue(StreamTitleProperty); }
        set { SetValue(StreamTitleProperty, value); }
    }

    public static BindableProperty StreamNameProperty = BindableProperty.Create<VideoView, string>(a => a.StreamName,
     defaultValue: "",
     defaultBindingMode: BindingMode.TwoWay,
     propertyChanging: (bindable, value, newValue) =>
     {
         var control = (VideoView)bindable;
         control.StreamName = newValue;
     }

     );

    public string StreamName
    {
        get { return (string)GetValue(StreamNameProperty); }
        set { SetValue(StreamNameProperty, value); }
    }

    public static BindableProperty StreamUriProperty = BindableProperty.Create<VideoView, string>(a => a.StreamUri,
     defaultValue: "",
     defaultBindingMode: BindingMode.TwoWay,
     propertyChanging: (bindable, value, newValue) =>
     {
         var control = (VideoView)bindable;
         control.StreamUri = newValue;
     }

     );

    public string StreamUri
    {
        get { return (string)GetValue(StreamUriProperty); }
        set { SetValue(StreamUriProperty, value); }
    }


    public static BindableProperty ControlOrientationProperty = BindableProperty.Create<VideoView, TwitchTvForms.Services.Orientation>(a => a.ControlOrientation,
        defaultValue: TwitchTvForms.Services.Orientation.Portrait,
        defaultBindingMode: BindingMode.OneWay,
        propertyChanging: (bindable, value, newValue) =>
        {
            var control = (VideoView)bindable;
            control.ControlOrientation = newValue;
        }

    );

    public TwitchTvForms.Services.Orientation ControlOrientation
    {
        get { return (TwitchTvForms.Services.Orientation)GetValue(ControlOrientationProperty); }
        set { SetValue(ControlOrientationProperty, value);

            if (value == TwitchTvForms.Services.Orientation.Landscape) {
                this.HorizontalOptions = LayoutOptions.FillAndExpand;
                this.VerticalOptions = LayoutOptions.FillAndExpand;
            } else {
                this.HorizontalOptions = LayoutOptions.FillAndExpand;
                this.VerticalOptions = LayoutOptions.Start;
            }
        }
    }

    public VideoView ()
    {
        HeightRequest = 150;
    }
}

}
`

And finally here is the method in my ContentPage that handles the rotation:

`protected override void OnSizeAllocated (double width, double height)
{
if (VideoView != null) {
if (width > height) {
VideoView.ControlOrientation = Orientation.Landscape;

                NavigationPage.SetHasNavigationBar (this, false);

            } else {

                VideoView.ControlOrientation = Orientation.Portrait;

                NavigationPage.SetHasNavigationBar (this, true);

            }
        }

        base.OnSizeAllocated (width, height);
    }

`
Any help would be greatly appreciated.

Apologizes for the formatting, tried to get it look correct, but gave up on it.


Viewing all articles
Browse latest Browse all 77050

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>