How to disable the Slide Menu functionality in iOS Xamarin.Forms - xamarin.forms

I'm facing some issue with Slide menu in Masterdetail page. I want to disable the functionality in iOS.
In Android, I'm able to disable. But, in iOS it's not working.
"IsGestureEnabled="False" - This Property is working in Android. But not in iOS.
Please help me out this issue.

It seems an existing,and you can use CustomRenderer . Here is a workaround .However , this workaround seems obsolete because of the update of Xamarin.So we can improve it .
[assembly: ExportRenderer (typeof(MasterDetailPage), typeof(ExtendedMasterDetailPageRenderer), UIUserInterfaceIdiom.Phone)]
namespace Core.iOS.Renderers
{
public class ExtendedMasterDetailPageRenderer : PhoneMasterDetailRenderer
{
private MasterDetailPage page;
public ExtendedMasterDetailPageRenderer ()
{
}
// add following override method
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
((MasterDetailPage)this.Element).PropertyChanged += HandlePropertyChanged;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
((MasterDetailPage)this.Element).PropertyChanged += HandlePropertyChanged;
}
private void HandlePropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == MasterDetailPage.IsGestureEnabledProperty.PropertyName)
{
var panGesture = typeof(PhoneMasterDetailRenderer).GetField ("panGesture", BindingFlags.NonPublic | BindingFlags.Instance).GetValue (this) as UIPanGestureRecognizer;
var hasPanGesture = false;
if (panGesture != null)
{
for (int i = 0; i < this.View.GestureRecognizers.Length; i++)
{
if (this.View.GestureRecognizers [i] is UIPanGestureRecognizer)
{
hasPanGesture = true;
break;
}
}
if (((MasterDetailPage)this.Element).IsGestureEnabled)
{
if (!hasPanGesture)
{
this.View.AddGestureRecognizer (panGesture);
}
return;
}
if (hasPanGesture)
{
this.View.RemoveGestureRecognizer (panGesture);
}
}
}
}
}
}
And in your MasterDetailPage
protected override void OnAppearing()
{
base.OnAppearing();
IsGestureEnabled = false;
}
Update
Create a CustomRenderer of Page
[assembly: ExportRenderer(typeof(Page), typeof(MyPageRenderer), UIUserInterfaceIdiom.Phone)]
namespace xxx.iOS
{
class MyPageRenderer : PageRenderer
{
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (this.NavigationController != null)
{
var items = this.NavigationController.NavigationBar.Items;
if(items.Length > 0)
{
UIBarButtonItem leftItem = items[0].LeftBarButtonItem;
if(this.NavigationController.ViewControllers.Length == 1)
{
leftItem.Enabled = false;
}
}
}
}
}
}

Related

iOS web view renderer doesn't update its value

