Webpage pops out of webview in Xamarin App - c#

When loading a webpage into the webview it shows correctly, but when I click on a menu item (on the web page inside the webview) it pops outside of the webview. Here is the code I'm using to load the webpage into the webview. How do I prevent this from happening.
BTW, the links are all normal links:
Menu Item
localWebView = FindViewById<WebView>(Resource.Id.webview);
localWebView.Settings.JavaScriptEnabled = true;
localWebView.Settings.JavaScriptCanOpenWindowsAutomatically = true;
localWebView.Settings.LoadWithOverviewMode = true;
localWebView.Settings.UseWideViewPort = true;
localWebView.Settings.BuiltInZoomControls = true;
localWebView.LoadUrl("https://...");

I needed to add a WebViewClient and it works now.
localWebView.SetWebViewClient(new MyWebViewClient());
public class MyWebViewClient : WebViewClient
{
[Obsolete("deprecated")]
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
view.LoadUrl(url);
return true;
}
}

Related

Xamarin Forms iOS RootViewController.View.AddSubview() not showing element in a page with Shell.PresentationMode="ModalAnimated"

I'm trying to add a floating Button for all my screens in a Xamarin forms app using Dependency service for each platform. iOS is working fine with any ContentPage but it fails when I set Shell.PresentationMode="ModalAnimated", button is not showing or is printing behind of ContentPage with animated modal.
Calling dependency service in my all views in Xamarin Forms
DependencyService.Get<IDeviceService>().ShowFloatingButton();
Dependency service implementation for iOS
namespace WebviewSample.iOS.DependencySeivices
{
public class DeviceService : IDeviceService
{
private void ShowFloatingButton()
{
var vc = UIApplication.SharedApplication.KeyWindow.RootViewController;
var btn = UIButton.FromType(UIButtonType.System);
btn.Frame = new CGRect(20, 200, 280, 44);
btn.SetTitle("Click Me", UIControlState.Normal);
vc.View.BackgroundColor = UIColor.DarkGray;
vc.View.AddSubview(btn);
vc.View.BringSubviewToFront(btn);
}
}
}
I have tried to get the top controller as below samples:
if (UIApplication.SharedApplication.KeyWindow.WindowLevel != UIWindowLevel.Normal)
{
foreach (var item in UIApplication.SharedApplication.Windows)
{
if (item.WindowLevel == UIWindowLevel.Normal)
{
vc = item.RootViewController;
break;
}
}
}
Also
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
According to this document:https://devblogs.microsoft.com/xamarin/xamarin-forms-shell-quick-tip-modal-navigation/
Xamarin shell navigation is different than traditional navigation where a page is pushed onto the stack so a new page pops up over the current page.

How to detect Xamarin Forms tabbed page click - iOS?

My scenario is, I have a Tabbed page in Xamarin Forms:
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var playPage = new NavigationPage(new PlayPage())
{
Title = "Play",
Icon = "play.png"
};
var settingsPage = new NavigationPage(new SettingsPage())
{
Title = "Settings",
Icon = "settings.png"
};
var favoritesPage = new NavigationPage(new FavoritesPage())
{
Title = "Favorites",
Icon = "fave.png"
};
var aboutPage = new NavigationPage(new AboutPage())
{
Title = "About",
Icon = "info.png"
};
Children.Add(playPage);
Children.Add(favoritesPage);
Children.Add(settingsPage);
Children.Add(aboutPage);
}
}
I want to add a pause and play function to my app. On start up, the PlayPage would initially have the play.png icon and when I click on the PlayPage again it would change the icon to pause.png. Page is not changing just the page icon. Anyone has any idea how this could be done?
Edit:
So I have created a custom renderer, in OnElementChanged I utilize the ViewControllerSelected:
var tabbarController = (UITabBarController)this.ViewController;
if (null != tabbarController)
{
tabbarController.ViewControllerSelected += OnTabBarReselected;
}
And my OnTabBarReselected I have:
private void OnTabBarReselected(object sender, UITabBarSelectionEventArgs e)
{
switch (TabBar.SelectedItem.Title)
{
case "Play":
TabBar.SelectedItem.Title = "Pause";
TabBar.SelectedItem.Image = UIImage.FromFile("pause.png");
break;
}
}
This only does half of the work. It changes the Title of the selected tab bar from Play to Pause after I click on the same tab but not the Icon. The icon remains "play.png" until I get out of that tab page (selecting another tab). Anyone has any idea why?
You will need to implement a custom renderer to pull this off. There are some implementations on James Montemagno's blog where he talks about changing the icons.
iOS:
http://motzcod.es/post/138225183932/tintcolor-selectedimage-xamarin-forms-ios
Droid:
http://motzcod.es/post/157544468267/xamarin-forms-android-selected-and-unselected-tab-colors
This is however not necessarily related to your requirement of tapping the icon and changing that specific icon since all this code only runs when the page initially loads. It could be a nice starting point though. Check in there if there's a property on TabbedPage that changes when you tap on the current tab and change the icon at that point.
You also have a OnCurrentPageChanged event you can override in TabbedPage, but that isn't called when the page is already active.

