Forms9Patch Simplify image management and text formatting in your PCL and Shared Library Xamarin.Forms mobile apps

Overview

Xamarin Forms is great for developing apps on Android and iOS but it is missing some important features:

  • Scalable images
  • PCL and SharedLibrary, multi-screen / multi-resolution image management
  • HTML formatted text for labels and buttons
  • PCL and SharedLibrary custom font management

Android developers can use NinePatch bitmaps, the drawable directory naming convention, Html.FromHtml, and a bunch of complex file manipulations to address the image issue.  Likewise, iOS developers can use ResizeableImageWithCapInsets, the @2x, @3x, @4x file naming convention, and some 3rd party libraries for this purpose.  Forms 9 Patch enhances Xamarin Forms to make multi-resolution / multi-screen image management, custom fonts, and HTML text formatting easy for PCL and Shared Library apps for iOS and Android.


So, what exactly is Forms9Patch?

Simply stated, Forms9Patch is ten primary and two bonus elements, starting with the three core elements:

  • ImageSource: a free to use derivative of Xamarin.Forms.ImageSource to support multi-device / multi-density image management from Embedded Resources
  • Image: an enhanced implementation of Xamarin.Forms.Image for scalable image, tiling, and tinting support.
  • Label: an enhanced implementation of Xamarin.Forms.Label for easy "code once" access to custom fonts and text formatting via HTML markup tags.

Next, it is derivative of the six Xamarin.Forms.Layout subclasses to enable the use of Forms9Patch.Image as a background image.

  • ContentView
  • Frame
  • AbsoluteLayout
  • Grid
  • RelativeLayout
  • StackLayout

The tenth element is ImageButton.  This element is designed to be a button element with text, companion image, and background image that is dependent upon the button's current state (default, selected, disabled, and disabled+selected).

Bonus: Form9Patch also includes:

  • Further enhancement of its derivatives of Xamarin.Forms.Layout subclasses (except ContentView):
    • OutlineColor: Specify an outline color
    • OutlineWidth: Specify an outline width
    • OutlineRadius: Specify the outline's corner radius
    • HasShadow: that actually works on Android
    • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled)
  • MaterialButton: An enhanced button element, loosely based upon Google's Material design language, that adds the following optional properties:
    • OutlineColor: Specify an outline color
    • OutlineWidth: Specify an outline width
    • OutlineRadius: Specify the outline's corner radius
    • HasShadow: that actually works on Android
    • Image: companion image

More about Forms9Patch.ImageSource

Xamarin Forms provides native iOS and Android multi-screen image management (described here).  This requires storing your iOS images using the native iOS schema and storing your Android images using the Android schema.  In other words, duplicative efforts to get the same results on both Android and iOS.  Forms9Patch.ImageSource extends Xamarin.Forms.ImageSource capabilities to bring multi-screen image management to your Shared Library or PCL Assemblies - so you only have to generate and configure your app's image resources once.  Forms9Patch.ImageSource is a cross-platform implementation to sourcing multi-screen images in Xamarin Forms PCL and Shared Library apps as embedded resources.

More about Forms9Patch.Image

Forms9Patch.Image extends Xamarin.Forms.Image to provide Xamarin Forms with a scalable, tilable, and tintable image element.  Scalable images are images that fill their parent view by stretching in designated regions.  The source image for the Forms9Patch.Image element can be specified either as a Forms9Patch.ImageSource or a Xamarin.Forms.ImageSource.  Supported file formats are NinePatch (.9.png), .png, .jpg, .jpeg, .gif, .bmp, and .bmpf.

Forms9Patch.Image further extends Xamarin.Forms.Image by providing a Tile fill capability when the source image is not in NinePatch format or the CapInsets property is not set.

More about using custom fonts

Xamarin.Forms approach to custom fonts is very native - which doesn't save the developer time nor help with the learning curve.  Form9Patch takes the approach I'm betting Xamarin would have taken if they had more time: everything is done in the PCL or Shared Library project and it's done only once.  To outline the process of setting up a custom font:

  • Copy your custom font to the Resources.Fonts folder of your application's PCL or Shared Library project
  • Set the Build Action of the custom font to Embedded Resource
  • In the Solution view, right click on the font file, select Properties, and note the font's Resource ID
  • When you want to use your custom font, you specify it by setting one the following to the Embedded Resource ID of the font:
    • FontFace property of the Forms9Patch element (will apply the custom font to entire string and yet, can be overridden by any of the below)
    • face attribute of an HTML markup font tag you embed in the string you pass to Form9Patch element's HtmlText property
    • font-family value of style attribute for any valid tag you embed in the string you pass to Form9Patch element's HtmlText property

More about Forms9Patch.Label

Xamarin Forms provides the FormattedString and Span classes as a way to format text used in labels.  However, there are a number of things that could be better:

  • Make it easier to use.  There is a lot of work in setting up the Spans of a FormattedString and any changes to the string means you're likely having to build your spans all over again.
  • Custom Fonts.  Xamarin's approach is the same as native, meaning you have to do everything in the platform projects.  It should be easier and faster if this could all be done in the PCL or Shared Library project.
  • Make it work for Buttons as well.

Forms9Patch address all of these through one new property and one enhanced property for its Label AND its MaterialButton, Segment, ImageButtonState elements:

  • FontFamily: Before, you couldn't access custom fonts on all platforms without a lot of pain.  Now, you just add your custom font to your PCL or Shared Library project as an Embedded Resource and then access it by setting FontFamily to the font's Embedded Resource ID.
  • HtmlText: Give it a string with HTML markup and it automatically does all the work.  Plus, it does things you can't with Xamarin Form's FormattedString, like subscripts, superscripts, underlines, stikethoughs, and custom fonts.

More about Layouts

Forms9Patch.ContentView, Forms9Patch.Frame, Forms9Patch.AbsoluteLayout, Forms9Patch.Grid, Forms9Patch.RelativeLayout, and Forms9Patch.StackLayout extend their Xamarin.Forms counterparts to provide the ability to have a Forms9Patch.Image background.  Additionally, all but Forms9Patch.ContentView further extend by providing the ability to alternatively have a rounded box background using the BackgroundColor, OutlineColor OutlineWidth and OutlineRadius properties and an elliptical background via the IsElliptical property;

More about ImageButton

Forms9Patch.ImageButton was the reason for writing this library in the first place.  Both iOS and Android button elements facilitate state dependent properties but Xamarin.Forms does not.  ImageButton does this through the following properties of type Forms9Patch.ImageButtonState

  • DefaultState
  • SelectedState
  • DisabledState
  • DisabledAndSelectedState

The optional state dependent properties in ImageButtonState are:

  • Image: the button's optional image
  • Text: the button's optional text
  • FontColor: the color of the text
  • FontAttributes: is the text bold or italics?
  • FontSize: the size of the text
  • FontFamily: the text's font
  • BackgroundColor: button's optional background color
  • BackgroundImage: the button's optional background Forms9Patch.Image

Any ImageButton Forms9Patch.ImageButtonState property not set will fall back to the default values - which can be set via the DefaultState property.

Bonus Element #1: MaterialButton

Arguably, from a design perspective, the polar opposite of the ImageButton is the MaterialButton.  While the former is about maximum control, the latter is about convenience - if you're willing to be constrained.  Why is MaterialButton included in Forms9Patch?  Because, much like iOS's UIBarButtonItem, its optional image is automatically tinted to match its text.  This tinting ability is part of Forms9Patch.  Note that you don't need a license to use MaterialButton as long as you do not wish to include the optional images.

To implement the outlining and shadowing of MaterialButton, Xamarin.Forms.Frame had to be improved and brought to the other derivatives of Xamarin.Forms.Layout.  Hence, the Forms9Patch layout elements (except ContentView) not only have the ability to set a background image, they also have the following framing properties:

  • OutlineColor: outline color
  • OutlineWidth: outline width
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: outline's corner radius
  • HasShadow: one more time ... that actually works on Android
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled)

Bonus Element #2: MaterialSegmentedControl

For instances where you want your users to choose from only a handful of options, a segmented button control is very useful.  Android and Xamarin.Forms do not give developers much to work with in this regard.  iOS does but is there are a number of things that could be better (adding images, vertical orientation, etc).  Forms9Patch's MaterialSegmentedControl addresses these gaps.  See its documentation for usage and examples.  Again note that you don't need a license to use MaterialSegmentedControl as long as you do not wish to include the optional images.


Getting Started

If you want to kick the tires before investing the time in learning Forms9Patch, I suggest trying either the free PCL Forms9PatchDemo app or the Shared Library demo app (both hosted on GitHub).  This app demonstrates the features and functions of Forms9Patch and you can experiment with it to get a grasp on how Forms9Patch can work for you.

To add Forms9Patch to your own app just follow these steps:

And now you can use the Forms9Patch.Image and Forms9Patch.ImageSource elements from the Forms9Patch namespace.


Buy

I have a lot of myself in Forms9Patch and would like to make it even better.  To justify the months and months spent, Forms9Patch is licensed per app name.  I.e. if your app has the same name for both iOS and Android, you only need one license key.  If you have different versions of your app (e.g. a free and a pro one) with different names, then you need a separate key for each version.

You can use it for as many developers on as many computers as you like.

The price for one license is $US 37.50 (plus applicable taxes).

The payment process will be handled by MyCommerce.  You will be forwarded to their site when you click the Buy button.

Once you purchased a license, instructions how to configure it will be displayed on the MyCommerce page.  These instructions can also be found in the email they will send you and in the FAQs.

If you forget to configure the license key properly or the key does not match your app name, Forms9Patch.Image will render one scaled image per app session.


Documentation

Images Although not necessary, you may find it helpful to review the Xamarin Developer Guide for Working With Images before starting with Forms9Patch.  If you wish to use Forms9Patch to manage multi-device / multi-resolution EmbeddedResource images be sure to read ResourceID Schema to learn how it works in concert with Forms9Patch.ImageSource.  If you're just interested in using NinePatch files in Xamarin Forms, feel free to jump straight to Forms9Patch.Image, below.  However, if you want to use Forms9Patch in your XAML, please take the time to read the documentation in it's entirity.

Custom Fonts Except academically, I can't recommend any of the Xamarin documentation on this subject.  Start with the Using Custom Fonts section below to learn how to setup and access custom fonts for general use.

HTML Markup It's not practical for Form9Patch to support all HTML tags (that's what WebView is for).  However, the HtmlText property does support a significant subset.  Checkout the HtmlLabel section for a more complete explanation.


ResourceID Schema

Both iOS and Android use unique approaches to naming conventions to facilitate the identification of multi-device / multi-resolution image files.  When used with the constraints of Embedded Resources, a PCL cross platform implementation of the iOS approach has ~3x better performance than a PCL cross platform implementation of the Android approach.  Considering that, the Forms9Patch Embedded Resource was very much modeled after the iOS approach.

The Forms9Patch ResourceID schema is project_assembly_name.project_path.base_image_name[resolution_modifier][device_modifier].filename_extension for each resolution and/or device specific rendition of your image.  Valid values for the optional modifiers are:

Resolution Modifiers

Forms9Patch notes iOS analog Android analog
none fallback image if no other is available none (default) none (default)
@¾x low density screens (~120 dpi) n/a -ldpi
@1x explicit medium density (~160 dpi) none (default) -mdpi
@1½x (~240 dpi) n/a -hdpi
@2x most common (~320) @2x -xhdpi
@3x rare (~480 dpi) @3x -xxhdpi
@4x future proof (~640 dpi) @4x -xxxhdpi

Device Modfiers

Forms9Patch notes iOS analog Android analog
none fallback image if no other is available none (default) none (default)
~phone maps to Xamarin Forms' TargetIdiom.Phone ~iPhone none (default)
~tablet maps to Xamarin Forms' TargetIdiom.Tablet ~iPad sw600dp

Forms9Patch.ImageSource

Forms9Patch.ImageSource extends Xamarin.Forms.ImageSource by adding the FromMultiResource static method. This additional method adds the following functionality to Xamarin.Forms.ImageSource.FromResource:

  • Finds the best fit image among the current EmbeddedResource images. (see ResourceID Schema)
  • Eliminates the need for exmplicitly specifying the image's extension.

This is not without compromises.  Because Xamarin.Forms.ImageSource.FromResource is intended to be multi-platform, it only supports the following image file formats: NinePatch (.9.png), .png, .jpg, .jpeg, .gif, .bmp, and .bmpf.

Note that a Forms9Patch license is not required to use Forms9Patch.ImageSource.

Code Example

The following is a very simple app to demonstrate how Forms9Patch.ImageSource uses Forms9Patch's Embedded Resource ResourceID schema to provide the best Embeded Resource image to Xamarin.Forms.Image or Forms9Patch.Image.

First, we start with a set of multi-device / multi-resolution images:

50x50 100x100 150x150
image.png
[email protected]
[email protected]
image~tablet.png
im[email protected]~tablet.png
[email protected]~tablet.png

Next, we create our app:

  • Create a PCL Xamarin Forms app with the MyDemoApp assembly namespace
  • Create a Resources directory in the app's PCL project
  • Save the above six images in the Resources directory
  • Set the Build Action to EmbeddedResource for those images

Forms9Patch.ImageSource.FromMultiResource will choose among the provided PCL assembly resource renditions and select the rendition that works best with the current device (iOS or Android, tablet or phone, low / medium / high resolution).

XAML Example

In Xamarin Forms, access to embedded resources from XAML requires some addtional work.  Unfortunately, Forms9Patch is no different.  As with Xamarin Forms, you will need (in the same assembly as your embedded resource images) a simple custom XAML markup extension to load images using their ResourceID.


    [ContentPropert ("Source")]
    public class ImageMultiResourceExtension : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue (IServiceProvider serviceProvider)
        {
            if (Source == null)
                return null;

            // Do your translation lookup here, using whatever method you require
            var imageSource  = Forms9Patch.ImageSource.FromMultiResource(Source);

            return imageSource;
        }
    }
                            

Once you have the above, you can load your embedded resource images as shown in the below example.  Be sure to add a namespace for the assembly that contains both your MarkupExtension and your EmbeddedResources (local in the below example).


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:MyXamlDemo;assembly=MyXamlDemo"
    x:Class="MyXamlDemo.MyPage"
    Padding="5, 20, 5, 5">
    <ScrollView>
        <ScrollView.Content>
            <StackLayout>
                <Label Text="Xamarin.Image"/>
                <Image Source="{local:ImageMultiResource Forms9PatchDemo.Resources.image}"/>
            </StackLayout>
        </ScrollView.Content>
    </ScrollView>
</ContentPage>
                            

Forms9Patch.Image

As stated above, Forms9Patch.Image extends Xamarin.Forms.Image to provide Xamarin Forms with a scalable image element and the ability to tile an image within its alloted bounds.  The ImageSource for the Forms9Patch.Image element can be specified either as a Forms9Patch.ImageSource or a Xamarin.Forms.ImageSource.  Supported file formats are NinePatch (.9.png), .png, .jpg, .jpeg, .gif, .bmp, and .bmpf.

iOS's UIKit provides resizableImageWithCapInsets: to make an UIImage a scalable image.  The capInset argument is used to specify the regions (distance inset from the edges) which will not scale (or scale in only one direction) when the image is stretched to fill it's parent view.  Similarly, Android provides NinePatchDrawable to allow apps to display Nine-patch images as scalable drawing elements.  The Nine-patch image format is used to specify the regions that are allowed scale when the image is stretched to fill it's parent view. 

Both approaches have their advantages.  Unlike iOS's resizableImageWithCapInsets:, Android and Forms9Patch's use of the Nine-patch image format allows for unscalable regions to be anywhere in the image (not just at the edges).  And, because the scaled regions are marked within the image file, scaling can be customized to each file.  On the other hand, resizableImageWithCapInsets: provides the ability to define the scaling regions at runtime - which provides some flexibility and convenience.

Seeing the advantages to both approaches, Forms9Patch.Image allows for both.  If a NinePatch image is provided, Forms9Patch.Image uses it's scalable region marking.  If the CapsInset property is set, Forms9Patch.ImageSource will use it to set the unscalable edges - which means CapsInset will always override NinePatch regions.

Xamarin.Forms.Image provides the Aspect property to indicate how an image will fill its bounds.  Forms9Patch.Image does not support the Aspect property.  Rather, it has the Fill property.  The Fill property supports the Aspect property's AspectFill, AspectFit, and Fill values and adds the Tile value for easy management of textures.  See either the PCL demo app or the Shared Library demo app for examples of it in action.

NinePatch images

Let's describe the use of Forms9Patch.Image for NinePatch images through an example.  Say you want to display a pop-up message bubble where the tip is centered.  Because they can have multiple scalable regions, the Nine-patch format works great for this.  Starting with a .png of the bubble, use a NinePatch editor, like Android's Draw 9-patch to mark the horizontal and vertical stretchable regions.

before marking after marking
bubble.png bubble.9.png
200x122 202x124

After adding bubble.9.png to your PCL or Shared Library project assembly as an EmbeddedResource, you can display it using something like the following:


var bubbleImage = new Forms9Patch.Image () 
{
    Source = ImageSource.FromResource("MyDemoApp.Resources.bubble.9.png"),
    HeightRequest = 110,
}
var label = new label () 
{
    Text = "Forms9Path NinePatch Image",
    HorizontalOptions = LayoutOptions.Center,
}
                            

Resulting in:

Using the CapsInset Property

The CapInset property is used to specify the regions (distance inset from the edges) which will not scale when the image is stretched to fill it's parent view.  For example, let's make the following image a banner by scaling it horizontally.

  • ResourceID: MyDemoApp.Resources.Images.redribbon.png
  • Image Size: 308x80

Load it using Xamarin.Forms.ImageSource as the source to Forms9Patch.Image and then, set the CapInsets properties:


var label1 = new Label () 
{
    Text = "Xamarin Image",
}
var image1 = new Xamarin.Forms.Image () 
{
    Source = ImageSource.FromResource("MyDemoApp.Resources.Images.redribbon.png"),
}
var label1 = new Label () 
{
    Text = "Forms9Patch Image w/ CapInsets",
}
var image2 = new Forms9Patch.Image () 
{
    Source = ImageSource.FromResource("MyDemoApp.Resources.Images.redribbon.png"),
    CapInsets = new Thickness(23, 0, 110, 0),
}
                            

XAML Example

To use Forms9Patch.Image in your XAML, you will have to do add the Forms9Patch namespace (from the Forms9Patch assembly) and then use Forms9Patch.Image when desired.  Also note that, if you want to use Embedded Resource images, you will need to add an XAML markup extension to the assembly that contains those images (see above).  For example:


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:MyXamlDemo;assembly=MyXamlDemo"
    xmlns:Forms9Patch="clr-namespace:Forms9Patch;assembly=Forms9Patch"
    x:Class="MyXamlDemo.MyPage"
    Padding="5, 20, 5, 5">
    <ScrollView>
        <ScrollView.Content>
            <StackLayout>
                <Label Text="Xamarin.Forms.Image"/>
                <Image Source="{local:ImageMultiResource Forms9PatchDemo.Resources.Images.redribbon}"/>
                <Label Text="Forms9Patch.Image w/ CapInsets"/>
                <Forms9Patch:Image 
                    Source="{local:ImageMultiResource Forms9PatchDemo.Resources.Images.redribbon}" 
                    CapInsets="23,-1,111,-1"/>
            </StackLayout>
        </ScrollView.Content>
    </ScrollView>
</ContentPage>                          
                            

Forms9Patch.Label

The Label element works a lot like Xamarin Form's Label element but with the following changes in properties:

  • Embedded Resource Custom Fonts: The FontFamily property has been enhanced to support Embedded Resource custom fonts.  See the Using Custom Fonts section below for more information.
  • HTML Markup in-line formatting: The HtmlText property has been added to support formatting via subset of HTML tags.  See the Using the HtmlLabel property section below for more information.
  • Autofitting: Forms9Patch's autofitting is meant to address the different ways a developer might want to autofit.  Which, quite frankly, is something that I've wanted in iOS and Android for a long, long time - and now, Xamarin Forms.  See the Label Autofitting section below for more details on using this feature.  Also, the readonly ActualFontSize property holds the font size that resulted from autofitting.
  • NOTE: The FormattedText property is not available because it was made redundant by HtmlText.  I have always found FormattedText to be a lot of work to use and a lot of work to support.  Good riddance.

Forms9Patch.ColorGradientBox

Here's another simple element that is handy when you need it - Forms9Patch.ColorGradientBox. It is a box, filled with the gradient between two colors in either the horizontal or vertical direction. Properties:

  • StartColor: The color a the starting side of the box.
  • EndColor: The color at the opposite side of the starting side.
  • Orientation: StackOrientation.Horizontal or StackOrientation.Vertical

Forms9Patch.ContentView

Forms9Patch.ContentView extends Xamarin.Forms.ContentView to provide Xamarin Forms with the ability to set a Forms9Patch.Image as the ContentView's background.  This is accomplished using the BackgroundImage property.

Code Example


new StackLayout 
{
    Children = 
    {
        new Forms9Patch.ContentView 
        {
            BackgroundImage = new Forms9Patch.Image 
            {
                Source = Forms9Patch.ImageSource.FromMultiResource ("Forms9PatchDemo.Resources.redribbon"),
                Fill = Forms9Patch.Fill.Tile,
                CapInsets = new Thickness(30,-1,160,-1),
            },
            Content = new Xamarin.Forms.Label 
            {
				Text = "ContentView scalable (CapInsets)",
				TextColor = Color.White,
				FontAttributes = FontAttributes.Bold,
				FontSize = 14,
				HorizontalOptions = LayoutOptions.Center,
				VerticalOptions = LayoutOptions.Center,
            },
            Padding = new Thickness(30,30,110,20),
            HeightRequest = 80,
        },
    },
}
                            

XAML Example

As discussed earlier, using Embedded Resource images in XAML requires the use of a XAML markup extension in your view's namespace. Assuming such an extension has been setup (as shown above), the following demonstrates how to use Forms9Patch.ContentView in XAML.


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:MyXamlDemo;assembly=MyXamlDemo"
    xmlns:Forms9Patch="clr-namespace:Forms9Patch;assembly=Forms9Patch"
    x:Class="MyXamlDemo.MyPage"
    Padding="5, 20, 5, 5">
    <StackLayout>
        <f9p:ContentView Padding="30,30,110,20" HeightRequest="80"/>
            <f9p:ContentView.BackgroundImage>
                <f9p:Image 
                    Source="{local:ImageMultiResource Forms9PatchDemo.Resources.redribbon}"
                    CapInsets="23,-1,111,-1" 
                    />
            </f9p:ContentView.BackgroundImage>
            <Label Text="Forms9Patch.Image w/ CapInsets"
                TextColor="White" 
                HorizontalOptions="Center" 
                VerticalOptions="Center" 
                FontSize="14"
                />
        </f9p:ContentView>
    </StackLayout>
</ContentPage>
                            

Forms9Patch Layouts:

AbsoluteLayout, Frame, Grid, RelativeLayout and StackLayout

Just as Xamarin.Forms.Frame extends Xamarin.Forms.ContentView by adding the OutlineColor and HasShadow properties, Forms9Patch.AbsoluteLayout, Forms9Patch.Frame, Forms9Patch.Grid, Forms9Patch.RelativeLayout and Forms9Patch.Stacklayout extend Forms9Patch.ContentView with those two properties and add the OutlineWidth, IsElliptical, OutlineRadius, and ShadowInverted properties.  Note that if the BackgroundImage is set and and said image is found and rendered, the OutlineColor, OutlineWidth, IsElliptical, OutlineRadius, and HasShadow properties will be ignored.  See the ContentView Code Example and ContentView XAML Example for how to set the BackgroundImage property.

Additionally, the Forms9Patch layouts have the IgnoreChildren property as a way to improve app responsiveness.  When a child element is updated, it kicks off a measurement and layout cycle that can propogate up through the view hierarchy - potentially consuming a lot of CPU.  I'm looking at you, Xamarin.Forms.Android!  Sometimes this is necessary in order to make room for or reclaim room from the updated child element.  However, there a lot of instances where the updated child will never have an impact upon the rest of the view hierarchy - other than slowing everything down while Xamarin Forms goes through the measure-layout cycle.  For example, if you have a Grid with fixed (GridUnitType.Absolute) or proportional (GridUnitType.Star) sized rows and columns then any change to a child will not change the Grid's layout.  So, to keep an update of a child from propogating up the view hierarchy, set the IgnoreChildren property to true.  Please note that this is a "running with sissors" feature that should be used carefully.

Note that a Forms9Patch license is not required to use these layout elements.

Code example


var frame = new Forms9Patch.Frame {
    Content = new Xamarin.Forms.Label {
        Text = "Frame OutlineRadius & Shadow",
        TextColor = Color.Black,
        FontSize = 12,
    },
    Padding = new Thickness(10),
    Background = Color.FromHex( 12),
    OutlineRadius = 2,
    HasShadow = true,
}                            
                            
Apple Android

XAML Example


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:MyXamlDemo;assembly=MyXamlDemo"
    xmlns:Forms9Patch="clr-namespace:Forms9Patch;assembly=Forms9Patch"
    x:Class="MyXamlDemo.MyPage"
    Padding="5, 20, 5, 5">
    <StackLayout>
        <f9p:Frame 
            Padding="20" 
            OutlineColor="Blue"
            OutlineWidth="3"
            OutlineRadius="10"
            BackgroundColor="Gray"
            />
            <Label Text="Forms9Patch.Frame w/ OutlineWidth+OutlineRadius"
                TextColor="White" 
                HorizontalOptions="Center" 
                VerticalOptions="Center" 
                FontSize="14"
                />
        </f9p:Frame>
    </StackLayout>
