I work on a Xamarin.Forms app (UWP!). It has a Master-Details architecture. The Master page has a ListView, and each item in it opens a corresponding Detail page. The first Detail page has only a WebView that plays a YouTube video upon loading. The second Detail view has just a placeholder label for now.
Where I switch from first Detail page to the second, the sound of the video from the first Detail page is still heard. And when I switch back to the first Detail page, the video loads again, and now I hear two voices. How can I stop the video upon switching to the second Detail page and resume when going back? If this is not possible, how can I just stop the video upon leaving its Detail page?
I guess I could do something in an overridden OnDisappearing() method of the detail page:
protected override void OnDisappearing()
{
MyWebView.NavigateToString(""); // This does not work, as NavigateToString() is not part of WebView.
base.OnDisappearing();
}
What can I use to stop playing video in WebView?
Could you please tell what I can use to stop playing video in WebView?
For your requirement, you could approach with injecting Eval java script.
private void Button_Clicked(object sender, EventArgs e)
{
string pausefunctionString = #"
var videos = document.querySelectorAll('video');
[].forEach.call(videos, function(video) { video.pause(); });
";
MyWebView.Eval(pausefunctionString);
}
Update
I have re-checked your issue, when you navigate to another page, the WebView has not be released correctly. If you want to stop the WebView video play, you could make it navigate to blank page via custom WebViewRenderer.
[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebViewRender))]
namespace App4.UWP
{
class CustomWebViewRender : WebViewRenderer
{
private Windows.UI.Xaml.Controls.WebView _WebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var source = Element.Source as UrlWebViewSource;
_WebView = new Windows.UI.Xaml.Controls.WebView();
SetNativeControl(_WebView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == WebView.SourceProperty.PropertyName)
{
var source = Element.Source as UrlWebViewSource;
if (source.Url == string.Empty)
{
_WebView.NavigateToString(string.Empty);
}
}
}
}
}
Usage
protected override void OnAppearing()
{
base.OnAppearing();
MyWebView.Source = "https://www.youtube.com";
}
protected override void OnDisappearing()
{
MyWebView.Source = string.Empty;
base.OnDisappearing();
}
Xaml
<WebView HeightRequest="500" WidthRequest="500" x:Name="MyWebView"/>
Related
I want to display awarded ad when app is starting.
I load ads under InitializeComponent(); with this code:
public MainPage()
{
InitializeComponent();
//Load Interestitial Ad
CrossMTAdmob.Current.LoadInterstitial("ca-app-pub-9688730828394396/1781454910");
//Load Rewarded Ad
CrossMTAdmob.Current.LoadRewardedVideo("ca-app-pub-9688730828394396/9667490273");
}
I have two buttons when users click on them different ads starting with this code:
private void ShowReward_OnClicked(object sender, EventArgs e)
{
CrossMTAdmob.Current.ShowRewardedVideo();
}
private void ShowInterstitial_OnClicked(object sender, EventArgs e)
{
CrossMTAdmob.Current.ShowInterstitial();
}
I try to put CrossMTAdmob.Current.ShowInterstitial(); from one button in my OnAppearing() method but when I start application, the ad does not appear with this code:
protected override void OnAppearing()
{
base.OnAppearing();
SetEvents();
CrossMTAdmob.Current.ShowInterstitial();
}
Can I get some example how to display my ad when app is starting ?
I'm the author of the plugin you are using.
You should check if the ads is actually loaded before trying to show it.
You can use
IsInterstitialLoaded()
And
IsRewardedVideoLoaded().
If these methods return true, then you can show the ads.
If the result is always false then you have to understand why they are not loaded, you can see in the output windows if you receive some error messages.
Most of the time the reason is a wrong Id.
I'm trying to display James Montemagno's Media Picker immediately when a user navigates to one of my tabbed pages. I found a function called OnAppearing() that I tried overriding to create this result. Although it technically shows the camera immediately when I switch tabs, after I close out of the media picker I get an error saying "only one operation can be active at a time".
Here is how I'm trying to implement this feature:
protected override async void OnAppearing()
{
TakePhotoButton_Clicked();
}
async void TakePhotoButton_Clicked()
{
//Allows users to take pictures in the app
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
DisplayAlert("No Camera", "Camera is not available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
//Sets the properties of the photo file
SaveToAlbum = true,
PhotoSize = PhotoSize.MaxWidthHeight,
DefaultCamera = CameraDevice.Rear
});
if (file == null)
return;
}
I'm pretty new to all of this and I feel as if I'm making a technical error. I read this post https://damian.fyi/2016/07/06/only-one-operation-can-be-active-at-at-time/ about someone getting the same error. They claimed, "I finally realized that after taking the photo it was re-displaying the form, causing the appearing event to be fired again, and thus causing a new photo to be taken while the old one was being taken. Hence the crash."
However, I'm not catching how my code is causing this. Any guidance would be appreciated.
use a bool variable to check if you have already taken a picture
bool first = true;
protected override async void OnAppearing()
{
if (first) TakePhotoButton_Clicked();
}
async void TakePhotoButton_Clicked()
{
first = false;
...
}
Initial Issue
I need to register ProcessLifecycleOwner as described here Xamarin.Android Architecture Components in my Application.OnCreate method.
But it had resulted in the error with 6.2.2 version of MvvmCross:
MvvmCross.Exceptions.MvxIoCResolveException: Failed to resolve type MvvmCross.ViewModels.IMvxAppStart occurred
or just stuck on the Splash Screen with 6.2.3.
Fix
Those problems were fixed by advice from Xamarin.Android mvvmcross app crashes when launching with intent filter.
[Application]
public class App : MvxAndroidApplication<Setup, Core.App>
{
public App(IntPtr reference, JniHandleOwnership transfer) :
base(reference, transfer) { }
public override void OnCreate()
{
MvxAndroidSetupSingleton
.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized();
base.OnCreate();
}
}
Current Issue
However Splash Screen dissapeared too, only blue background from default theme was left.
A workaround I've found:
public override void OnCreate()
{
Task.Run(() => MvxAndroidSetupSingleton
.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized());
base.OnCreate();
}
But due to parallelism it is not reliable, sometimes works, sometimes crashes.
Question
How Splash Screen can be restored?
Your approach is most likely blocking on the UI thread which us causing the UI to block during the time that the expected splash screen is suppose to show.
Try using an async event handler to allow for a non blocking UI call
[Application]
public class App : MvxAndroidApplication<Setup, Core.App> {
public App(IntPtr reference, JniHandleOwnership transfer) :
base(reference, transfer) {
EnsureInitialized = onEnsureInitialized; //Subscribe to event
}
private event EventHandler EnsureInitialized = delegate { };
private async void onEnsureInitialized(object sender, EventArgs args) {
await Task.Run(() => MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized());
}
public override void OnCreate() {
EnsureInitialized(this, EventArgs.Empty); //Raise event
base.OnCreate();
}
}
I Handled webview success loading as the following :
void WebOnEndNavigating(object sender, WebNavigatedEventArgs e)
{
if (e.Result!=WebNavigationResult.Success)
{
//show message ... click on the button to retry
}
}
Here is event Refresh button :
void Refresh_Click(object Sender,EventArgs e)
{
webview.Source = (webview.Source as UrlWebViewSource).Url;
}
When I connect to the internet an click on the refresh button, Reloading webview success but on WebOnEndNavigating eventHandler WebNavigationResult is failed
what is the correct way to reload webview on Xamarin.Forms
I would like to know if there is a working sample for monotouch that shows a working example for receiving remote control events such as those from the headphone buttons.
I have implemented a single view iphone app, implemented CanBecomeFirstResponder, called BecomeFirstResponder and also UIApplication.SharedApplication.BeginReceivingRemoteControlEvents() but I dont get any events.
Here is my code for my SingleViewController.
public partial class SingleViewViewController : UIViewController
{
public SingleViewViewController () : base ("SingleViewViewController", null)
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
AVAudioSession audioSession = AVAudioSession.SharedInstance();
NSError error;
audioSession.SetCategory(AVAudioSession.CategoryPlayback, out error);
audioSession.SetActive(true,out error);
this.BecomeFirstResponder();
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
public override bool CanBecomeFirstResponder {
get {
return true;
}
}
public override bool CanResignFirstResponder {
get {
return false;
}
}
public override void RemoteControlReceived (UIEvent theEvent)
{
base.RemoteControlReceived (theEvent);
}
}
I spent a little bit of time on this and I think I might have an answer for you. My first faulty assumption was that the volume up and down controls on the remote (headphones) would register but they don't.
I haven't managed to confirm the following except through trial and error, but it appears that you need to have an AVAudioPlayer playing something, or at least playing something when you start the AVAudioSession. Without playing something the play / stop event gets passed to the Music app which handles it.
In your code, in the ViewDidLoad method after the call to base, I added
AVAudioPlayer player = new AVAudioPlayer(new NSUrl("Music/test.m4a", false), null);
player.PrepareToPlay();
player.Play();
If you look at chapter 27 of these samples on GitHub, you'll see an example that plays audio and handles the remote control events.
https://github.com/mattneub/Programming-iOS-Book-Examples
I wasn't able to get remote control events working without the player playing, your example matched lots of Obj-C samples but I couldn't make it work in Xcode either.
Hope this helps.