I have implemented WebViewRenderer it works well on Android but it doesn't work on iOS. It displays the value, but then user clicks next button and the value doesn't update. I have tried the the example on ms website, but that displayed no text, I don't have the values from URL. I have also tried several post here.
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace MyApp.iOS.Renderers
{
public class ExtendedWebViewRenderer : ViewRenderer<ExtendedWebView, WKWebView>
{
WKWebView _wkWebView;
static ExtendedWebView _xwebView = null;
protected override void OnElementChanged(ElementChangedEventArgs<ExtendedWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
WKWebViewConfiguration config = new WKWebViewConfiguration();
_wkWebView = new WKWebView(Frame, config);
_wkWebView.NavigationDelegate = new CustomWKNavigationDelegate(this);
SetNativeControl(_wkWebView);
}
if (e.NewElement != null)
{
HtmlWebViewSource source = (Xamarin.Forms.HtmlWebViewSource)Element.Source;
string html = source.Html;
_wkWebView.LoadHtmlString(html, baseUrl: null);
_wkWebView.ScrollView.ScrollEnabled = false;
_wkWebView.SizeToFit();
}
}
}
public class CustomWKNavigationDelegate : WKNavigationDelegate
{
ExtendedWebViewRenderer _webViewRenderer;
public CustomWKNavigationDelegate(ExtendedWebViewRenderer webViewRenderer)
{
_webViewRenderer = webViewRenderer;
}
public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
var wv = _webViewRenderer.Element as ExtendedWebView;
if (wv != null)
{
await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
}
}
}
}
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace MyApp.Droid.Renderers
{
public class ExtendedWebViewRenderer : WebViewRenderer
{
public static int _webViewHeight;
static ExtendedWebView _xwebView = null;
public WebView _webView;
bool isScroll;
[Obsolete]
public ExtendedWebViewRenderer(Context context) : base(context)
{
}
class ExtendedWebViewClient : WebViewClient
{
WebView _webView;
public async override void OnPageFinished(WebView view, string url)
{
try
{
_webView = view;
if (_xwebView != null)
{
view.Settings.JavaScriptEnabled = true;
await Task.Delay(100);
string result = await _xwebView.EvaluateJavaScriptAsync("(function(){return document.body.scrollHeight;})()");
_xwebView.HeightRequest = Convert.ToDouble(result);
}
base.OnPageFinished(view, url);
}
catch (Exception ex)
{
Console.WriteLine($"{ex.Message}");
}
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
return true;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
_xwebView = e.NewElement as ExtendedWebView;
_webView = Control;
if (e.OldElement == null)
{
_webView.SetWebViewClient(new ExtendedWebViewClient());
}
}
}
}
public class ExtendedWebView : WebView
{
public ExtendedWebView()
{
}
}
XAML
<controls:ExtendedWebView
VerticalOptions="FillAndExpand" Grid.RowSpan="2"
x:Name="enView"
Opacity="1"
Source="{Binding CZ, Mode=TwoWay}"/>
private static HtmlWebViewSource htmlSourceExplanation = new HtmlWebViewSource();
public HtmlWebViewSource Cz
{
get { return _cz; }
set
{
_cz = value;
NotifyPropertyChanged(nameof(Cz));
}
}
private void SetExplanationDetail(string text, string text2)
{
htmlSourceExplanation.Html = _style + "<div class=\"text\"><div>" + text + "</div><div>" + text2 + "</div></div>";
_cz = htmlSourceExplanation;
NotifyPropertyChanged("Cz");
}
I expect the value to change once to user cliks the button. `

How can I redirect the phone dialer from WebView when I click on a phone number?

I have implemented a custom web view renderer in Droid project.
How can I redirect the Phone Dialer from WebView when I click on a phone number in WebView?
Any help is appreciated. Thanks!
You can try the following code:
public class MyWebViewRenderer : WebViewRenderer
{
public MyWebViewRenderer(Context context) : base(context) { }
static MyWebView _xwebView = null;
WebView _webView;
class ExtendedWebViewClient : Android.Webkit.WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
var tel = "tel:";
if (url != null)
{
if (url.StartsWith(tel))
{
var uri = Android.Net.Uri.Parse(url);
var intent = new Intent(Intent.ActionView, uri);
intent.SetFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
return true;
}
}
return false;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
_xwebView = e.NewElement as MyWebView;
_webView = Control;
if (e.OldElement == null)
{
_webView.SetWebViewClient(new ExtendedWebViewClient());
}
}
}
And for the ios part:
public class MyWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationDelegate = new MyWKNavigationDelegate();
}
class MyWKNavigationDelegate : WKNavigationDelegate
{
[Export("webView:decidePolicyForNavigationAction:decisionHandler:")]
public override void DecidePolicy(WKWebView webView, WKNavigationAction
navigationAction, Action<WKNavigationActionPolicy> decisionHandler)
{
var navType = navigationAction.NavigationType;
var targetFrame = navigationAction.TargetFrame;
var url = navigationAction.Request.Url;
if (
url.ToString().StartsWith("http") && (targetFrame != null &&
targetFrame.MainFrame == true)
)
{
decisionHandler(WKNavigationActionPolicy.Allow);
}
else if (
url.ToString().StartsWith("mailto:")
|| url.ToString().StartsWith("tel:")
|| url.ToString().StartsWith("Tel:"))
{
UIApplication.SharedApplication.application.OpenUrl(url);
}
}
}
}

How to remove visual material entry underline in xamarin forms ios [duplicate]

This question already has answers here:
Remove underline from Entry Control in Xamarin Forms
(5 answers)
Closed 1 year ago.
We are using the visual material entry for our project.
using Xamarin.Forms.Material.IOS;
[assembly: ExportRenderer(typeof(Entry), typeof(CustomMaterialEntryRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MyApp.Android
{
public class CustomMaterialEntryRenderer : MaterialProgressBarRenderer
{
//...
}
}
How to remove material entry underline in xamarin forms ios?
You could set the active underline height to 0f to achieve this:
[assembly: ExportRenderer(typeof(CustomMaterialEntry), typeof(CustomMaterialEntryRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MyApp.iOS
public class CustomMaterialEntryRenderer : MaterialEntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
Control.ActiveTextInputController.UnderlineHeightActive = 0f;
}
}
}
You can use custom renderers with material visual to achieve entry underline removal.
I am using the below code to apply it for all entries in the project and it is working with Xamarin Forms 4.8+
Xamarin Android
Entry
[assembly: ExportRenderer(typeof(Entry), typeof(EntryMaterialRendererAndroid), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace XFTest.Droid.Renderers
{
public class EntryMaterialRendererAndroid : MaterialEntryRenderer
{
public EntryMaterialRendererAndroid(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BoxStrokeWidth = 0;
Control.BoxStrokeWidthFocused = 0;
}
}
}
}
Xamarin iOS
Entry
[assembly: ExportRenderer(typeof(Entry), typeof(EntryMaterialRendereriOS), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace XFTest.iOS.Renderers
{
public class EntryMaterialRendereriOS : MaterialEntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
EntryRemoveUnderLine();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
EntryRemoveUnderLine();
}
protected void EntryRemoveUnderLine()
{
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.None;
Control.Underline.Enabled = false;
Control.Underline.DisabledColor = UIColor.Clear;
Control.Underline.Color = UIColor.Clear;
Control.Underline.BackgroundColor = UIColor.Clear;
Control.ActiveTextInputController.UnderlineHeightActive = 0f;
Control.PlaceholderLabel.BackgroundColor = UIColor.Clear;
}
}
}
}

How to remove the button click highlight

I have a submit button in my page, when I click on the button, button color is slightly changing (highlight).
How to remove this highlight feature in xamarin forms.
On Android it is called ripple effect, you can create a custom renderer to hide it
[assembly: ExportRenderer(typeof(Button), typeof(MyButtonRenderer))]
namespace App.Droid
{
public class MyButtonRenderer : ButtonRenderer
{
public MyButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Control.Background != null && e.NewElement != null)
{
var buttonBackgroundColor = e.NewElement.BackgroundColor;
Control.Background = new RippleDrawable(
new ColorStateList(
new[] { new int[] { } },
new[] { new int { } })
, new ColorDrawable(buttonBackgroundColor.ToAndroid()), null);
}
}
}
}

FontFamily on Shell -> TabBar -> Tab -> Title

Is there a way to set this a font family? I'm unable to find how to do it. In what way I can implement this?
as i didn't find the direct property to set,here i use Custom Renderen to achive it (for Android):
create a AndroidShell.cs in Droid project:
[assembly: ExportRenderer(typeof(ShellTest.AppShell), typeof(AndroidShell))]
namespace ShellTest.Droid
{
class AndroidShell : ShellRenderer
{
public AndroidShell(Context context) : base(context)
{
}
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
{
return new MyBottomNavigationView(this);
}
}
}
create MyBottomNavigationView.cs :
internal class MyBottomNavigationView: IShellBottomNavViewAppearanceTracker
{
private AndroidShell androidShell;
public MyBottomNavigationView(AndroidShell androidShell)
{
this.androidShell = androidShell;
}
public void Dispose()
{
}
public void ResetAppearance(BottomNavigationView bottomView)
{
IMenu menu = bottomView.Menu;
for (int i = 0; i < bottomView.Menu.Size(); i++)
{
IMenuItem menuItem = menu.GetItem(i);
var title = menuItem.TitleFormatted;
Typeface typeface = Typeface.CreateFromAsset(MainActivity.Instance.Assets, "HYXuJingXingKaiW.ttf");
SpannableStringBuilder sb = new SpannableStringBuilder(title);
sb.SetSpan(new CustomTypefaceSpan("",typeface), 0, sb.Length(), SpanTypes.InclusiveInclusive);
menuItem.SetTitle(sb);
}
}
public void SetAppearance(BottomNavigationView bottomView, ShellAppearance appearance)
{
}
}
create CustomTypefaceSpan.cs:
class CustomTypefaceSpan :TypefaceSpan
{
private Typeface newType;
public CustomTypefaceSpan(String family, Typeface type) : base(family)
{
newType = type;
}
public override void UpdateDrawState(TextPaint ds)
{
applyCustomTypeFace(ds,newType);
}
public override void UpdateMeasureState(TextPaint paint)
{
applyCustomTypeFace(paint,newType);
}
private static void applyCustomTypeFace(Paint paint, Typeface tf)
{
TypefaceStyle oldStyle;
Typeface old = paint.Typeface;
if (old == null)
{
oldStyle = 0;
}
else
{
oldStyle = old.Style;
}
TypefaceStyle fake = oldStyle & ~tf.Style;
if ((fake & TypefaceStyle.Bold) != 0)
{
paint.FakeBoldText = true;
}
if ((fake & TypefaceStyle.Italic) != 0)
{
paint.TextSkewX = -0.25f;
}
paint.SetTypeface(tf);
}
}
and HYXuJingXingKaiW.ttf is put inside Resources/Assets with BuildAction:AndroidAsset
in ios,you could try add this in AppDelegate.cs :
UITabBarItem.Appearance.SetTitleTextAttributes(new UITextAttributes() {Font=UIFont.FromName("HYXuJingXingKaiW.ttf",14), },UIControlState.Normal);
UITabBarItem.Appearance.SetTitleTextAttributes(new UITextAttributes() { Font = UIFont.FromName("HYXuJingXingKaiW.ttf", 14), }, UIControlState.Selected);
HYXuJingXingKaiW.ttf is put inside Resources
Leo Zhu's Answer is correct but didn't work for me until i put the ResetAppearance(bottomView) in SetAppearance Method. And i put this : if (title == null) { continue; } in ResetAppearance method.
At first, in your Android Folder, you need to add internal static MainActivity Instance { get; private set; } to MainActivity Class in MainActivity.cs and Initialize it by Instance = this; in OnCreate method in the same class.
public void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
{
ResetAppearance(bottomView);
}
public void ResetAppearance(BottomNavigationView bottomView)
{
IMenu menu = bottomView.Menu;
for (int i = 0; i < bottomView.Menu.Size(); i++)
{
IMenuItem menuItem = menu.GetItem(i);
var title = menuItem.TitleFormatted;
if (title == null) { continue; }
Typeface typeface = Typeface.CreateFromAsset(MainActivity.Instance.Assets, "HYXuJingXingKaiW.ttf");
SpannableStringBuilder sb = new SpannableStringBuilder(title);
sb.SetSpan(new CustomTypefaceSpan("",typeface), 0, sb.Length(), SpanTypes.InclusiveInclusive);
menuItem.SetTitle(sb);
}
}

Resources