</ContentPage>
                            

Buttons

Forms9Patch was originally written for the purpose of making it easy to have highly stylized buttons in PCL Xamarin.Forms apps.  It has three button elements to serve this purpose: ImageButton, MaterialButton, and MaterialSegmentedControl.  Additionally: ImageButtonState is used to specify the appearance of an ImageButton when it is selected and/or disabled; and Segment is used to specify the appearance and behavior of a MaterialSegmentedControl.

As of Forms9Patch 0.10.1.0, the HapticEffect and HapticMode properties have been added to the Forms9Patch buttons to give them ability to have haptic feedback.  See Haptics Service for more information on HapticEffect and HapticMode.


ImageButton

ImageButton was designed in order to have complete control over a button's appearance.  To make this happen, the Forms9Patch.ImageButtonState class is used to specify the button's appearance in the selected and/or disabled states.  For each of these states, an instance of ImageButtonState can be given to ImageButton with or without its properties set.  Unset properties fall back to the defaults values as specified with the DefaultState property.

Properties
  • IsSelected: Is the button in the selected state?  Note: StickyBehvior property must be true for this to change in response to the button being tapped.
  • IsEnabled: Is the button enabled?
  • ToggleBehavior: Set to true if you want the button to stay in a selected state when pressed once and return to the unselected state when pressed a second time.
  • HorizontalTextAlignment:: Do you want the text and image biased to the start (left), center, or end (right) of the button?
  • VerticalTextAlignment:: Do you want the text and image biased to the start (top), center, or end (bottom) of the button?
  • Orientation: Do you want the text and image placed image on top of text (vertical) or image to the left of text (horizontal)?
  • Spacing: The gap between the icon and the text.
  • HasTightSpacing: Is the icon biased towards the outside edge of the button (false) or towards the text (true).
  • DefaultState: Specifies the appearance of the button when in an unselected and enabled state.  ImageButton will use the DefaultState's properties for other state's properties when they have not been specified.
  • PressingState: Specifies the appearance of the button when it is actively being pressed.
  • SelectedState: Specifies the appearance of the button when it is in the selected state.
  • DisabledState: Specifies the appearance of the button when it is in the disabled state.
  • DisabledAndSelectedState: Specifies the appearance of the button when it is in the disabled and selected state.
  • TrailingImage: Set to true to have the button's image after (instead of before) the button's label.
  • HapticEffect: What kind of haptic effect will then button have, when appropriate as indicated by HapticMode.  See Haptic Service for more information on HapticEffect and HapticMode.
  • HapticMode: Under what conditions should this button give haptic feedback?  See Haptic Service for more information on HapticEffect and HapticMode.
Events:
  • Command: The ICommand to execute when the button is pressed.
  • CommandParameterThe parameter used in ICommand calls.
  • Tapped: EventHandler be called anytime a button is tapped.
  • Selected: EventHandler be called when a button transitions from unselected to selected.
  • LongPressing: EventHandler be called when a button is being held down long enough to be considered a long press.
  • LongPressed: EventHandler be called when a button's long press has ended.
Methods:
  • void Tap(): programmically tap the button.
Alignment Properties in action:
Code example

var button = new Forms9Patch.ImageButton {
    DefaultState = new Forms9Patch.ImageButtonState {
        BackgroundImage = new Forms9Patch.Image {
            Source = Forms9Patch.ImageSource.FromMultiResource("MyDemoApp.Resources.button"),
        },
        Image = new Forms9Patch.Image {
            Source = Xamarin.Forms.ImageSource.FromFile("five.png"),
        },
        FontColor = Color.White,
        Text = "Sticky w/ SelectedState",
    },
    SelectedState = new Forms9Patch.ImageButtonState {
        BackgroundImage = new Forms9Patch.Image {
            Source = Forms9Patch.ImageSource.FromMultiResource("MyDemoApp.Resources.image"),
        },
        Image = new Forms9Patch.Image {
            Source = Xamarin.Forms.ImageSource.FromFile("five.png"),
        },
        FontColor = Color.Red,
        Text = "Selected",
    },
    ToggleBehavior = true,
    HeightRequest = 50,
    HorizontalTextAlignment = TextAlignment.Start,
}                        
                            
Apple Android
default
selected

ImageButtonState

ImageButtonState is used to describe the appearance of an ImageButton for a given state.  If an ImageButtonState property is unset, ImageButton will use the value for that property as set in ImageButton's DefaultState property.  If the value hasn't been set in the DefaultState property, it will use the default value for that ImageButtonState property.

Properties
  • Image: the button's optional image.
  • Text: the button's optional text.
  • HtmlText: text formatted via subset of HTML tags.  See the Using the HtmlLabel property section below for more information.
  • FontFamily: the text's font.  Now supports Embedded Resource custom fonts.  See the Using Custom Fonts section below for more information.
  • FontSize: the text size.
  • FontAttributes: is the text bold or italics?
  • FontColor: the color of the text when enabled.  Disabled buttons use a shade of grey determined by the DarkTheme property.
  • BackgroundImage: button's background image (as a Forms9Patch.Image).
  • BackgroundColor: button's optional background color.  This will allow BackgroundImage to have transparent pixels and set the color of them using BackgroundColor.

Forms9Patch.MaterialButton

Forms9Patch.MateriaButton is a convenience class meant for making buttons that have a look loosely based on Google's Material design.  For example, MateriaButton automates creating icon buttons by tinting icon images to match the button's text and correctly aligning the image and text, if present.  MateriaButton is not is highly customizable - that is the role of Forms9Patch.ImageButton.

Properties:
  • ImageSource: source for the button's optional image.  It will be tinted to FontColor when enabled and grey when disabled. 
  • IconText: text alternative to the ImageSource property. Used to specify HTML formatted text for button's icon. Great when used with Google's Material Font.
  • Text: the button's optional text.
  • HtmlText: text formatted via subset of HTML tags.  See the Using the HtmlLabel property section below for more information.
  • FontFamily: the text's font.  Now supports Embedded Resource custom fonts.  See the Using Custom Fonts section below for more information.
  • FontSize: the text size.
  • FontAttributes: is the text bold or italics?
  • FontColor: the optional color of the text when enabled.  Disabled buttons use a shade of grey determined by the DarkTheme property.
  • SelectedFontColor: the optional color of the text when selected.  Disabled buttons use interpolate this color with the shade of grey determined by the DarkTheme property.
  • BackgroundColor: button's optional background color.  The color of selected, disabled and disabled+selected buttons will be based upon the value of the DarkTheme property.
  • SelectedBackgroundColor: optional setting that sets the button's background color when selected, overriding the DarkTheme property behaviour.  The disabled state will use a version of this color that has been interpolated to a grey, based upon the value of the DarkTheme property.
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • DarkTheme: Set to true if your BackgroundColor is a dark and the FontColor is light.  This controls the color of the button's background, text and image in the selected, disabled, and disabled+selected states.
  • IsSelected: Is the button in the selected state?  Note: StickyBehvior property must be true for this to change in response to the button being tapped.
  • IsEnabled: Is the button enabled?
  • ToggleBehavior: Set to true if you want the button to stay in a selected state when pressed once and return to the unselected state when pressed a second time.
  • HorizontalTextAlignment:: Do you want the text and image biased to the start (left), center, or end (right) of the button?
  • VerticalTextAlignment:: Do you want the text and image biased to the start (top), center, or end (bottom) of the button?
  • Orientation: Do you want the text and image placed image on top of text (vertical) or image to the left of text (horizontal)?
  • Spacing: The gap between the icon and the text.
  • HasTightSpacing: Is the icon biased towards the outside edge of the button (false) or towards the text (true).
  • TrailingImage: Set to true to have the button's image after (instead of before) the button's label.
Events:
  • Command: The ICommand to execute when the button is pressed.
  • CommandParameterThe parameter used in ICommand calls.
  • Tapped: EventHandler be called anytime a button is tapped.
  • Selected: EventHandler be called when a button transitions from unselected to selected.
  • LongPressing: EventHandler be called when a button is being held down long enough to be considered a long press.
  • LongPressed: EventHandler be called when a button's long press has ended.
Inherited Properties:

From Forms9Patch.Frame

  • ImageSource: Using this will make BackgroundColor and OutlineColor settings not applicable.
  • ShadowInverted: Overwritten by MaterialButton's use of HasShadow and ToggleBehavior properties.
  • Padding: Sets the padding between the buttons borders and the combined borders of the button's image and text.
Methods:
  • void Tap(): programmically tap the button.
Alignment Properties in action:
Code example

// Image example
var lightButton = new Forms9Patch.MaterialButton {
    Text = "sticky",
    ToggleBehavior = true,
    BackgroundColor = Color.FromHex("#EOEOEO"),
    HasShadow = true,
    Image =  new Forms9Patch.Image {
        Source = Forms9Patch.ImageSource.FromMultiResource("DemoApp.Resources.info"),
    }
};


// IconText example
var darkButton = new Forms9Patch.MaterialButton {
    Text = "sticky",
    IconText = "<font face=\"TestProject.Resources.Fonts.MaterialIcons-Regular.ttf\"></font>";
    ToggleBehavior = true,
    BackgroundColor = Color.FromHex("#1194F6"),
    DarkTheme = true,
    HasShadow = true,
};
                           
                                

In the samples below: (1) the ToggleBehavior buttons are shown in the selected state; (2) HasShadow buttons with default BackgroundColor are not shown because they render the same as !HasShadow.

Apple Android
HasShadow
!HasShadow

Important note: One more time, the HasShadow property has not effect when BackgroundColor has not been set.


Forms9Patch.MaterialSegmentedControl

One place that Android and Xamarin Forms falls short: neither has a segmented control element.  And, after using iOS's since the early days, I have always felt it could be better.  Forms9Path.MaterialSegmentedControl is the segmented button control I've always wanted.  In addition to specifying it behavior and appearance using the below properties, each segment of a MaterialSegmentedControl is specified with the Forms9Patch.Segment element (see the next section).

