Xamarin.Tips – iOS Bar Background Images in Xamarin.Forms

Xamarin.Forms doesn’t ship with any way to provide images as your background of either NavigationBars or TabBars. So in order to do this, we will have to build some custom renderers.

iOS

Morgan skinner has a great post here about an approach that he took to apply background images to his NavigationBars: http://www.morganskinner.com/2015/01/xamarin-formsusing-background-images-on.html

The give you the synopsis, you take your entire background image, crop it, and apply the cropped piece as the background of the bar in your renderer.

Here’s a look at how he cropped his image:
Original Marked Up_thumb[5]

I want to take a different approach here and do this programmatically so that you can be EXACT in the background of the bar so that it can match the background of your image.

Although we are approaching this as if you are applying the background image to be the same as your page background image, the same principle applies if you just want to set any image.

Here’s a renderer to use for a NavigationBar:

BackgroundImageNavigationRenderer.cs

[assembly: ExportRenderer(typeof(NavigationPage), typeof(BackgroundImageNavigationRenderer))]
namespace YOUR_IOS_NAMESPACE
{
    public class BackgroundImageNavigationRenderer : NavigationRenderer
    {
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            View.BackgroundColor = UIColor.Clear;
            NavigationBar.BackgroundColor = UIColor.Clear;
            var image = UIImage.FromBundle("YOUR_PAGE_BACKGROUND_IMAGE.png");
            image = image.Crop(0,
                (int)(image.CGImage.Height - NavigationBar.Frame.Height),
                (int)image.CGImage.Width,
                (int)NavigationBar.Frame.Height);
            image = image.Scale(new CGSize(NavigationBar.Frame.Width, NavigationBar.Frame.Height));
            NavigationBar.BarTintColor = UIColor.FromPatternImage(image);
            NavigationBar.ShadowImage = new UIImage();
        }

    }
}

Breaking it down, we are taking the image that we use as the background for our entire page, then opening cropping it to the size of the NavigationBar itself.

I’ve also created an extension method called Crop so that we can reuse it here and for our UITabBar:

ImageExtensions.cs

    public static class ImageExtensions
    {
        public static UIImage Crop(this UIImage image, int x, int y, int width, int height)
        {
            var imgSize = image.Size;

            UIGraphics.BeginImageContext(new SizeF(width, height));
            var imgToCrop = UIGraphics.GetCurrentContext();

            var croppingRectangle = new CGRect(0, 0, width, height);
            imgToCrop.ClipToRect(croppingRectangle);

            var drawRectangle = new CGRect(-x, -y, imgSize.Width, imgSize.Height);

            image.Draw(drawRectangle);
            var croppedImg = UIGraphics.GetImageFromCurrentImageContext();

            UIGraphics.EndImageContext();
            return croppedImg;
        }

    }

Now, if you are not doing this to have a full background image, and just want some image for your UINavigationBar only, you can do so like this:

BackgroundImageNavigationRenderer.cs

[assembly: ExportRenderer(typeof(NavigationPage), typeof(BackgroundImageNavigationRenderer))]
namespace YOUR_IOS_NAMESPACE
{
    public class BackgroundImageNavigationRenderer : NavigationRenderer
    {
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            View.BackgroundColor = UIColor.Clear;
            NavigationBar.BackgroundColor = UIColor.Clear;
            var image = UIImage.FromBundle("YOUR_BAR_BACKGROUND_IMAGE.png");

            image = image.Scale(new CGSize(NavigationBar.Frame.Width, NavigationBar.Frame.Height));
            NavigationBar.BarTintColor = UIColor.FromPatternImage(image);
            NavigationBar.ShadowImage = new UIImage();
        }

    }
}

Essentially just cutting out the cropping process.

Also note that I set the NavigationBar.ShadowImage to a new UIImage();. Doing this gets rid of the line below your UINavigationBar. If you don’t want to remove the line, just don’t set the ShadowImage.

Now that we’ve done this for our UINavigationBar, we can apply the same thing to our UITabBars. So let’s create another custom renderer for that!

BackgroundImageTabbedPageRenderer.cs


[assembly: ExportRenderer(typeof(TabbedPage), typeof(BackgroundImageTabbedPageRenderer))]
namespace YOUR_IOS_NAMESPACE
{
    public class BackgroundImageTabbedPageRenderer : TabbedRenderer
    {
        public override void ViewWillLayoutSubviews()
        {
            base.ViewWillLayoutSubviews();

            var image = UIImage.FromBundle("YOUR_PAGE_BACKGROUND_IMAGE.jpg");
            image =image.Crop(0,
                (int)(image.CGImage.Height - TabBar.Frame.Height),
                (int)image.CGImage.Width,
                (int)TabBar.Frame.Height);
            image = image.Scale(new CGSize(TabBar.Frame.Width, TabBar.Frame.Height));
            TabBar.BackgroundImage = image;
            TabBar.UnselectedItemTintColor = UIColor.FromRGBA(255, 255, 255, 150);
            TabBar.ShadowImage = new UIImage();
        }

    }
}

just as we did with our UINavigationBar, we crop the page background image to the location and dimensions of our UITabBar, and set the background image there. The same thing also applies with removing the ShadowImage.

And if you are not using a full background image, and just want an image for your bar, take this:

BackgroundImageTabbedPageRenderer.cs


[assembly: ExportRenderer(typeof(TabbedPage), typeof(BackgroundImageTabbedPageRenderer))]
namespace YOUR_IOS_NAMESPACE
{
    public class BackgroundImageTabbedPageRenderer : TabbedRenderer
    {
        public override void ViewWillLayoutSubviews()
        {
            base.ViewWillLayoutSubviews();

            var image = UIImage.FromBundle("YOUR_PAGE_BACKGROUND_IMAGE.jpg");

            image = image.Scale(new CGSize(TabBar.Frame.Width, TabBar.Frame.Height));
            TabBar.BackgroundImage = image;
            TabBar.UnselectedItemTintColor = UIColor.FromRGBA(255, 255, 255, 150);
            TabBar.ShadowImage = new UIImage();
        }

    }
}

And now you can use full page images over your NavigationBars and TabBars, or just set an image as the background for your bars!

 

Simulator Screen Shot Apr 7, 2017, 11.23.33 AM

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Advertisements

3 thoughts on “Xamarin.Tips – iOS Bar Background Images in Xamarin.Forms”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s