How do I have master details page and a back button on single page

I have app where in I have master details page something like this:
I would have this(left menu bar settings, login) static for all the pages. Since I am using master details page I am using messagingcenter to navigate between pages as given here:
MessagingCenter.Send(new RedirectClass.OpenDetails(), RedirectClass.OpenDetails.Key);
But now since I have used master details I cannot navigate back using back button. The back button would exit the application. Say user is at 'page A', When user clicks on settings menu the user should be redirected to settings page(settings page will all have left menu), so on click of back button on settings page should redirect user to 'Page A'. Which is not happening. ANy help?
MessagingCenter.Subscribe<RedirectClass.OpenDetails>(this, RedirectClass.OpenDetails.Key, (sender) =>
{
Detail = new NavigationPage(new Details())
{
BarBackgroundColor = Color.FromRgb(172, 183, 193),
BarTextColor = Color.Black,
BackgroundColor = Color.White
};
});
Instead of overriding the Detail page in your MessagingCenter callback
Detail = new NavigationPage(new Details())
You should use the Detail page's Navigation property to push the new page on the top of the stack
Detail.Navigation.PushAsync(new Details())
make sure your initial detail page is wrapped in a navigationpage
I was having same issue, Detail.Navigation.PushAsync(itemSelected) makes hamburger menu vanish I decided to use my own stack datatype for Master detail page. It was bit tricky to keep track and code but working fine.
Initialize it at the app load with current Detail page and for each item selected Push new page on top of stack.
public partial class MyMasterDetailPage: MasterDetailPage
{
private Stack navigationStack = new Stack();
public MyMasterDetailPage()
{
InitializeComponent();
navigationStack.Push(Detail);
try
{
masterPage.listView.ItemSelected += OnItemSelected;
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.Message);
}
}
Override OnBackButtonPressed() in same Page code behind
protected override bool OnBackButtonPressed()
{
try
{
var lastPage = navigationStack.Pop();
if (lastPage.Equals(Detail))
lastPage = navigationStack.Pop();
Detail = (Page)lastPage;
IsPresented = false;
// to avoid app close when complete pop and new page is push on top of it
if (navigationStack.Count == 0)
navigationStack.Push(Detail);
return true;
}
catch (Exception)
{
return base.OnBackButtonPressed();
}
}

Binding a HTML control into a stacklayout using xamarin forms