Properties:
  • Segments: An ObservableCollection that you put Segments.
  • HasShadow: Does the control have a shadow (only applied if BackgroundColor is not transparent.
  • Padding: For all segments, sets the padding between the segment's borders and the combined borders of the segment's image and text.
  • FontFamily: For all segments, sets the text's font.  Now supports Embedded Resource custom fonts.  See the Using Custom Fonts section below for more information.
  • FontSize: For all segments, sets the text size.
  • FontAttributes: For all segments, sets the text bold or italics.
  • FontColor: For all segments, sets the enabled font color (used for text and images).  Disabled segments use a shade of grey determined by the DarkTheme property.
  • SelectedFontColor: the optional color of the text when selected.  Disabled buttons use interpolate this color with the shade of grey determined by the DarkTheme property.
  • BackgroundColor: For all segments, sets segment's optional background color.  The color of selected, disabled and disabled+selected segments will be based upon the value of the DarkTheme property.
  • SelectedBackgroundColor: optional setting that sets the button's background color when selected, overriding the DarkTheme property behaviour.  The disabled state will use a version of this color that has been interpolated to a grey, based upon the value of the DarkTheme property.
  • OutlineColor: For all segments, sets segment's optional outline color.
  • OutlineWidth: For all segments, sets segment's width of the optional outline.
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: For all segments, sets segment's outline's corner radius.
  • DarkTheme: For all segments, sets how the background, text and image colors will be modified when the segment is in the selected, disabled, and disabled+selected states.  Set to true if your BackgroundColor is a dark and the FontColor is light. 
  • SelectedSegments: A List of the segments currently in the selected state.  Note: StickyBehvior property must be either GroupToggleBehavior.Radio or GroupToggleBehavior.MultiSelect for this to change in response to a segment being tapped.
  • SelectedIndexes: A List of the indexes of the segments in the selected state.  See above note.
  • ToggleBehavior: There are three possible values:
    • GroupToggleBehavior.None: Segments won't stick in the selected state.
    • GroupToggleBehavior.Radio: Only one segment at a time will stick in the selected state and can be unselected only by tapping another segment.
    • GroupToggleBehavior.MultiSelect: Any segment can stick in the selected state and can be unselected only by tapping it a second time.
  • SeparatorWidth: The width of the separator line between each segment.  Note: This is a way to control the appearance of the separator independent of the outline.
  • TrailingImage: Set to true to have each button's image after (instead of before) the button's label.
  • HorizontalTextAlignment:: Do you want the text and image biased to the start (left), center, or end (right) of the button?
  • VerticalTextAlignment:: Do you want the text and image biased to the start (top), center, or end (bottom) of the button?
  • IntraSegmentOrientation: Do you want the text and image placed image on top of text (vertical) or image to the left of text (horizontal)?
  • IntraSegmentSpacing: The gap (in pixels) between the icon and the text.
  • HasTightSpacing: Are the segment icons biased towards the outside edge of the segments (false) or towards the text (true).
Inherited Properties:
  • Orientation: Do you want the segments placed horizontally or vertically?
  • Spacing: Ugh.  I forgot to hide this one.  I don't have a clue what bad things will happen if you use it.  Expect it to be hidden or repurposed in a future release.
Events:
  • SegmentTapped: Returns the index and Segment element of any enabled segment when it is tapped.
  • SegmentSelected: Returns the index and Segment element of any segment that transitions from unselected to selected.
Methods:
  • void SelectIndex(int index): Programmically set an index.
  • void TapIndex(int index): Programmically tap the segment at index.
Alignment Properties in action:
Code example

Although MaterialSegmentedControl defaults to a Material Design appearance, the below examples illustrate how to give it an iOS7+ appearance.


    ...
 
var segCtrl1 = new Forms9Patch.MaterialSegmentedControl {
    GroupToggleBehavior = Forms9Patch.GroupToggleBehvior.None,
    BackgroundColor = Color.White,
    FontSize = 16,
    FontColor = Color.FromHex("#0076FF"),
    Orientation = Forms9Patch.StackOrientation.Vertical,
    OutlineColor = Color.FromHex("#CCC"),
    OutlineWidth = 0,
    SeparatorWidth = 1,
    OutlineRadius = 6,
    Padding = new Thickness("5"),
    Segments = {
        new Segment { Text = "Pause 5"},
        new Segment { Text = "Pause 10"},
        new Segment { Text = "Pause 15"},
        new Segment { Text = "Cancel", FontColor=Color.Red,},
        new Segment { Text = "Launch", FontAttributes="Bold",},
    },
};

    ...

var segCtrl1 = new Forms9Patch.MaterialSegmentedControl {
    GroupToggleBehavior = Forms9Patch.GroupToggleBehavior.None,
    BackgroundColor = Color.White,
    FontSize = 16,
    FontColor = Color.FromHex("#0076FF"),
    OutlineColor = Color.FromHex("#CCC"),
    OutlineWidth = 0,
    SeparatorWidth = 1,
    OutlineRadius = 6,
    Padding = new Thickness("0,5,0,0"),
    Segments = {
        new Segment { 
            Text = "A",
            ImageSource = Forms9Patch.ImageSource.FromMultiResource("Resources.ArrrowR"),
        },
        new Segment { 
            Text = "B",
            IconText = "<font face=\"TestProject.Resources.Fonts.MaterialIcons-Regular.ttf\"></font>",
        },
        new Segment { Text = "PIZZA"},
    },
};                            
                                
XAML example

Again, the below examples illustrate how to give it an iOS7+ appearance.


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:MyXamlDemo;assembly=MyXamlDemo"
    xmlns:Forms9Patch="clr-namespace:Forms9Patch;assembly=Forms9Patch"
    x:Class="MyXamlDemo.MyPage"
    BackgroundColor="Gray">
    Padding="40">
    <StackLayout>
        <f9p:MaterialSegmentedControl 
            BackgroundColor="White"
            FontSize="16" 
            FontColor="#0076FF"
            Orientation="Vertical"
            OutlineColor="#CCC"
            OutlineWidth="0"
            SeparatorWidth="1"
            OutlineRadius="6"
            Padding="20" 
            />
            <f9p:Segment Text="Pause 5"/>
            <f9p:Segment Text="Pause 10"/>
            <f9p:Segment Text="Pause 15"/>
            <f9p:Segment Text="Cancel" FontColor="Red"/>
            <f9p:Segment Text="Launch" FontAttributes="Bold"/>                
        </f9p:MaterialSegmentedControl>
        <f9p:MaterialSegmentedControl 
            BackgroundColor="White"
            FontSize="16" 
            FontColor="#0076FF"
            OutlineColor="#CCC"
            OutlineWidth="0"
            SeparatorWidth="1"
            OutlineRadius="6"
            Padding="0,5,0,0" 
            />
            <f9p:Segment 
                Text="A"
                ImageSource="{local:ImageMultiResource Forms9PatchDemo.Resources.ArrowR}"
                Orientation="Vertical"
            />
            <f9p:Segment Text="B" Orientation="Vertical">
                <f9p:Segment.IconText>
                    &lt;font face="TestProject.Resources.Fonts.MaterialIcons-Regular.ttf"&gt;&lt;/font&gt;
                </f9p:Segment.IconText>
            </f9p:Segment>
            <f9p:Segment Text="PIZZA"/>
        </f9p:MaterialSegmentedControl>
    </StackLayout>
</ContentPage>                            
                                
Apple Android

Forms9Patch.Segment

The Segment element is used primarily to populate the MaterialSegmentedController and secondarily, to customize individual segments beyond the default values provided by the parent MaterialSegmentedController.

Properties

  • ImageSource: source for the segment's optional image.  It will be tinted to FontColor when enabled and grey when disabled. 
  • IconText: text alternative to the ImageSource property. Used to specify HTML formatted text for button's icon. Great when used with Google's Material Font.
  • Text: the segment's optional text.
  • HtmlText: text formatted via subset of HTML tags.  See the Using the HtmlLabel property section below for more information.
  • FontColor: the color of the text when enabled.  Disabled segmentS use a shade of grey determined by the DarkTheme property.
  • FontAttributes: is the text bold or italics?
  • IsSelected: Is the segment in the selected state?  Note: Segment's parent's StickyBehvior property must be Radio or MultiSelect for this to change in response to the segment being tapped.
  • IsEnabled: Is the segment enabled?
  • Orientation: Do you want the text and image placed image on top of text (vertical) or image to the left of text (horizontal)?
Events
  • Command: The ICommand to execute when the segment is pressed.  NOTE: If the segment's parent's StickyBehvior property is set to None, then this will fire anytime the segment is tapped.  Otherwise, it will fire only when the segment transitions from unselected to selected.
  • CommandParameterThe parameter used in ICommand calls.
  • Tapped: EventHandler be called anytime a segment is tapped.
  • Selected: EventHandler be called when a segment transitions from unselected to selected.
  • LongPressing: EventHandler be called when a segment is being held down long enough to be considered a long press.
  • LongPressed: EventHandler be called when a segment's long press has ended.


Popups!

Yet another thing missing from the Xamarin Forms framework is comprehensive set of popup views.  Forms9Patch has a six (ModalPopup, BubblePopup, Toast, TargetedToast, PermissionPopup and ActivityInditorPopup) popups to simplify the most common tasks.  However, this comes at a price!  In previous releases of Forms9Patch, I tried to implement the popups in a way that would require the least amount of prep work on your part.  Unfortunately, this meant a lot very ugly code, performance penalties, and (to add insult to injury) the Android implementation of version 2.3 of Xamarin.Forms broke it for the Xamarin.Forms.MasterDetailPage

So, this part is IMPORTANT!  Forms9Patch popups only work on the Forms9Patch.RootPage.  Wait, DON'T PANIC!  Forms9Patch.RootPage is just a wrapper for your app's pages.  In other words, if you want to use popups in Forms9Patch 0.10 and later, you'll have to wrap your app's MainPage in an instance of Forms9Patch.RootPage. For example, if your app's instance (without Forms9Patch or before version 0.10) of App is as follows (pay attention to line 25):


using Xamarin.Forms;

namespace ExampleApp
{
	public class App : Application
	{
		public App()
		{
			// The root page of your application
			var content = new ContentPage
			{
				Title = "ExampleApp",
				Content = new StackLayout
				{
					VerticalOptions = LayoutOptions.Center,
					Children = {
						new Label {
							HorizontalTextAlignment = TextAlignment.Center,
							Text = "Welcome to Xamarin Forms!"
						}
					}
				}
			};

			MainPage = new NavigationPage(content);  // before adding Forms9Patch popup support
		}
	}
}                        
                        

You are going to want to change line 25 to:


using Xamarin.Forms;

namespace ExampleApp
{
	public class App : Application
	{
		public App()
		{
			// The root page of your application
			var content = new ContentPage
			{
				Title = "ExampleApp",
				Content = new StackLayout
				{
					VerticalOptions = LayoutOptions.Center,
					Children = {
						new Label {
							HorizontalTextAlignment = TextAlignment.Center,
							Text = "Welcome to Xamarin Forms!"
						}
					}
				}
			};

			MainPage = Forms9Patch.RootPage.Create(new NavigationPage(content)); // after adding Forms9Patch popup support
		}
	}
}
                        
                        

Forms9Patch.ModalPopup

The most needed missing component: a simple content container popup that centers its contents on the main page.  Since you may want a popup container with a NinePatch background image, Forms9Patch provides the ModalPopup element for this purpose.  Once you have initialized a Forms9Patch popup view, set the IsVisible property to true to present it.

Properties
  • Content: The element that will be the content for the popview.  Layouts and Views are fair game.
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • BackgroundImage: The Forms9Patch.Image displayed as the popup's background.
  • BackgroundColor: popup's optional background color. 
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • CancelOnBackgroundTouch: Controls is the popup is cancelled if the background is touched.  Default value is true.
  • Retain: a boolean (default: false) used to indicate if the popup and its contents should be removed from the view hierarchy as soon as the view is hidden.  Why would I bother to have this? ANDROID! If you have a heavy layout that will be shown multiple times, you may not want to re-render each time it is made visible. Seeing Retain=true will keep your popup and its content in the view hierarchy so it won't have to be re-rendered the next time you want to present it.
Methods
  • Cancel: Programically cancels the Popup.
Events
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Forms9Patch.BubblePopup

The popup that is missing from both Xamarin Forms framework and Android is a pointer bubble popup - a popup that points to another element.  Given a Target element, some Content to display, and an allowed PointerDirection, Forms9Patch.BubblePopup will best fit a popup bubble pointing the the Target.  Note that, unlike the ModalPopup element, BubblePopup does not support background images.  If you do not specify the Target, it will present itself as a ModalPopup.  As with ModalPopup, once you have initialized a BubblePopup you will need to set the IsVisible property to true to present it.

Properties
  • Content: The VisualElement that will be the content for the popview.  Layouts and Views are fair game.
  • Target: The VisualElement to which the bubble popup will point.
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • BackgroundColor: popup's optional background color.
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • PointerLength: how long is the pointer.
  • PointerTipRadius: what is the radius of the pointer's tip?
  • PointerDirection: what directions is the bubble popup allow to point?  Type:PointerDirection
  • PointerCornerRadius: what is the radius of the notch between the bubble's body and the pointer?
  • CancelOnBackgroundTouch: Controls is the popup is cancelled if the background is touched.  Default value is true.
  • Retain: a boolean (default: false) used to indicate if the popup and its contents should be removed from the view hierarchy as soon as the view is hidden.  Why would I bother to have this? ANDROID! If you have a heavy layout that will be shown multiple times, you may not want to re-render each time it is made visible. Seeing Retain=true will keep your popup and its content in the view hierarchy so it won't have to be re-rendered the next time you want to present it.
Methods
  • Cancel: Programically cancels the Popup.
Events
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Forms9Patch.Toast

Sometimes you simply need to put a message up on the screen.  Given some HTML formatted text and an HTML formatted title Toast will display them in a popup with an (optional but enabled by default) "OK" button.  Toast is inherited from the ModalPopup element so it does support background images.  Unlike ModalPopup, Toast has the Create(string title, string text) static method that will generate and present the toast.  You can still manually construct and present a Toast by using its constructor and setting its IsVisible property to true.

Properties
  • Title: The title for the Toast.  See HTML Markup for supported markup.
  • Text: The text for the Toast.  See HTML Markup for supported markup.
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • BackgroundImage: The Forms9Patch.Image displayed as the popup's background.
  • BackgroundColor: popup's optional background color. 
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • CancelOnBackgroundTouch: Controls is the popup is cancelled if the background is touched.  Default value is true.  Warning: You really don't want this to be set to false when OkText is set to null, right?
  • OkButtonColor: Background color for OK button.
  • OkTextColor: Text color for OK button.
  • OKText: Text for OK button.  Set to null to remove the OK button from the popup.  As noted above, you don't want this set to null when CancelOnBackgroundTouch is set to false.
Methods
  • void Cancel(): Programically cancels the Popup.
  • static Toast Create(string title, string text): instantiates and presents a Toast.
Events
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Forms9Patch.TargetedToast

Just as Toast is a convenience version of ModalPopup, TargetedToast is a convenience version of BubblePopup  Given a Target element, a Title, some Textto display, and an allowed PointerDirection, Forms9Patch.TargetedToast will best fit a popup bubble pointing the the Target.  Like BubblePopup element, BubblePopup does not support background images.  If you do not specify the Target, it will present itself as a Toast.  As with Toast, you can use the Create static method to instantiate and present a TargetedToast.

Properties
  • Title: The title for the Toast.  See HTML Markup for supported markup.
  • Text: The text for the Toast.  See HTML Markup for supported markup.
  • Target: The VisualElement to which the bubble popup will point.
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • BackgroundColor: popup's optional background color.
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • PointerLength: how long is the pointer.
  • PointerTipRadius: what is the radius of the pointer's tip?
  • PointerDirection: what directions is the bubble popup allow to point?  Type:PointerDirection
  • PointerCornerRadius: what is the radius of the notch between the bubble's body and the pointer?
  • CancelOnBackgroundTouch: Controls is the popup is cancelled if the background is touched.  Default value is true.  Warning: You really don't want this to be set to false when OkText is set to null, right?
  • OkButtonColor: Background color for OK button.
  • OkTextColor: Text color for OK button.
  • OKText: Text for OK button.  Set to null to remove the OK button from the popup.  As noted above, you don't want this set to null when CancelOnBackgroundTouch is set to false.
Methods
  • void Cancel(): Programically cancels the Popup.
  • static TargetedToast Create(VisualElement target, string title, string text): instantiates and presents a TargetedToast.
Events
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Forms9Patch.PermissionPopup

Sometimes you simply need to ask a yes/no question.  Given some HTML formatted text and an HTML formatted title PermissionPopup will display them in a popup with "OK" and "Cancel" buttons.  PermissionPopup is inherited from the ModalPopup element so it does support background images.  Unlike ModalPopup, PermissionPopup has the Create(string title, string text) static method that will generate and present the toast.  You can still manually construct and present a PermissionPopup by using its constructor and setting its IsVisible property to true.  Unlike Toast, the OK and Cancel buttons cannot be removed from the layout by setting their text to null.

Properties
  • Title: The title for the Toast.  See HTML Markup for supported markup.
  • Text: The text for the Toast.  See HTML Markup for supported markup.
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • BackgroundImage: The Forms9Patch.Image displayed as the popup's background.
  • BackgroundColor: popup's optional background color. 
  • OutlineColor: optional outline color.
  • OutlineWidth: width of optional outline.
  • IsElliptical: the outline (and fill) is elliptical rather than rectangular
  • OutlineRadius: outline's corner radius.
  • HasShadow: one more time ... that actually works on Android.  Has no effect when BackgroundColor has not been set.
  • ShadowInverted: to apply a recessed effect to the layout (if HasShadow is enabled).
  • CancelOnBackgroundTouch: Controls is the popup is cancelled if the background is touched.  Default value is true.
  • OkButtonColor: Background color for OK button.
  • OkTextColor: Text color for OK button.
  • OKText: Text for OK button.
  • CancelButtonColor: Background color for Cancel button.
  • CancelTextColor: Text color for Cancel button.
  • CancelText: Text for Cancel button.
Methods
  • void Cancel(): Programically cancels the Popup.
  • static PermissionPopup Create(string title, string text, string okText = "OK", string cancelText = "Cancel"): instantiates and presents a Toast.
Events
  • OkTapped: Called when the OK button has been tapped.
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Forms9Patch.ActivityIndicatorPopup

This popup is propably misnamed. Its purpose is to present an activity indicator and block interaction with the app.   Because ModalPopup had everything I needed to build this, I named it a popup.  Probably should have thought about that more.  Also, because this is something you typically just want to fire and forget, like Toast and TargetedToast, ActivityIndicatorPopup has a Create static method to instantiate and present an instance in one call.

Properties
  • PageOverlayColor: The Color of the page overlay upon which the ModalPopup sets.  Default value is Color.Rgba(0.5, 0.5, 0.5, 0.5).
  • Color: Color of the activity indicator.
Methods
  • static ActivityIndicatorPopup Create()
  • void Cancel(): Programically cancels the Popup.
Events
  • Cancelled: Called when the popup has been canceled by the user tapping outside its bounds.

Custom Fonts

Using custom Fonts in Forms9Patch elements

I wish Xamarin had made using custom fonts easier because I would rather be making apps than making libraries.  But, alas, that's not (yet) the case.  I built custom font support because I just couldn't believe how bad it was on Xamarin Forms Android.  If you're at Xamarin and are reading this, please don't take it personally because I love Xamarin Forms (I wouldn't be putting in this much effort if I didn't).  Once I worked it out, I brought this font management magic to Form9Patch's buttons because I thought others would find it useful.  And, because it took less time than it is documenting it, I've added a Label element to Forms9Patch so you can have custom fonts there too.  More recently, I've ported custom font support to Xamarin.Forms's Label, Button, Entry, and Editor elements via Xamarin's PlatformEffects (see below).

Below is an example of how to use Forms9Patch's custom font management.  The example uses Google's Material Design Icons font, which they have been nice enough to license under the Creative Common Attribution 4.0 International License (CC-BY 4.0)! You can download this font from the Material Design Icon's GitHub repository.

Example: Label with Material Icon font

  • Create a PCL Xamarin Forms cross-platform app Solution with the MyDemoApp assembly namespace
  • Add the Forms9Patch Nuget Package
    • Double Click on the "Packages" folder in the PCL project (MyDemoApp in this example).  The "Add Packages" dialog should appear.
    • Search for "Forms9Patch".
    • Check "Forms9Patch" and click [Add Package].
    • Repeat the above three steps for each Platform project (MyDemoApp.Droid and MyDemoApp.iOS in this example).
  • Add the Forms9Patch license key
    • In your Android project (MyDemoApp.Droid), open your MainActivity.cs file.  After global::Xamarin.Forms.Forms.Init(this, bundle); and before LoadApplication (new App ());, insert Forms9Patch.Droid.Settings.Initialize(this, "your_license_key");
    • In your iOS project (MyDemoApp.iOS), open your AppDelegate.cs file.  After global::Xamarin.Forms.Forms.Init(); and before LoadApplication (new App ());, insert Forms9Patch.iOS.Settings.Initialize(this, "your_license_key");
    • FYI, if your app happens to be named "MyDemoApp", then 8HY9-P5V6-J9WA-B3G8-BA8E-ERSA-JRKV-XTHE-79K6-YPY2-YRWX-Y5CW-RA59 would be a valid license key.  Feel free to use it!
  • Update Packages
    • Double Click on your solution solution (MyDemoApp in this example) and then select "Update Nuget Packages".
  • Create a Resources folder in the app's PCL project
    • Right click on your PCL project and select "Add / New Folder".
    • A "New Folder" folder should appear.
    • Rename it "Resources" and press return.
  • Create a Fonts folder under the Resources folder in the app's PCL project
    • Right click on the "Resources" folder you just created (above) and select "Add / New Folder".
    • A "New Folder" folder should appear.
    • Rename it "Fonts" and press return.
  • Save the MaterialIcons-Regular.ttf custom font file to the Resources/Fonts folder.  I prefer to drag it from OSX Finder or Windows File Explorer into the Resources/Fonts folder in Xamarin Studio.
  • Set the Build Action to EmbeddedResource for this custom font
  • Make note of the Resource ID of this custom font
    • Right click on the custom font file and select "Properties".
    • The "Properties" pane should appear.
  • Open your PCL application source file (MyDemoApp.cs in this example)
  • Change the Label element to a Forms9Patch Label
    • Note: XAlign and YAlign is depricated by Xamarin.  As such, I didn't implement them in Forms9Patch.  Use HorizontalTextAlignment and VerticalTextAlignment instead.
  • Set the FontFamily property to the font's resource ID
    • Note 1: XAlign and YAlign is depricated by Xamarin.  As such, I didn't implement them in Forms9Patch.  Use HorizontalTextAlignment and VerticalTextAlignment instead.
    • Note 2: If you compile and run now, you should see some very unexpected output.  Why? Because the Material Icons doesn't have support for most standard characters!
  • BONUS Unicode Characters.  Because we're using Material Icons (which is great for symbols but terrible for text), we are going to need to non-latin, unicode characters to our string.  With Forms9Patch, we have some options for specifying unicode characters.
    • Objective:  The below approaches should result in the following Material Icons in the center of the screen:
    • Copy & Paste:  A lot of times, you can get a Unicode character by copying it from a web page or from an application (like FontBook on OSX).  Once you copy it, you can then paste it into your string in Visual Studio or Xamarin Studio.  For example, here [    ] (between the brackets) are the unicode characters for the Material Icons Font's sissors, airplane, and umbrella characters.
    • C# unicode escape code:  C# makes unicode pretty easy via escape codes ... as long as the character is 16 bit!  For the Material Icons font, you can go to https://design.google.com/icons, select the charactor (icon in this case) you want.  Then, at the bottom right of the page, select "<  > ICON FONT".  There you can find the hexadecimal excape code (see "For IE9 and below").  For the sissors, it is &#xE14E;.  For the airplane, is be &#xE195;.  And for the umbrella, it is &#xEB3E;.  Since each has 4 hexadecimal characters, they all are 16 bit unicode - and I get to avoid explaining how to deal with 32 bit unicode.  In our example, replace "Welcome to Xamarin Forms" with "\uE14E \uE195 \uEB3E".  Notice, for each escape code, that the leading &# was replaced with \u and the traiing semicolon was dropped.
    • HtmlText property:  By design, HTML does a great job with Unicode.  HtmlLabel wouldn't be useful without that magic.  For this example, remember (above) that the HTML escape codes we found on Google's Material Design Icons page were (Sissors=&#xE14E;.  Airplane=&#xE195;.  Umbrella=&#xEB3E;. ).  Since these are HTML escape codes, we can pass them in a string to the HtmlText parameter.

      There is a lot more information about using the HtmlText property below.

Using custom fonts with Xamarin Forms elements

As of Forms9Patch version 0.9.13, you can use font files, embedded as PCL Embedded Resources, with Xamarin Forms Label, Button, Entry, and Editor elements.  Forms9Patch 0.10.2.0 adds this capability to Shared Library Xamarin Forms projects. The process of using Embedded Resource font files with Xamarin Forms's Label is almost the same as doing so with Forms9Patch elements (so please first read Using custorm fonts in Forms9Patch elements, above) but with one additional step.  You will need to add the "Forms9Patch.CustomFontEffect" platform effect to instance of the Xamarin.Forms element in question.  The PCL Forms9PatchDemo app and the Shared Library demo app illustrates this in the CustomFontEffectPage.cs page.  Below is an excerpt from there that demonstrates just how easy this is:


var entry = new Xamarin.Forms.Entry {
    Text = "Xamarin.Forms.Entry element",
    FontFamily = "Forms9PatchDemo.Resources.Fonts.Pacifico.ttf"
};
entry.Effects.Add(Effect.Resolve("Forms9Patch.CustomFontEffect"));                            
                            

Just like Forms9Patch elements, you set the FontFamily property to the EmbeddedResourceID of the font you have embedded in the PCL project.  Then, in order to use that font, you will need to add the "Forms9Patch.CustomFontEffect" to the Effects property of the element in question.


FontFamily Enumeration

So, want to know what fonts are available to you ... in your PCL or Shared Library code?  Call Forms9Patch.FontExtensions.LoadedFontFamilies() to get a List<string> of the currently loaded font families.


Using HTML Markup

Both iOS and Android have some HTML markup capability, natively.  However, the philosophy behind Forms9Patch is to avoid native if there is a PCL or Shared Library approach that is easier and just as fast.  Forms9Patch does this by avoiding the use of intermediate classes and, instead, allows you to pass HTML directly to its Label, MaterialButtonSegment, and ImageLabelState elements by way of the HtmlText property.  Also, HtmlText property supports a larger range of formatting than Xamarin provides via the Span element. Additionaly, HtmlText integrates Forms9Patch's Embedded Resource Custom Font support into its HTML markup to give you the power to easily apply custom fonts on a granular level.

Tags:  Just like both native approaches, Forms9Patch's HtmlText property supports a subset of HTML. Below are the tags and attributes that are supported:

  • <a> Anchor (Action), formatted as a hyperlink.  The text surrounded by this tag will look like a hyperlink.  When this text is tapped on, it will trigger Label's event EventHandler<ActionTagEventArgs>> ActionTagTapped event.  The ActionTagTapped event will pass object sender (the Label element) and ActionTagEventArgs e (with, you guessed it, two parameters: Id and Href).  Attributes:
    • id a first string to identify the action
    • href a second string to further identify the action
  • <big> Big
  • <b> Bold
  • <del> Delete
  • <den> Denominator
  • <em> Emphesis
  • <font> Font. Attributes:
    • face: font family (supports native, "Monospace", "San-serif", "Serif", and Embedded Resource custom fonts)
    • size: font size (in "px", "em", and "%" units, HTML 1-7 unitless, HTML relative, and HTML named sizes )
    • color: font color (in rgb, rgba, hex, and HTML named colors)
  • <ins> Insert
  • <i> Italic
  • <num> Numerator
  • <pre> Prefomatted (Monospace font with white space preserved)
  • <s> Stikethrough
  • <small> Small
  • <strike> Strikethrough
  • <strong> Strong
  • <sub> Subscript
  • <sup> Superscript
  • <tt> Teletype
  • <u> Underline

General Attributes:  Only the style attribute is supported at this time.

  • style: Style applied within tag limits. Parameters:
    • background-color: Background color. (in rgb, rgba, hex, and HTML named colors)
    • color: Font (foreground) color. (in rgb, rgba, hex, and HTML named colors)
    • font-family: Font family (supports native, "Monospace", "San-serif", "Serif", and Embedded Resource custom fonts)
    • font-size: font size (in "px", "em", and "%" units, HTML 1-7 unitless, HTML relative, and HTML named sizes )
    • font-weight: Set to bold to apply bold to the text.  Only bold is supported at this time and only on fonts there a bold subset is available.  It is recommended to use the <b> tag instead.
    • font-style: Set to italic to apply italics formatting to the text. Only italic is supported at this time and only on fonts where an italic subset is available.  It is recommended to use the <i> tag instead.

XAML Example: Html Markup with custom fonts

  • Create a PCL Xamarin Forms cross-platform app Solution with the MyDemoApp assembly namespace
  • Add the Forms9Patch Nuget Package
    • Double Click on the "Packages" folder in the PCL project (MyDemoApp in this example). The "Add Packages" dialog should appear.
    • Search for "Forms9Patch".
    • Check "Forms9Patch" and click [Add Package].
    • Repeat the above three steps for each Platform project (MyDemoApp.Droid and MyDemoApp.iOS in this example).
  • Add the Forms9Patch license key
    • In your Android project (MyDemoApp.Droid), open your MainActivity.cs file.  After global::Xamarin.Forms.Forms.Init(this, bundle); and before LoadApplication (new App ());, insert Forms9Patch.Droid.Settings.LicenseKey = "your_license_key";
    • In your iOS project (MyDemoApp.iOS), open your AppDelegate.cs file.  After global::Xamarin.Forms.Forms.Init(); and before LoadApplication (new App ());, insert Forms9Patch.iOS.Settings.LicenseKey = "your_license_key";
    • FYI, if your app happens to be named "MyDemoApp", then 8HY9-P5V6-J9WA-B3G8-BA8E-ERSA-JRKV-XTHE-79K6-YPY2-YRWX-Y5CW-RA59 would be a valid license key. Feel free to use it!
  • Update Packages
    • Double Click on your solution solution (MyDemoApp in this example) and then select "Update Nuget Packages".
  • Create a Resources folder in the app's PCL project
    • Right click on your PCL project and select "Add / New Folder".
    • A "New Folder" folder should appear.
    • Rename it "Resources" and press return.
  • Create a Fonts folder under the Resources folder in the app's PCL project
    • Right click on the "Resources" folder you just created (above) and select "Add / New Folder".
    • A "New Folder" folder should appear.
    • Rename it "Fonts" and press return.
  • Save the MaterialIcons-Regular.ttf custom font file to the Resources/Fonts folder. I prefer to drag it from OSX Finder or Windows File Explorer into the Resources/Fonts folder in Xamarin Studio.
  • Set the Build Action to EmbeddedResource for this custom font
  • Make note of the Resource ID of this custom font
    • Right click on the custom font file and select "Properties".
    • The "Properties" pane should appear.
  • Add a "Forms ContentPage Xaml" file to your PCL project:
    • Right click on your PCL project (MyDemoApp)
    • Select "Add" / "New File"

      The "New File" dialog box should appear.
    • Select "Forms ContentPage Xaml", enter a name (HtmlTextPage), and click the "New" button.

      You should now have two new files open in Xamarin Studio: HtmlTextPage.xaml (a skeleton Xaml page) and its code behind, HtmlTextPage.cs.
  • Add the Forms9Patch namespace to your XAML
    • Open the HtmlTestPage.xaml file.
    • Add the xmlns:f9p="clr-namespace:Forms9Patch;assembly=Forms9Patch" attribute to the <ContentPage> tag.
  • Add your XAML Layout
    • Add the Padding="40 and BackgroundColor="Silver" attributes to the <ContentPage> tag.
    • Add the following Forms9Patch Label and MaterialSegmentedControl elements to a Xamarin Forms StackLayout as the ContentPage's content:
      
          <StackLayout>
              <Label Text="HTML Markuped Label Examples" TextColor="Black" FontAttributes="Bold"	/>
      
              <f9p:Label TextColor="Black">
                  plain &lt;b&gt;bold&lt;/b&gt; &lt;i&gt;italic&lt;/i&gt;
              </f9p:Label>
      
              <f9p:MaterialSegmentedControl BackgroundColor="White" FontSize="16" FontColor="#0076FF" Orientation="Vertical" OutlineColor="#CCC" OutlineWidth="0" SeparatorWidth="1" OutlineRadius="6" Padding="5">
      
                  <f9p:Segment>Pause &lt;b&gt;5&lt;/b&gt;</f9p:Segment>
                  <f9p:Segment>Pause &lt;b&gt;10&lt;/b&gt;</f9p:Segment>
                  <f9p:Segment>Pause &lt;b&gt;15&lt;/b&gt;</f9p:Segment>
      
                  <f9p:Segment Text="Cancel" FontColor="Red"/>
                  <f9p:Segment HtmlText="&lt;s&gt;Launch&lt;/s&gt;" FontAttributes="Bold" IsEnabled="false"/>
              </f9p:MaterialSegmentedControl>
      
          </StackLayout>                                               
                                                  
    • IMPORTANT NOTE: At this time, HTML markup has to be HTML escaped when used in XAML. This shouldn't be necessary if the HTML markup is put in a <!CDATA[ ]]> block. Unfortunetly, Xamarin seems to be ignoring <!CDATA[ ]]> blocks at this time. You can find the bug report here. In the mean time, there are a number of HTML escape utilites on the web you can use to HTML escape your HTML.
  • Make HtmlTestPage your apps MainPage.
    • Open your PCL projects Application subclass (MyDemoApp.cs in this example).
    • Set the MainPage property to new HtmlTestPage()
  • Launch your app:

Label Autofitting

Xamarin's recommendation for label autofitting is "build a custom renderer".  That is a lot of work.  Really, a lot of work.  Apple's UILabel does make it somewhat straight forward scale the font size to fit the label's width (AdjustFontSizeToFitWidth) or bounds (by setting numberOfLines to zero)but does not handle the case where you want to fit n lines to the label's height.  Android, well because it's Android, makes you get a Ph.D. in reading their source code to do anything - autofitting being a good example. 

Forms9Patch's Label's autofitting works differently because I had more in mind.  Oversimplifying things:

  • If the bounds of the label are imposed upon it then autofitting should scale the font to fit those bounds.
  • If the width of the label is imposed upon it then autofitting should scale the label's height.

But that is an oversimplification.  The Lines, FontSize, and Fit properties play an important role and determining just how Forms9Patch's autofitting works.  To better explain this, lets look at the imposed bounds and imposed width cases separately.


Imposed Bounds

So what is meant by "imposed bounds"?   If the bounds of the Label is either requested (using WidthRequest and HeightRequest) or is limited by it's parent's layout (the Label's content is greater than the space available), then Forms9Patch says the Label's bounds is "imposed". If the Label's bounds are imposed, then you can choose the autofitting behavior by the following property settings:

Property Setting(s) Result GIF
Lines=0 Scale the font size of the text until it either fits within the bounds, limiting the font size between MaxFontSizeand MinFontSize. This is the default setting.
Lines>0
Fit=LabelFit.None
Scale the font size of the text until Lines lines fits the Label's Height, limiting the font size between FontSizeand MinFontSize.  If the text cannot fit within Lines lines or the imposed height, apply the LineBreakMode truncation.
Lines>0
Fit=LabelFit.Width
Scale the font size of the text until it all fits within Lines lines, limiting the font size between FontSizeand MinFontSize.  If limited to MinFontSize, apply the LineBreakMode truncation.
Lines>0
Fit=LabelFit.Lines
Scale the font size of the text until Lines lines fits the Label's Height, limiting the font size between FontSizeand MinFontSize.  If the text cannot fit within Lines lines, apply the LineBreakMode truncation.

Imposed Width

Autofitting works differently if the Label's width has been imposed but the height has not.  In this scenario, the goal is to scale the height to match text at the given FontSize or the given Fit and Line values. The table below describes how imposed width autofitting behavior is controlled by the related property settings:

Property Setting(s) Result GIF
Lines=0 Scale the height of the label to fit the text at the current FontSize. This is the default setting.
Lines>0
Fit=LabelFit.None
Scale the height of the label so that it is as tall as the smaller of either Lines lines at FontSize of the complete text body at FontSize.  If the text cannot fit within Lines lines, apply the LineBreakMode truncation.
Lines>0
Fit=LabelFit.Width
Scale the height of the label and the font size of the text until it all fits within Lines lines, limiting the font size between FontSize and MinFontSize..  If limited to MinFontSize, apply the LineBreakMode truncation.
Lines>0
Fit=LabelFit.Lines
Scale the height of the label so that it is as tall as Lines lines at FontSize.  If the text cannot fit within Lines lines, apply the LineBreakMode truncation.

Once the autofitting is completed, Forms9Patch updates Label's read only ActualFontSize property with the resulting font size.  And, in case you were wondering: Why is there no autofitting when the width is not imposed?  Because then the text should all fit on one line.


Extensions

Here are a few extensions that you might find useful.


Color Extensions

RgbBlend

static Color RgbBlend(this Color c, Color c2, double percent) usage: blend = c.RgbBlend(c2, percent);.  This method returns the color that is percent between c and c2.

WithAlpha

static Color WithAlpha(this Color c, double alpha) usage: alphaColor = c.WithAlpha(c, alpha);.  This method returns the same color but with alpha as the opacity.


WebView Extensions

CanPrint

static bool CanPrint usage: if(Forms9Patch.WebExtensions.CanPrint) ....  This property will return true if the OS can print the contents of a Xamarin.Forms.WebView.

static void Print(this WebView webview, string jobname) usage: webview.Print(jobname);.  This method will print the contents of webview using jobname as the jobname.


String Extensions

ToColor

static Color ToColor(this string s) usage: color = s.ToColor();.  This method parses an HTML format color string into a Xamarin.Forms Color.


HTML String Extensions

ToPng

static void ToPng(this string html, string fileName, Action<string> onComplete) usage:


var fileName = "attachment.1";
htmlString.ToPng(fileName, (string path) =>
{
    if (path != null)
        System.Diagnostics.Debug.WriteLine("A PNG of your HTML is here: "+path);
});
                        

ToPng renders your HTML string as a PNG file, places it in the PCLStorage.FileSystem.Current.LocalStorage folder, as a file named fileName plus the .png extension.  Once it has completed, it will call onComplete, passing to it path - a string that is the path to the generated PNG.  This works great with Xam.Plugins.Messaging to create email attachments.

And why not a PDF?  Mostly because I wasn't able to (1) have large, single page documents on both iOS and Android, (2) not have page breaks in inconvenient places, (3) get anything but the first page to render on Android, and (4) reduce the bloat of the PDF file size (PNG was always smaller).

And why not just have this as an extension to WebView?  Largely because it would be a lot more work and I didn't need it for my own apps.  If you think that would be of value to you, help me understand the use case and I'll consider it.



Services

Here are some services you might find helpful as well.


Keyboard Service

Want to put away the system keyboard?  Want to be notified when the system keyboard appears or disappears?  The KeyboardService class has the following for those purposes:

  • public static void KeyboardService.Hide() will hide the system keyboard.
  • public static event EventHandler Hidden; will be invoked when the keyboard is hidden.
  • public static event EventHandler Shown; will be invoked when the keyboard is shown.

Key Clicks Service

Do you want to make a system keyboard sound (and vibration, if available)?  The static KeyClicksService class has just one method, static void Feedback(HapticEffect effect, KeyClicks mode=KeyClicks.Default).  The values of KeyClicks are:

  • HapticEffect.None: As you might guess, it will do nothing!
  • HapticEffect.KeyClick: Responds with the system keyboard keyclick haptic effect
  • HapticEffect.Return: Responds with the system keyboard return key keyclick haptic effect
  • HapticEffect.Delete: Responds with the system keyboard back/delete key keyclick haptic effect

Likewise, the HapticMode values are:

  • KeyClicks.Off: no sound, no vibration
  • KeyClicks.Default: uses the default (application or OS) for haptics on/off
  • KeyClicks.On: You don't care what defaults have been set by your application or the system, make the this haptic feedback happen!

Usage is pretty simple. Just pick your combination of HapticEffect and KeyCLicks, and use them as arguments to KeyClicksService.FeedBack.  And here is the helpful part: when you set your KeyClicks to KeyClicks.Default, your haptics feedback will be determined by the value of the Forms9Patch.Settings.KeyClicks property.  Which means you have a global switch for not just your KeyClicksService.Feedback but all of Forms9Patch buttons  And, on Android, when Forms9Patch.Settings.KeyClicks is set to KeyClicks.Default, Forms9Patch will use the device's KeyClicks settings.


Application Information Service

Do you want to quickly know your application's Name, Bundle/Package ID, Build number and Version string?  ApplicationInfoService is a static class with the following static properties:

  • Name: Application's display name.
  • Identifier: Application's Bundle/Package identifier.
  • Build: Application's build number.
  • Version: Application's version string.

Release Notes

Version Changes
0.10.3.5
  • Fixed: Android popup element's background overlay is not blocking touch events.
  • UWP: The following Forms9Patch elements are "pre-alpha" for UWP, meaning they mostly work but are not complete:
    • ImageSource
    • Image
    • ImageButton
    • ImageButtonState
    • MaterialButton
    • MaterialSegmentedControl
    • Segment
    • RootPage
    • ActivityIndicatorPopup
    • ModalPopup
    • PermissionPopup
    • Toast
    • AbsoluteLayout
    • BubbleLayout
    • ContentView
    • Frame
    • Grid
    • ManualLayout
    • RelativeLayout
    • StackLayout
    • Display
    • ApplicationInfoService

    Correspondingly, the following are not working:
    • Anything with custom fonts
    • Label
    • Image.TintColor
    • ColorGradientBox
    • BubblePopup
    • TargetedToast
    • the WebView extensions
    • the ToPng() string extension
    • KeyboardService
    • KeyClicksService
    • StatusBarService

0.10.3.4
  • Fixed: Size of last Segment of MaterialSegmentedController does not always match other segments
  • Fixed: iOS: intermittant crash when ImageSource is disposed
  • Changed: Added appDelegate as the first argument in Forms9Patch.iOS.Settings.Initialize(AppDelegate appDelegate, string licenseKey)
  • Changed: Added activity as the first argument in Forms9Patch.Droid.Settings.Initialize(Android.App.Activity activty, string licenseKey)
0.10.3.3
  • Fixed: Android Image property of ImageButtonState, MaterialButton, and MaterialButtonSegment dissappears when tapped.
  • Fixed: Android: Some Forms9Patch.Image sourced from Forms9Patch.ImageSource.FromMultiResource are not fitted properly
0.10.3.2
  • Fixed: ImageButton triggers Tapped event twice when tapped.
  • Fixed: Properties of ImageButton.DefaultState are overwritten by properties of other states when state is changed.
0.10.3.1
  • Fixed:ImageButton crashes when ImageButtonState properties (DefaultState, PressedState, etc) are not set.
0.10.3.0
  • Enhanced: ImageButton, MaterialButton and MaterialSegmentedControl has been enhanced with HorizontalTextAlignment and VerticalTextAlignment properties.
  • New: MaterialSegmentedControl also has IntraSegmentSpacingcode> and IntraSegmentOrientation properties
  • Obsolete:Alignment property for ImageButton, MaterialButton and MaterialSegmentedControl
  • Refactored: Type of Image property of ImageButton has been changed from Xamarin.Forms.Image to Forms9Patch.Image
  • Fixed: Potential crash when Image elements are deconstructed.
0.10.2.16
  • Fixed:rendering of images and fonts in VisualStudio XAML Previewer (iOS only). Known issue: images and fonts do not render in your Xamarin.Forms PCL file (derived from Xamarin.Forms.Application).
0.10.2.13
  • Changed: Forms9Patch.Label is now a descendent of Xamarin.Forms.Label in anticipation of XF 2.6
  • Fixed: Many Forms9Patch.Label edge cases:
    • Android: LineBreakMode=LineBreakMode.NoWrap wraps at words rather than force the text to be on one line;
    • Android: LineBreakMode=LineBreakMode.NoWrap wraps at words, not characters;
    • iOS: Label degrades to default iOS label behavior when FontSize is changed;
    • iOS: Label does not correctly vertical align when using NoWrap LineBreakMode;
    • iOS: Label does not correctly vertical align when LabelFit=None and FontSize exceeds available space;
    • iOS: Label does not correctly vertical align when LabelFit=None, height is unimposed, and lines are larger than needed
    • iOS: Label with unimposed height, fit=width, lines 3,5,6,7 vs 1,2,4 gives inconsistant vertical alignment;
    • iOS: Label fixed height, Fit=LabelFit.None, adjust lines gives erratic veritcal alignment;
    • iOS: Label text is centered with fixed height, Fit=LabelFit.None, Lines=0, VerticalAlighment=TextAlignment.Start
    • iOS: Label unimposed height, fit=none, lines=0, some font sizes give 1 less line than it should
    • iOS: Label unimposed height, fit=none; adjust lines: should not add empty lines
    • iOS: Label unimposed height, fit=width, lines=5, some font sizes give 4 vs 5 lines
0.10.2.12
  • Fixed:
    • ImageSource does not (by default) open Embedded Resource images when used in library project.
  • Changed:
    • PCL Profile from 259 to 111.
0.10.2.11
  • Fixed:
    • Android: Back button causes app to exit.
0.10.2.10
  • Fixed:
    • Android: Label not rendering in Xamarin.Studio's XAML Previewer.
0.10.2.9
  • Fixed:
    • iOS: LabelFit.Lines not working when truncating.
  • Changed:
    • Buttons now default to Fit=LabelFit.Width and Padding=4
0.10.2.8
  • Added:
    • optional SelectedBackgroundColor and SelectedFontColor properties are added to MaterialButton and MaterialSegmentedControl. See SegmentSelectedBackgroundPage in demo app for example usage.
0.10.2.7
  • Fixed:
    • iOS: Failure to dynamically resize Label when text is dynamically changed.
0.10.2.6
  • Fixed:
    • ImageButton not returned to full opacity when IsEnabled is programically set to true.
0.10.2.5
  • Fixed:
    • bound values of ImageButtonState properties are intermittantly (if at all) used by ImageButton.
0.10.2.4
  • Added:
    • TintImage property to MaterialButton and MaterialSegmentedController to control if ImageSource image is tinted with FontColor;
0.10.2.3
  • Fixed:
    • Forms9Patch.Label blocking touches on Xamarin.Forms.ListView.
    • Forms9Patch.Label not updating when BindingContext changes (Android only).
  • Added:
    • Support for <br> tag to Forms9Patch.Label.Html property.
    • ApplicationInfoService added to make it easy to get applications Name, Bundle/Package id, Build number and Version string.
    • RootPage.Create static method to assure singleton instantiation.
    • RootPage.Page property is available as an alternative way to set the content of the RootPage as well as a way to get the content of the RootPage.
  • Changed:
    • Refactored KeyClicksService to be KeyClicksService
  • Enhanced:
    • PermissionPopup is now inherited from BubblePopup so permission popups can point to a VisualElement.
0.10.2.2
  • Fixed:
    • Ability of FormsGestures.Listener to listen to gestures on existing Forms9Patch elements.
    • RootPage responds correctly to changes in iOS status bar
    • Finally got rid of the unnecessary FormsGestures exception presented when disposing FormsGestures.Listener on Android.
  • Added:
    • ColorGradientBox element
0.10.2.1
  • Fixed:
    • Intermittant crash (on Android) when disposing a Forms9Patch layout.
0.10.2.0
  • New:
    • Forms9Patch now supports Shared Library projects.  Apparently, it (almost) did all along except for Embedded Resource font files.  This release fixes that.
0.10.1.0
  • Added:
    • The much requested <a> markup element to Label
    • The Forms9Patch buttons now have the HapticEffect and HapticMode properties to control when and what kind of haptic feedback they may have. See Haptic Service for more information on HapticEffect and HapticMode.
0.10.0.1
  • Fixed:
    • Crash when setting OutlineRadius property via XAML attribute.
0.10.0.0
  • IMPORTANT: Wrapping your app's main page in a Forms9Patch.RootPage is required to use the popups. See Popups! for more information about this.
  • New:
    • Added the Toast, TargetedToast, and ActivityIndicatorPopup popups.
    • Significant layout optimizations for the Label renderers.
    • Added the IgnoreChildren property to the layouts to prevent a child view update from kicking off a measurement-layout cycle on the view hierarchy.
    • Added the Retain property to the popups. Setting it to true will keep the popup and its contents on the view stack so it won't have to be re-rendered when presented again.
    • ListView and SinglePicker elements are Alpha.  This is the reason for the version number jump to 0.10.  If you're interested in learning more, let me know.
    • Added the <num> and <den> markup tags to Label.HtmlText for the purpose of displaying numerators and denominators (slightly different than <sup> and <sub>).
    • Added the IconText property to MaterialButton and Segment as an alternative to ImageSource.
    • Added static class WebViewExtensions
    • Added void Tap() method to buttons to programmically tap them.
    • Added KeyClicksService and configured buttons to use it.
    • Added KeyboardService as a way to retract the system keyboard and be alerted to changes in system keyboard visibility.
  • Fixed:
    • Label being instantiated but not rendered causes crash.
    • popups now respect the Margin property.
    • popups now respect the HorizontalOptions and Vertical options property.
    • intermittent crash on Android when initizing a popup.
0.9.13.5
  • Fixed:
    • Crash from Label element being instantiated and held a period without being rendered.
0.9.13.4
  • Fixed:
    • iOS: FormsGestures library provides erratic results for Panning events.
0.9.13.3
  • Enhanced:
    • Added read-only property ActualFontSize to Label to share the post-fitting font size
  • Fixed:
    • Android: Label is not truncated to Lines if the LineBreakMode is not HeadTruncation, CenterTruncation, or TailTruncation.
0.9.13.2
  • Enhanced:
    • Build to Android API 15 (rather than API 16)
    • Added IsElliptical to layouts and MaterialButton to make outline and fill elliptical rather than rectangular.
  • Fixed:
    • Opacity property of Image is now supported.
    • Android: Math symbols were not being processed correctly
  • Changed: StickyBehavior property of buttons has been renamed ToggleBehvior and (for MaterialSegmentedControl GroupToggleBehavior
0.9.13.1 New: Added the CancelOnBackgroundTouch property to ModalPopup and BubblePopup.  Default value is true.
0.9.13.0 New: CustomFontEffect platform effect can be applied to Xamarin.Forms Label, Button, Entry, and Editor elements to allow the EmbeddedResourceID of PCL Embedded Resource fonts as value for FontFamily property..
0.9.12.5 Fixed: ImageButton in ContentView fails to correctly render state changes in BackgroundImage (Android).
0.9.12.4
  • Enhanced: Forms9Patch.ImageSource.FromMultiResource uses first portion of Embedded Resource ID to determine which assembly to search for the embedded resouce in question.
  • Fixed: Resizing of button labels when text is changed.
  • Changed: Lines property of Label sets the max number of lines displayed when Fit is set to LabelFit.None
0.9.12.3
  • Enhanced: FontFamily can be set to explicit iOS system font name.
  • Fixed:
    • Crash when rendering multiple Labels in horizontal orientation in StackLayout
    • Failure to correctly render Label in some layouts
    • Failure to autofit some one-character labels correctly
    • Failure to resize label when bounds changes
0.9.12.2
  • Enhanced: Label's Fit property is now enabled for labels with unimposed Height.
  • Fixed:
    • Crash when instantiating buttons on iOS release builds
    • iOS HtmlText <tt> tag combined with <b>, <u>, or <i> fails to render font correctly
    • Android ImageButton intermittantly does not respond to touch
0.9.12.1 Fixed:
  • Failure to get bold and/or italic version of some iOS system fonts
  • Multi-line labels not appearing as such on iOS
  • 9-Patch images that have been marked to the trailing edge fail to render on iOS
0.9.12.0
  • New!
    • Autofit ability for Forms9Patch.Label.
    • TrailingImage property for ImageButton, MaterialButton, and MaterialSegmentedController reverses the order in which a button's label and image are displayed.
    • Forms9Patch.FontExtensions.LoadedFontFamilies() enumerates the fonts that are currently loaded.
  • Fixed
    • iOS: HtmlText underlines don't match current font color
    • Android: DefaultState ImageButton label is missing for some states.
    • Unable to bind to Segment
    • When Sticky property is set to Radio, able to (when shouldn't be able to) tap to unselect a MaterialSegmentedController Segment
0.9.11.2 Fixed: In iOS, Images will have height or width of 1 (instead defaulting to source image height or width) when HeightRequest or WidthRequest is not set.
0.9.11.1 Fixed: Issue where Forms9Patch.iOS.Settings.LicenseKey throws System.NullRefernceException.
0.9.11.0 Added:
  • Custom fonts (saved as Embedded Resources) can be loaded by setting the FontFamily property (of the Label, MaterialButton, and ImageButtonState elements) to the font's Embedded Resource ID.
  • HtmlText property added to the Label, MaterialButton, Segment, and ImageButtonState elements.
0.9.10.7 UPDATE: Built for Xamarin Forms 2.2.0.31.
0.9.10.6 Fixed:
  • Crash when no Target is given for BubblePopup
  • Failure to present popups when used w/ PushModalAsync()
0.9.10.4 Added: Cancel method to Popups.  Auto-cancel of Popups when Android's [back] button is pressed.
0.9.10.3 Fixed: Improved reliabilty of rendering of 9patch backgrounds when used in ListView in Android.
0.9.10.2 Fixed: AOT issue that caused BubblePopup to crash on iOS devices.
0.9.10.1 Fixed: layout of NinePatch backgrounds when used in a ListView on Android.  See demo app on Github for example usage.
0.9.10.0
  • Added: ModalPopup, a modal popup centered to the device's screen or, if specified, a Xamarin.Forms.Page.
  • Added: BubblePopup, a bubble popup that will point to a given Xamarin.Forms.VisualElement and do a best fit to the available screen space based on its allowed pointer directions and the size of its content.
  • Fixed: MaterialSegmentedControl not responding to changes in its StickyBehavoir property.
0.9.9.3
  • Enhanced: 25x faster tap response on all buttons.
  • Enhanced: 2x additionally faster rendering of iOS images (when sourced using Forms9Patch.ImageSource.FromMultiResource or Forms9Patch.ImageSource.FromResource.
  • Enhanced: 10x faster rendering of MaterialButton and MaterialSegmentedControl
  • Fixed: Background is properly rendered for all states of ImageButton
  • .
0.9.9.2 Enhanced: Forms9Patch.Image loading is 3x faster on iOS. Known Issue: ImageButton sometimes fails to show any background other than the default. Will be fixed very soon.
0.9.9.1 Fixed: Failed to resolve "System.Reflection.Emit.OpCode" during compilation for iOS devices (not iOS emulators).
0.9.9.0 Added:
  • PressingState to ImageButton to enable customization of the button for when it is in the pressed state.
  • LongPressing and LongPressed events have been added to the ImageButton, MaterialButton, and Segment element.
  • SegmentLongPressing and SegmentLongPressed events have been added to the MaterialSegmentedControl element.
  • Renamed ImageButton's Clicked event to Tapped.
0.9.8.2 Fixed: Not all attributes of ImageButtonState respond to XAML setters.
0.9.8.1 Fixed:
  • MaterialSegmentedControl.Segments is not recognized as the XAML Content for MaterialSegmentedControl.
  • Shadows are clipped on high resolution Android devices.
  • Padding (which should only impact Segments) changes padding for the whole MaterialSegmentedControl element.
Added:
  • Segment.FontColor: to be able to override parent's FontColor property.
  • Segment.FontAttributes: to be able to override parent's FontAttributes property.
0.9.8.0 Added:
  • MaterialSegmentedControl: A segmented button control not unlike iOS's UISegmentControl
  • Segment: An element for each segment of a MaterialSegmentedControl
  • MaterialButton.Orientation property
  • MaterialButton.Selected event
Changes: because of a lack of foresight
  • renamed MaterialButton.Selected property to MaterialButton.IsSelected
  • renamed MaterialButton.Clicked event to MaterialButton.Tapped
0.9.7.1 Bug Fix MaterialButton updates:
  • Fix bad boarder rendered when image but no text present
  • Changed MaterialButton.Image (bad idea) to MaterialButton.ImageSource (not so bad idea)
  • removed AllCaps from MaterialButton's text
0.9.7.0 Added
  1. ImageButton: Button with optional background image, optional text and optional companion image sub-elements that can change based upon button state.  State depended subelements are specified via the DefaultState, SelectedState, DisabledState, and DisabledAndSelectedState properties with a ImageButtonState instance.  See demo app for example.  A state property that is not set will default to its corresponding DefaultState property - so you only have to specify what you want to change relative to the DefaultState.
  2. ImageButtonState class for the purpose of specifying the properties (BackgroundImage, Text, FontColor, FontAttributes, FontSize, FontFamily, BackgroundColor, and Image) of an ImageButton for a state.
  3. MaterialButton: Button loosely based upon Google's Material design language.  Again, see demo app.  Text and companion images are optional.
  4. HasShadow property added to StackLayout, RelativeLayout, Grid, and AbsoluteLayout Elements.  Also, Forms9Patch's HasShadow works on Frame on Android!!!
  5. ShadowInverted property added to StackLayout, RelativeLayout, Grid, Frame, and AbsoluteLayout elements to give a recessed effect.
0.9.6.0
  1. Bug fix Crash from intermittant iOS UIImage.ImageWithData double free
  2. Added RelativeLayout, Grid, and AbsoluteLayout Elements
0.9.5.2 Bug fix Fixed ContentView background scalable image rendered as non-scalable image if CapsInset has a one or two -1 values
0.9.5.1 Bug fix Fixed device scaling of ContentView BackgroundImage
0.9.5.0 Enhancement
  1. Added Fill (AspectFill, AspectFit, Fill and Tile) property to Image (applies when image is not a NinePatch or CapInsets property is not set
  2. Added Forms9Patch.ContentView element (extension of Xamarin.Forms.ContentView) with BackgroundView property
  3. Added Forms9Patch.Frame element (extension of Xamarin.Forms.Frame element) with BackgroundView, OutlineWidth and OutlineRadius properties
0.9.4.1 Bug fix Correct resizing when iOS screen orientation changes
0.9.3.0 Bug fix Race condition during debug where iOS Renderer releases Element before releasing renderer.
0.9.2.3 Bug fix for not properly scaling when parent space is smaller than base image but larger than base image less complaint portion.
0.9.1 Initial version for Xamarin.Forms 2.0.0.6490

To install any specific version, you need to use the Package Manager Console.

Install-Package Forms9Patch [-Pre] [-version <version>]

If you don't specify a version, then the most recent version will be installed.
If you want to install a prerelease version, then you have to add the -Pre switch.



FAQ

How do I install Forms9Patch?

You can install it with NuGet.  The easiest way is to right click your solution and choose "Manage NuGet Packages for Solution...", then search for Forms9Patch and install it.

You could also do this from the Package Manager Console.  In the Default Project drop down list select your portable project. Then type

Install-Package Forms9Patch

Then select all your platform projects one after the other and type the same again (or cursor up).  This installs the package in all projects.  There will be different references added depending on the project type.

Does it support Windows Phone / Desktop apps ?

Windows Phone: No.  Windows UWP: limited, alpha implementation.  See the release notes for more details.

I get "Could not load file or assembly 'Forms9Patch'" or "Could not load type Forms9Patch...".

Please check your references.  The portable project needs to reference Forms9Patch.  The platform specific projects need references to Forms9Patch.Droid or Forms9Patch.iOS respectively.  In Xamarin Studio your platform projects also need a reference to Forms9Patch.  Visual Studio copies it over to the output directory, but XS doesn't do that.

Please also check, if you called Settings.Initialize like it is described below.  If this is not called, then the linker thinks you don't need the dll and doesn't include it in the package deployed to your device.

If you don't have a license key yet, you can set it to a dummy string in the meantime (just be sure it's not null or empty).  This will at least include the dll, activate Forms9Patch.ImageSource and allow Forms9Patch.Image to function properly on one image.

Setting Forms9Patch.iOS.Settings.Initialize throws a System.NullReferenceException

It appears that the info.plist editor in Xamarin Studio is setting the wrong key for the Application Name.  Use a text editor to open info.plist and look for the key CFBundleName.  If you find it and it contains your intended Application Name, then this is the root cause.  Rename the key CFBundleDisplayName and save your updated version of info.plist.

Only one Forms9Patch.Image is scaled - the rest are not.  What's going on?

You did not set the LicenseKey properly or it does not match your app name.  Please check if you set the correct LicenseKey in all platform specific projects and that your app name matches the key.

How do I configure my license key?

As your app name can be different on each platform, the license key must be configured in all platform specific projects.  The best place for it is in each project immediately after the call to global::Xamarin.Forms.Forms.Init(...).

Android

In your Android project open MainActivity.cs and in the OnCreate method after the call to global::Xamarin.Forms.Forms.Init(...) add the following line:


                    Forms9Patch.Droid.Settings.Initialize(this, "<your license key>");
iOS

In the iOS project this has to be done in AppDelegate.cs, in the FinishedLaunching method.  Add this line:

Forms9Patch.iOS.Settings.Initialize(this, "<your license key>");
Windows UWP
  1. Follow the Xamarin guide to create the UWP project for your Xamarin.Forms app.
  2. Add Forms9Patch nuget package (version >= 0.10.3.5)
  3. In the UWP project's App.Xaml.cs file, replace the Xamarin.Forms.Init(e); line (you added earlier in Step 1) with the following lines:
    
                    var assembliesToInclude = Forms9Patch.UWP.Settings.AssembliesToInclude;
                    Xamarin.Forms.Forms.Init(e, assembliesToInclude); 
                    Forms9Patch.UWP.Settings.Initialize(this, _put_the_Forms9Patch_license_key_for_this_app_here_ );
    
  4. Set the UWP apps display name:
    • Open the UWP project's app manifest (double click on the Package.appxmanifest file in the UWP project).
    • In the [Application] section, set the "Display Name:" to the name associated with your Forms9Patch license key.
    • In the [Packaging] section, set the "Package display name:" to the name associated with your Forms9Patch license key.
  5. Enable XAML Compilation: In every project that has XAML to display, add the following line to the project's Properties/AssemblyInfo.cs file. Note: Don't make the same rookie mistake I did and put the following line in the UWP project's (instead of the PCL project's) AssemblyInfo.cs file.
    
        [assembly: Xamarin.Forms.Xaml.XamlCompilation(Xamarin.Forms.Xaml.XamlCompilationOptions.Compile)]
    

System.MissingMethodException

If you are getting a System.MissingMethodException and the missing method is from Xamarin.Forms (ex: VisualElement.InvalidMeasure or VisualElement.OnMeasure), you may have a conflict in assembly versions used in various 3rd party Nuget packages in your project or, more likely, you've got an old version of a DLL in your build.  Forms9Patch is usually checked against the two most recent releases of Xamarin.Forms.  If in doubt, verify that the Forms9Patch demo app works and, if it does, use the same build of Xamarin.Forms it does.

I can't get feature x to work

Well, you may have found a bug!  But, to be sure, download and try either the PCL demo app or the Shared Library demo app.  You might have to modify the demo app to implement the feature as you are using it.  Does the feature in question work in the demo app?  If it does not, then you have a non-proprietary way of replicating the issue (which GREATLY improves the chances of a quick solution).   If it does, then you have a place to start debugging your app.  What is different between the demo app your your app?  Once you know what turns the bug on/off in your app, if you consider the root of the problem to be with Forms9Patch, please either create a small sample project or modify the demo app to replicate the issue and share it with me.

How do I configure my app name?

The name of the app has to be configured differently on each platform.

Android

In the Android project open MainActivity.cs.  The MainActivity class should have a Activity attribute.  The Label parameter is the app name.

If you configured your activity manually in the Properties / AndroidManifest.xml file, then you need to change the android:label attribute there.

iOS

Open the iOS project properties and go to the "iOS Application" tab.  There you'll find the "Application name".  Alternatively, you can edit the value for the CFBundleDisplayName key in your iOS application's Info.plist file.

Is there a trial version?

The trial version is built in.  Partially that is because, if you don't use the correct license key, Forms9Patch will mostly work (because most of it is free).  What won't work, if you don't have the right license key, are the HtmlText properties and the image manipulations - in other words, scaling scalable images, tiling, tinting, etc.  To get a fully functional trial, you'll need a valid key - but how?  Well, the free PCL Forms9PatchDemo project hosted on GitHub or the Shared Library demo app have a valid keys!   In other words, if you want a valid demo key for your project, just be sure your app is named "Forms9Patch Demo" or "SharedApp", just like the two demo apps.   See How to I configure my app name, above for instructions on how to do that.

When I compile the demo app, the compiler says some of the images are missing.

Take a moment to look at the compile logs and verify if all the missing image files contain either the ¾ or the ½ character.  If they do, you have a git client that has trouble with unicode characters.  Switching to a different git client usually addresses this.  My preference is SourceTree.

How do get a popup view to display?

To display a popup view, after it has been initialized, set its IsVisible property to true.


Contact

My name is Ben Askren and I'm a mobile developer located in Lexington, Kentucky.  I had 18 years experience in R&D Engineering and Management before, in 2009, I started mobile development with my first app, BuildCalc.  Once a C bigot, I have now drank the C# / Xamarin Forms Kool-aid and am currently working to make it my framework of choice.

If you have any questions or suggestions, find an inevitable bug, or whatever, you can: