Xamarin Forms Shell: Handling Android Scrolling in WebViews

2019-07-26 13_14_18-android webview xamarin - Google Search.pngXamarin Forms Shell is an awesome new development tool allowing you to build amazing apps faster. Shell takes care of a lot of the plumbing so you can focus more on the app to make your customer happy, rather than the behind the scenes details needed to support your features.

There is a special case you do need to take care of on Android to allow the app to scroll WebViews as there currently is a bug. When a user tries to scroll, it won’t.

Instead of using WebView in your XAML, change that to use a new custom one that simply inherits from WebView:

namespace App.Views.Common
{
    /// <summary>
    /// Needed for Android scroll issue
    /// </summary>
    public class MyWebView  : WebView
    {
    }
}

In your XAML reference it will look like this:

<common:MyWebView 
x:Name="WebView" 
HorizontalOptions="FillAndExpand" 
VerticalOptions="FillAndExpand">
</common:MyWebView>

Now we add a renderer to the Android project:

[assemblyExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace App.Droid.Renderers
{
    class MyWebViewRenderer : WebViewRenderer
    {
        public MyWebViewRenderer(Context context) : base(context)
        {
        }
 
        protected override void OnElementChanged(ElementChangedEventArgs<WebViewe)
        {
            base.OnElementChanged(e);
        }
 
        public override bool DispatchTouchEvent(MotionEvent e)
        {
            Parent.RequestDisallowInterceptTouchEvent(true);
            return base.DispatchTouchEvent(e);
        }
    }
}

 iOS requires no changes.

Advertisements

#Xamarin Forms #Shell: Creating a Gradient Flyout

David Ortinau’s Xappy was a fun demo of some of the features of the Rendering capabilities of the new Xamarin Forms Shell. That has served as an inspiration for the gradient flyout in this article. We’ve extended it to handle some Android Dispose issues in Shell that in the next Xamarin Forms should go away.

Here’s how it looks when running:

2019-07-26 12_47_38-iPhone 7 iOS 12.4.png

In Shell, you can enhance the UI with simple Renderers you add as classes to your iOS and Android projects. You decorate them with [ExportRender] to tell Xamarin to use them.

Style

Add this to the App.xaml so that you have the Flyout styles ready to be accessed. Note that they are dynamic so that they can be updated live.


    <Color x:Key="FlyoutGradientStart">#347FB9</Color>
    <Color x:Key="FlyoutGradientEnd">#38AECC</Color>

Renderers

The easy one in this example is iOS, it’s straight forward, just add it anywhere in your iOS project:

using System;
using CoreAnimation;
using CoreGraphics;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
 
 
[assemblyExportRenderer(typeof(Shell), typeof(App.iOS.Renderers.GradientShellRenderer))]
namespace App.iOS.Renderers
{
	/// <summary>
	/// Inspired by David Ortinau's Xappy renderer
	/// </summary>
    public class GradientShellRenderer : ShellRenderer
    {
        private CAGradientLayer _flyoutBackground = null;
 
        protected override void OnElementSet(Shell element)
        {
            base.OnElementSet(element);
        }
 
        protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
        {
            var renderer = base.CreateShellSectionRenderer(shellSection);
            if (renderer == nullreturn null;
 
            if (renderer is ShellSectionRenderer r)
            {
	            r.NavigationBar.ShadowImage = new UIImage();
            }
 
            return (IShellSectionRenderer)renderer;
        }
 
        protected override IShellFlyoutContentRenderer CreateShellFlyoutContentRenderer()
        {
 
            var flyout = base.CreateShellFlyoutContentRenderer();
            flyout.WillAppear += OnFlyoutWillAppear;
 
            var tv = (UITableView)flyout.ViewController.View.Subviews[0];
            tv.ScrollEnabled = false;
 
            return flyout;
        }
 
        /// <summary>
        /// Only grab the bounds of the View when View rendering calculations are already done
        /// </summary>
        private void OnFlyoutWillAppear(object senderEventArgs e)
        {
            if (_flyoutBackground == null && sender != null && sender is IShellFlyoutContentRenderer flyout)
			{
	            var view = flyout.ViewController.View;
 
                _flyoutBackground = new CAGradientLayer
                {
	                Frame = new CGRect(0, 0, view.Bounds.Widthview.Bounds.Height),
	                Colors = new []
	                {
		                ((ColorApp.Current.Resources["FlyoutGradientStart"]).ToCGColor(), ((ColorApp.Current.Resources["FlyoutGradientEnd"]).ToCGColor()
	                }
                };
 
                flyout.ViewController.View.Layer.InsertSublayer(_flyoutBackground, 0);
                flyout.WillAppear -= OnFlyoutWillAppear;
            }
        }
    }
}

Next in your Android project add this one. Note that we handle the Dispose due to a bug in Xamarin Shell in 4.1

The dispose needs to be taken care of or your app will crash a lot because of

ShellSectionRenderer.UnhookEvents ()

System.NullReferenceException: Object reference not set to an instance of an object
[assemblyExportRenderer(typeof(Shell), typeof(App.Droid.Renderers.GradientShellRenderer))]
 
namespace App.Droid.Renderers
{
	/// <summary>
	/// Inspired by David Ortinau's Xappy renderer
	/// </summary>
    public class GradientShellRenderer : ShellRenderer
    {
	    bool _disposed;
        public GradientShellRenderer(Context context) : base(context)
        {
        }
 
        protected override void OnElementSet(Shell element)
        {
            base.OnElementSet(element);
        }
 
        protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
        {
            var renderer = base.CreateShellSectionRenderer(shellSection);
            return (IShellSectionRendererrenderer;
        }
 
        protected override IShellFlyoutRenderer CreateShellFlyoutRenderer()
        {
            var flyout = base.CreateShellFlyoutRenderer();
 
            return flyout;
        }
 
        protected override IShellFlyoutContentRenderer CreateShellFlyoutContentRenderer()
        {
 
            var flyout = base.CreateShellFlyoutContentRenderer();
 
            try
            {
	            GradientDrawable gradient = new GradientDrawable(
		            GradientDrawable.Orientation.BottomTop,
		            new Int32[]
		            {
			            ((ColorApp.Current.Resources["FlyoutGradientStart"]).ToAndroid(),
			            ((ColorApp.Current.Resources["FlyoutGradientEnd"]).ToAndroid()
 
		            }
	            );
 
	            var cl = ((CoordinatorLayoutflyout.AndroidView);
	            cl.SetBackground(gradient);
 
	            var g = (AppBarLayoutcl.GetChildAt(0);
	            g.SetBackgroundColor(Color.Transparent.ToAndroid());
	            g.OutlineProvider = null;
 
	            var header = g.GetChildAt(0);
	            header.SetBackgroundColor(Color.Transparent.ToAndroid());
 
            }
            catch (Exception e)
            {
	            Logger.LogError(e);
            }
 
            return flyout;
        }
 
        protected override void Dispose(bool disposing)
        {
	        if (_disposed)
	        {
		        return;
	        }
 
	        if (disposing && Element!=null)
	        {
		        Element.PropertyChanged -= OnElementPropertyChanged;
		        Element.SizeChanged -=
			        (EventHandlerDelegate.CreateDelegate(typeof(EventHandler), this"OnElementSizeChanged"); // OnElementSizeChanged is private, so use reflection
	        }
 
	        _disposed = true;
        }
    }
}

 

#Xamarin Forms: When Apple rejects your binary for a quirky weird reason

question-mark-2110767_960_720.jpgYou’ve just updated your #Xamarin Forms app, it’s perfect and so you send the update via the Application Loader to Apple and…. the Apple servers reject it for some seeming crazy reason.

Don’t worry. It’s not you. Your code is fine. Here’s a checklist I go through to get the app into the approval process every time.

info.plist

Sometimes Visual Studio changes your info.pist and breaks it.

Review it for the common items like CFBundleName, UIDeviceFamily, UIRequiredDeviceCapabilities. I often find that the Assets catalog is missing suddenly.

Check for it:

	<key>XSAppIconAssets</key>
	<string>Resources/Images.xcassets/AppIcons.appiconset</string>

Certificates

This is the most common issue for me, even with Automatic set. Double and triple-check that your certificate and profile are set correctly.

2019-07-26 12_04_17-Window.png

ipa

After you’ve built your application and are ready to upload the ipa, check to make sure that the ipa file doesn’t have 0 file length images. If it does, just delete the bin and obj folders from the solution and rebuild.

To check for missing files in your ipa, right-click the ipa and unzip it. Then right-click the unzipped file and choose Show Package Contents

bin/obj

Sometimes, though rarely, I have to delete the bin and obj from the solution, then go to the Mac and delete the build folder there too, reboot everything and then rebuild. On the Mac the Build folder is in ~/Library/Caches/Xamarin/mtbs/builds – You can delete anything there.

 

Xamarin styles: Tips on managing XAML files

2019-07-26 10_11_57-artboard_2_1x.png (400×300).pngXamarin offers a wide range of style options to help you make your app consistent, and easy to change. Here are a few tips on how to manage a lot of style settings.

Let’s first create a xaml file with some simple styles. Create a new file in your main project called ThemeFonts.xaml. In this example, I create references for Font Awesome Pro fonts.

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
                    x:Class="App.Themes.ThemeFonts">
 
    <OnPlatform x:Key="FontAwesomeLightFontFamily" x:TypeArguments="x:String"
                Android="fa-light-300.ttf#Font Awesome 5 Pro Light"
                iOS="FontAwesome5Pro-Light"/>
 
    <OnPlatform x:Key="FontAwesomeSolidFontFamily" x:TypeArguments="x:String"
                Android="fa-solid-900.ttf#Font Awesome 5 Pro Solid"
                iOS="FontAwesome5Pro-Solid" />
 
    <Style x:Key="FontAwesomeFontIcon" TargetType="Label">
        <Setter Property="FontFamily" Value="{DynamicResource FontAwesomeLightFontFamily}" />
    </Style>
 
    <Style x:Key="FontAwesomeFontIconSolid" TargetType="Label">
        <Setter Property="FontFamily" Value="{DynamicResource FontAwesomeSolidFontFamily}" />
    </Style>
</ResourceDictionary>

Make sure the Properties are set like this:

2019-07-26 10_02_02-BpApp - Microsoft Visual Studio.png

Now just reference this new file in your App.xaml.

Now your App.xaml is nice a clean. You can add more style xaml pages, each with an area of responsibility, to your app.

<?xml version="1.0" encoding="utf-8"?>
 
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:themes="clr-namespace:App.Themes;assembly=App"
             mc:Ignorable="d"
             x:Class="App.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <themes:ThemeFonts/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

Xamarin: FontAwesome Image

download.pngNow that Xamarin supports a FontImageSource as a source for an Image, it’s time to create a simple custom Image control that uses it.

 

 

Step 1: In your App.xaml add a reference to the FontAwsome font you’d like after you have added it to your iOS and Android project:

<OnPlatform x:Key="FontAwesomeLightFontFamily" x:TypeArguments="x:String"
            Android="fa-light-300.ttf#Font Awesome 5 Pro"
            iOS="FontAwesome5Pro-Light"/>

Step 2: Go to Andre’s site and generate a Font Reference for that font. It will look like this:

static class FontAwesomeLight
{
    public const string GlassMartini = "\uf000";
    public const string Music = "\uf001";
    public const string Search = "\uf002";

Step 3: Create this control that is based on an Image:

public class FontAwesomeImage : Image
{
 
    public string FontImageGlyph
    {
        get { return (stringGetValue(FontImageGlyphProperty); }
        set { SetValue(FontImageGlyphPropertyvalue); }
    }
 
    public static readonly BindableProperty FontImageGlyphProperty =
        BindableProperty.Create(nameof(FontImageGlyph), typeof(string), typeof(FontAwesomeImage),
            propertyChanged: (bindableoldValuenewValue) => ((FontAwesomeImagebindable).Populate());
 
    public double FontImageSize
    {
        get { return (doubleGetValue(FontImageSizeProperty); }
        set { SetValue(FontImageSizePropertyvalue); }
    }
 
    public static readonly BindableProperty FontImageSizeProperty =
        BindableProperty.Create(nameof(FontImageSize), typeof(double), typeof(FontAwesomeImage),
            propertyChanged: (bindableoldValuenewValue) => ((FontAwesomeImagebindable).Populate());
 
 
    public Color FontImageColor
    {
        get { return (ColorGetValue(FontImageColorProperty); }
        set { SetValue(FontImageColorPropertyvalue); }
    }
 
    public static readonly BindableProperty FontImageColorProperty =
        BindableProperty.Create(nameof(FontImageColor), typeof(Color), typeof(FontAwesomeImage),
            propertyChanged: (bindableoldValuenewValue) => ((FontAwesomeImagebindable).Populate());
 
 
    void Populate()
    {
        this.Source = new FontImageSource()
        {
            FontFamily = "FontAwesomeLightFontFamily",
            Color = FontImageColor,
            Glyph = FontImageGlyph,
            Size = FontImageSize
        };
    }
 
 
}

Step 4: To use it, just add this markup to your XAML page.

            <common:FontAwesomeImage 
                FontImageColor="White" 
                FontImageGlyph="{x:Static fonts:FontAwesomeLight.Bookmark}"
                FontImageSize="24">
            </common:FontAwesomeImage>

 

Speeding up Android Emulator using Windows Hyper-V – Tricks to make it work

image01.pngThe Android emulator is so very slow compared to the Apple iOS Simulator. But with recent changes in, the Android emulator is now a bit faster, though not as fast as Apple still.

Here’s all the lessons I learned with getting Android’s Emulator to run as fast as possible.

I assume you have installed Visual Studio 2019

Step 1: Enable Hyper-V  in your Bios

Look for “VT-X” or other “Virtualization” related terms. Often under “Security”:

0D3Zh.png

Step 2: Install Hyper-V on your Windows 10 PC

Search for “Add/Remove Windows Features” in the Start Menu. Add Hyper-V

enable-hyper-v-features.jpg

Step 3: Open the Android Device Manger in Visual Studio and “Factory Reset” your devices

2019-04-09 08_43_08-Android Device Manager.png

GOTCHA! Step 4: Edit your devices and make sure that the hw.gpu.mode is set to host. This will ensure that your PC’s GPU will do the heavy lifting.

2019-04-09 08_43_47-Hyper_81.png

Problems?

Make sure that your machine has Hyper V successfully installed. To do so, open a CMD prompt and type systeminfo. You should see this if all is well:

 

 

 

Debugging Xamarin Forms 3.6 and up

download.jpgWhen your app fails, is it your app, or is there a bug in Xamarin Forms? How to know? In this post I’ll show you how to run Xamarin Forms in debug mode so that exceptions are caught and displayed deep inside Xamarin Forms.

In my previous post I showed you how to debug Xamarin Forms 3.5 and below. 3.6 and above are very different (and easier).

Let’s get to it!

GOTCHA: Make sure you have all the UWP components from the Visual Studio installer or you’ll get errors building. When in doubt, just add it all.

2019-04-02 09_08_19-Window.png

GOTCHA: Delete any Xamarin Forms github repro you have.

Step 1: Create a folder to contain the GitHub source code. I use e:\GitHub

Step 2: Open the GitHub Windows Client and clone  Xamarin Forms Git Hub Repro . Switch to version 3.6

2019-04-02 09_06_16-Window.png

The code is now in e:\GitHub\Xamarin Forms

Step 3: With notepad, create this batch file  e:\GitHub\Build Xamarin NuGet.bat

e:\
cd E:\GitHub\Xamarin.Forms

PowerShell.exe -Command “& ‘Build XF By Batch file.ps1′”
PAUSE

Step 4: With notepad, create this ps1 file e:\GitHub\Build XF By Batch file.ps1

Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force

cd E:\GitHub\Xamarin.Forms
./Build.ps1 -Target NugetPack

Step 5: Double click Build Xamarin NuGet.bat to build

GOTCHA: It can take 6-10 minutes to build. Really. Coffee time….

2019-04-02 09_12_32-Window.png

Now we have the NuGet packages for Xamarin Forms on our machine.

In Visual Studio, add this Nuget repository , then upgrade your projects to the new Xamarin Forms build (Prerelease Nuget)

GOTCHA: Don’t forget to check the “Include Prerelease” checkbox.

2019-04-02 09_15_42-Window.png

GOTCHA: Update project by project, not the whole solution at once. I often get NuGet errors on the solution.

GOTCHA: Delete all bin/obj folder, restart Visual Studio then rebuild.

All done! Now you can debug into Xamarin Forms.