Being a newbie to Xamrin I am struggling to adding some HTML to a StackLayout via Xamarin Forms. I have tried quite a few things and had a Google around.
Firstly I can't work out which bindable object I am supposed to be using. As I cannot find a straight answer on Google/Xamarin I am going to assume this is not as easy I was hoping.
var nameEntry = new Label ();
nameEntry.SetBinding (Label.TextProperty, "Club.ClubName");
var webView = new WebView ();
webView.SetBinding ( ??? , "Club.Description");
var content = new StackLayout {
Children = {
nameEntry,
???
}
};
I am not sure if this is possible within Xamarin forms itself. Can anyone help?
I should point out my data for the form is being retrieved asynchronously on a remote json endpoint
protected override void OnAppearing ()
{
base.OnAppearing ();
if (ViewModel == null || ViewModel.IsLoading)
return;
ViewModel.LoadItemsCommand.Execute (Club.ClubId);
}
My remote json api contains, Description contatins a HTML snippet which I would like to use.
{
ClubName: "Stourbridge",
Description: "<p>This club meets every TWO weeks on a <b>Friday</b>.</p>"
...
}
Try the following example that will show how to do the bindings.
Note that you have to use a HtmlWebViewSource to achieve this, and bind the WebView.Source to this.
Clicking the button will change the view model and update the WebView appropriately to the newly changed text.
StackLayout objStackLayout = new StackLayout();
MyView objMyView = new MyView();
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text</p></body></html>";
HtmlWebViewSource objHtmlWebViewSource = new HtmlWebViewSource();
objHtmlWebViewSource.SetBinding(HtmlWebViewSource.HtmlProperty, "MyHtml");
objHtmlWebViewSource.BindingContext = objMyView;
WebView objWebview = new WebView();
objWebview.HorizontalOptions = LayoutOptions.FillAndExpand;
objWebview.VerticalOptions = LayoutOptions.FillAndExpand;
objWebview.Source = objHtmlWebViewSource;
Button objMyButton2 = new Button();
objMyButton2.Text="Change Html";
objMyButton2.Clicked+=((o2,e2)=>
{
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text that has changed.</p></body></html>";
});
objStackLayout.Children.Add(objMyButton2);
objStackLayout.Children.Add(objWebview);
The view model is just a simple one with a bindable property as below:-
public class MyView
: Xamarin.Forms.View
{
public static readonly BindableProperty MyHtmlProperty = BindableProperty.Create<MyView, string>(p => p.MyHtml, default(string));
public string MyHtml
{
get { return (string)GetValue(MyHtmlProperty); }
set { SetValue(MyHtmlProperty, value); }
}
}
Before clicking the button gives:-
After clicking the button, adjusts the view model, and automatically updates the control via the binding giving:-

Issue while enabling hyperlinks in master page from content page

I had written code to Enable and disable hyperlinks on master page from the content page. Every thing is working fine and the hyperlinks are getting disabled also after calling the DisableHyperlinkInMasterPage Method. When i am calling the EnableHyperlinkInMasterPage method still the hyperlinks are not working. If we are leaving that page , then i found that the hyperlinks starts working. My issue is after calling the EnableHyperlinkInMasterPage method , without leaving the page the hyperlinks are still disabled and not working and after leaving the page it getting enabled . Please help me that how i fix this issue.I debug the code and not found any error on EnableHyperlinkInMasterPage method.
private void DisableHyperlinkInMasterPage()
{
AssociateMaster mymaster = (AssociateMaster)Page.Master;
HyperLink home = (HyperLink)mymaster.FindControl("Home");
home.Enabled = false;
HyperLink profile = (HyperLink)mymaster.FindControl("ProfileLink");
profile.Enabled = false;
HyperLink report = (HyperLink)mymaster.FindControl("Report");
report.Enabled = false;
HyperLink signout = (HyperLink)mymaster.FindControl("SignOut");
signout.Enabled = false;
}
private void EnableHyperlinkInMasterPage()
{
AssociateMaster mymaster = (AssociateMaster)Page.Master;
HyperLink home = (HyperLink)mymaster.FindControl("Home");
home.Enabled = true;
HyperLink profile = (HyperLink)mymaster.FindControl("ProfileLink");
profile.Enabled = true;
HyperLink report = (HyperLink)mymaster.FindControl("Report");
report.Enabled = true;
HyperLink signout = (HyperLink)mymaster.FindControl("SignOut");
signout.Enabled = true;
}
Try using properties to enable and disable links. And try using FindControl as less as you can. Consider you have a link in your MasterPage named lnkTest. Write this code in your master page:
public bool TestLinkEnabled
{
get { return lnkTest.Enabled; }
set {lnkTest.Enabled = value; }
}
Then in your content page after adding this line to your page:
<%# MasterType VirtualPath="~/MasterPage.master" %>
enable and disable this link using:
Master.TestLinkEnabled = true;
Master.TestLinkEnabled = false;

Categories

Resources