Summary of Chapter 13. Bitmaps
Notes on this page indicate areas where Xamarin.Forms has diverged from the material presented in the book.
Image element displays a bitmap. All the Xamarin.Forms platforms support the JPEG, PNG, GIF, and BMP file formats.
Bitmaps in Xamarin.Forms come from four places:
- Over the web as specified by a URL
- Embedded as a resource in the shared library
- Embedded as a resource in the platform application projects
- From anywhere that can be referenced by a .NET
Bitmap resources in the shared library are platform-independent, while bitmap resources in the platform projects are platform-specific.
The text of the book makes references to Portable Class Libraries, which have been replaced by .NET Standard libraries. All the sample code from the book has been converted to use .NET standard libraries.
UriImageSourcefor accessing a bitmap over the web based on a
Uriobject set to its
FileImageSourcefor accessing a bitmap stored in a platform application project based on a folder and file path set to its
StreamImageSourcefor loading a bitmap using a .NET
Streamobject specified by returning a
Funcset to its
Alternatively (and more commonly) you can use the following static methods of the
ImageSource class, all of which return
ImageSource.FromUrifor accessing a bitmap over the web based on a
ImageSource.FromResourcefor accessing a bitmap stored as an embedded resource in the application PCL;
ImageSource.FromResourceto access a bitmap in another source assembly
ImageSource.FromFilefor accessing a bitmap from a platform application project
ImageSource.FromStreamfor loading a bitmap based on a
There is no class equivalent of the
Image.FromResource methods. The
UriImageSource class is useful if you need to control caching. The
FileImageSource class is useful in XAML.
StreamImageSource is useful for the asynchronous loading of
Stream objects, whereas
ImageSource.FromStream is synchronous.
The WebBitmapCode project loads a bitmap over the web using
Image element is set to the
Content property of the
ContentPage, so it is constrained to the size of the page. Regardless of the bitmap's size, a constrained
Image element is stretched to the size of its container, and the bitmap is displayed in its maximum size within the
Image element while maintaining the bitmap's aspect ratio. Areas of the
Image beyond the bitmap can be colored with
Fit and fill
AspectFit: respects aspect ratio (default)
Fill: fills area, does not respect aspect ratio
AspectFill: fills area but respects aspect ratio, accomplished by cropping part of the bitmap
You can add a bitmap file to a PCL, or to a folder in the PCL. Give it a Build Action of EmbeddedResource. The ResourceBitmapCode sample demonstrates how to use
ImageSource.FromResource to load the file. The resource name passed to the method consists of the assembly name, followed by a dot, followed by the optional folder name and a dot, followed by the filename.
The program sets the
HorizontalOptions properties of the
LayoutOptions.Center, which makes the
Image element unconstrained. The
Image and the bitmap are the same size:
- On iOS and Android, the
Imageis the pixel size of the bitmap. There is a one-to-one mapping between bitmap pixels and screen pixels.
- On Universal Windows Platform, the
Imageis the pixel size of the bitmap in device-independent units. On most devices, each bitmap pixel occupies multiple screen pixels.
The StackedBitmap sample puts an
Image in a vertical
StackLayout in XAML. A markup extension named
ImageResourceExtension helps to reference the embedded resource in XAML. This class only loads resources from the assembly in which it's located, so it can't be placed in a library.
More on sizing
It's often desirable to size bitmaps consistently among all the platforms.
Experimenting with StackedBitmap, you can set a
WidthRequest on the
Image element in a vertical
StackLayout to make the size consistent among the platforms, but you can only reduce the size using this technique.
You can also set the
HeightRequest to make the image sizes consistent on the platforms, but the constrained width of the bitmap will limit the versatility of this technique. For an image in a vertical
HeightRequest should be avoided.
The best approach is to begin with a bitmap wider than the phone width in device-independent units and set
WidthRequest to a desired width in device-independent units. This is demonstrated in the DeviceIndBitmapSize sample.
The MadTeaParty displays Chapter 7 of Lewis Carroll's Alice's Adventures in Wonderland with the original illustrations by John Tenniel:
Browsing and waiting
The program uses an
ActivityIndicator to indicate that something's going on. As each bitmap is loading, the read-only
IsLoading property of
IsLoading property is backed by a bindable property, so a
PropertyChanged event is fired when that property changes. The program attaches a handler to this event, and uses the current setting of
IsLoaded to set the
IsRunning property of the
ImageSource.FromStream method creates an
ImageSource based on a .NET
Stream. The method must be passed a
Func object that returns a
Accessing the streams
The BitmapStreams sample demonstrates how to use the
ImaageSource.FromStream method to load a bitmap stored as an embedded resource, and to load a bitmap across the web.
Generating bitmaps at run time
All the Xamarin.Forms platforms support the uncompressed BMP file format, which is easy to construct in code and then store in a
MemoryStream. This technique allows algorithmically creating bitmaps at runtime, as implemented in the
BmpMaker class in the Xamrin.FormsBook.Toolkit library.
The "Do It Yourself" DiyGradientBitmap sample demonstrates the use of
BmpMaker to create a bitmap with a gradient image.
All the Xamarin.Forms platforms allow storing bitmaps in the platform application assemblies. When retrieved by a Xamarin.Forms application, these platform bitmaps are of type
FileImageSource. You use them for:
The platform assemblies already contain bitmaps for icons and splash screens:
- In the iOS project, in the Resources folder
- In the Android project, in subfolders of the Resources folder
- In the Windows projects, in the Assets folder (although the Windows platforms do not restrict bitmaps to that folder)
The PlatformBitmaps sample uses code to display an icon from the platform application projects.
All the platforms allow storing multiple versions of bitmap images for different device resolutions. At runtime, the proper version is loaded based on the device resolution of the screen.
On iOS, these bitmaps are differentiated by a suffix on the filename:
- No suffix for 160 DPI devices (1 pixel to the device-independent unit)
- '@2x' suffix for 320 DPI devices (2 pixels to the DIU)
- '@3x' suffix for 480 DPI devices (3 pixels to the DIU)
A bitmap intended to be displayed as one-inch square would exist in three versions:
- MyImage.jpg at 160 pixels square
- MyImage@2x.jpg at 320 pixels square
- MyImage@3x.jpg at 480 pixels square
The program would refer to this bitmap as MyImage.jpg, but the proper version is retrieved at runtime based on the resolution of the screen. When unconstrained, the bitmap will always render at 160 device-independent units.
For Android, bitmaps are stored in various subfolders of the Resources folder:
- drawable-ldpi (low DPI) for 120 DPI devices (0.75 pixels to the DIU)
- drawable-mdpi (medium) for 160 DPI devices (1 pixel to the DIU)
- drawable-hdpi (high) for 240 DPI devices (1.5 pixels to the DIU)
- drawable-xhdpi (extra high) for 320 DPI devices (2 pixels to the DIU)
- drawable-xxhdpi (extra extra high) for 480 DPI devices (3 pixels to the DIU)
- drawable-xxxhdpi (three extra highs) for 640 DPI devices (4 pixels to the DIU)
For a bitmap intended to be rendered at one square inch, the various versions of the bitmap will have the same name but a different size, and be stored in these folders:
- drawable-ldpi/MyImage.jpg at 120 pixels square
- drawable-mdpi/MyImage.jpg at 160 pixels square
- drawable-hdpi/MyImage.jpg at 240 pixels square
- drawable-xhdpi/MyImage.jpg at 320 pixels square
- drawable-xxhdpi/MyImage.jpg at 480 pixels square
- drawable-xxxhdpi/MyImage.jpg at 640 pixels square
The bitmap will always render at 160 device-independent units. (The standard Xamarin.Forms solution template only includes the hdpi, xhdpi, and xxhdpi folders.)
The UWP project supports a bitmap naming scheme that consists of a scaling factor in pixels per device-independent unit as a percentage, for example:
- MyImage.scale-200.jpg at 320 pixels square
Only some percentages are valid. The sample programs for this book include only images with scale-200 suffixes, but current Xamarin.Forms solution templates include scale-100, scale-125, scale-150, and scale-400.
When adding bitmaps to the platform projects, the Build Action should be:
- iOS: BundleResource
- Android: AndroidResource
- UWP: Content
The ImageTap sample creates two button-like objects consisting of
Image elements with a
TapGestureRecognizer installed. It is intended that the objects be one-inch square. The
Source property of
Image is set using
On objects to reference potentially different filenames on the platforms. The bitmap images include numbers indicating their pixel size, so you can see which size bitmap is retrieved and rendered.
Toolbars and their icons
One of the primary uses of platform-specific bitmaps is the Xamarin.Forms toolbar, which is constructed by adding
ToolbarItem objects to the
ToolbarItems collection defined by
ToobarItem derives from
MenuItem from which it inherits some properties.
The most important
ToolbarItem properties are:
Textfor text that might appear depending on platform and
FileImageSourcefor the image that might appear depending on platform and
ToolbarItemOrder, an enumeration with three members,
The number of
Primary items should be limited to three or four. You should include a
Text setting for all items. For most platforms, only the
Primary items require an
Icon but Windows 8.1 requires an
Icon for all items. The icons should be 32 device-independent units square. The
FileImageSource type indicates that they are platform-specific.
Both iOS and Android require that a page that displays a toolbar be a
NavigationPage or a page navigated to by a
NavigationPage. The ToolbarDemo program sets the
MainPage property of its
App class to the
NavigationPage constructor with a
ContentPage argument, and demonstrates the construction and event handler of a toolbar.
The use of images on buttons has been enhanced. See Using bitmaps with buttons.