Monthly Archives: December 2016

Listening to the Layout on Xamarin Android PageRenderer! (LayoutListener)

So when you create a Custom Renderer for your Xamarin Forms ContentPage, on Android, sometimes you have to tap into the Android Layout changes on your current page.

For instances like, Orientation changes, Keyboard visibility changes on Android and so on.

This is done by Adding a Layout Listener to our Layout’s ViewTree. 🙂 Confusing? Let’s get to work!

Create a Layout Listener…

First let’s create our Layout Listener, the guy who get’s the call back when the Layout Changes on the ViewTree of our Layout.

public class CustomLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
	public void OnGlobalLayout()
	{
		// do whatever the stuff you wanna do here
	}
}

 

We derive to from the IOnGlobalLayoutListener interface, where as you need to implement its OnGlobalLayout() method which get’s the call back when a Layout change occurs.

Add the Listener to the ViewTree…

Next add it to the ViewTreeObserver of your Layout.

[assembly: ExportRenderer(typeof(CustomContentPage), typeof(CustomContentPageRenderer))]
namespace WhateverYourNamespace
{
    public class CustomContentPageRenderer : PageRenderer
    {
        protected override async void OnElementChanged(ElementChangedEventArgs<Page> e)
        {
			var rootView = CrossCurrentActivity.Current.Activity.Window.DecorView.RootView;
			rootView.ViewTreeObserver.AddOnGlobalLayoutListener(new CustomLayoutListener());
		}
	}
}

 

Since I implemented this on a Xamarin Forms Custom Renderer, first I have gained access to the current Activity’s RootView (from a 3rd party library CurrentActivityPlugin) and then I have added my listener to the ViewTreeObserver of my root view. 😀

TADAA! 😀

but you could also…

Oh well good things comes to those who wait.. lol Xamarin Android provides you an event called GlobalLayout where you could also directly subscribe to Layout changes without having to implement your own listener.

rootView.ViewTreeObserver.GlobalLayout += (sender, args) =>
{
	// do whatever the stuff you wanna do here
}

 

Oh well it depends on your implementation requirement though.

Anyways there you have it! 😀

Enjoy!

Setting RelativeLayout ConstraintExpressions from XAML Styles in Xamarin Forms…

When it comes to Xamarin Forms RelativeLayout we always use Constraints, its pretty easy to add those Constraint values from C# code behind, but when it comes to XAML UI implementation, it’s not so easy.

so myself…

I have been working with XAML UI implementation for the last year or so, specially dealing with a lot of pixel perfect design, which needs a lot of customization to design from XAML. But as a developer you have to find ways to deal with those stuff. In my current project we practice a strict discipline of MVVM pattern, which we strongly separate XAML UI View and the ViewModel code. So under no exceptions we add any single C# UI code or XAML code behind implementations in our project.

complex design implementations…

When you have to deal with complex design implementations in Xamarin Forms, the best way to go is with RelativeLayout, along with Relative Constraint values for X/Y position and Height/Width values.

flag1

RelativeLayout is good…

Usually those RelativeLayout Constraint values manages to get the job done, with ease on both Android and iOS devices. But sometimes it doesn’t quite go right, specially with Android, where you have to deal with different types of screen resolutions.

layouts1

but sometimes…

So at times like that you need to specify RelativeLayout ConstraintExpression separately for iOS and Android devices. But how do you do this in XAML code?

so how?

So how do you set those ConstraintExpression right from XAML code? Styles is the answer! 😀

The trick is to create two different Styles for Android and iOS, targeting the control you need to set the RelativeLayout Constraints on.

And then on your control’s XAML declaration, you set the Style property using the OnPlatform tag accordingly for iOS and Android.

Let’s do it…

You could define these Styles on your Page level or Application level as you wish as shown below…

You can see I have created twp styles which targets the Label control type and added my Relative Layout ConstraintExpressions. 🙂 Also I have added the other Properties that I need to customize through these Styles.

<ContentPage.Resources>
	<ResourceDictionary>
		<Style x:Key="MyLabelStyleiOS" TargetType="Label">
		  <Setter Property="BackgroundColor" Value="Yellow"/>
		  <Setter Property="HorizontalTextAlignment" Value="Center"/>
		  <Setter Property="RelativeLayout.YConstraint" 
				  Value="{ConstraintExpression RelativeToParent,Property=Height,Factor=0.5}"/>
		  <Setter Property="RelativeLayout.WidthConstraint"
				  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.7}"/>
		  <Setter Property="RelativeLayout.XConstraint"
				  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.15}"/>
		</Style>

		<Style x:Key="MyLabelStyleAndroid" TargetType="Label">     
		  <Setter Property="BackgroundColor" Value="Yellow"/>
		  <Setter Property="HorizontalTextAlignment" Value="Center"/>
		  <Setter Property="RelativeLayout.YConstraint"
				  Value="{ConstraintExpression RelativeToParent,Property=Height,Factor=0.1}"/>
		  <Setter Property="RelativeLayout.WidthConstraint"
				  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.7}"/>
		  <Setter Property="RelativeLayout.XConstraint"
				  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.15}"/>
		</Style>
	</ResourceDictionary>
</ContentPage.Resources>

 

And then on the your Control that you need to set those RelativeLayout Constraints…

<Label Text="Welcome to the app!"  >
	<Label.Style>
	  <OnPlatform x:TypeArguments="Style"
				  iOS="{StaticResource MyLabelStyleiOS}"
				  Android="{StaticResource MyLabelStyleAndroid}" />
	</Label.Style>
</Label>

 

You can see how I have nested down the Style property and added the specific style according to the Platform type.

It’s very important to notice that I have added those Styles as StaticResource this is because we need to set those RelativeLayout ConstraintExpressions before the run time, while the XAML are being parsed. 🙂 Once the XAML layout is parsed, we can not set the ConstraintExpressions, since it’s not going to be rendered.

make it pretty… Generalize!

Yep the above styles are ugly, so let’s generalize it and move the common properties and constraints to a general style as below, and derive our child styles.

<Style x:Key="MyLabelStyle" TargetType="Label">
  <Setter Property="BackgroundColor" Value="Yellow"/>
  <Setter Property="HorizontalTextAlignment" Value="Center"/>
  <Setter Property="RelativeLayout.WidthConstraint"
		  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.7}"/>
  <Setter Property="RelativeLayout.XConstraint"
		  Value="{ConstraintExpression RelativeToParent,Property=Width,Factor=0.15}"/>
</Style>

<Style x:Key="MyLabelStyleiOS" TargetType="Label" BasedOn="{StaticResource MyLabelStyle}">
  <Setter Property="RelativeLayout.YConstraint" 
		  Value="{ConstraintExpression RelativeToParent,Property=Height,Factor=0.5}"/>
</Style>

<Style x:Key="MyLabelStyleAndroid" TargetType="Label" BasedOn="{StaticResource MyLabelStyle}">
  <Setter Property="RelativeLayout.YConstraint"
		  Value="{ConstraintExpression RelativeToParent,Property=Height,Factor=0.1}"/>
</Style>

 

There we go! now that’s beautiful. Always keep in mind to generalize the common Style properties, and here in this case the common ConstraintExpression values. 🙂

Cheers! 😀

How to add a fixed Background Image for a UIScrollView?

So recently I wanted to add a Fixed image behind a ScrollView in Xamarin Forms. Furthermore when the ScrollView is scrolling the background image shouldn’t scroll along with it, and background image should stay fixed while the content is scrolling.

Solution?

So the obvious solution would be to lay down a RelativeLayout and top of that Image, and then a ScrollView with Transparent background.

But I wanted…

but instead of laying out all those layouts and multiple controls, I wanted to achieve this right from one Control, by customizing the ScrollView accordingly.

So I got to into Coding…

So I created a Custom ScrollView control in PCL project and added the Custom Renderers for each platform iOS and Android. Although I got it working with ease in on Android by setting the Image as the Background drawable for the ScrollView, I was having some struggle with iOS.

trouble with iOS UIScrollView…

So the Xamarin Forms ScrollView’s native iOS mapped control is the UIScrollView. So I tried adding the a UIImageView to the UIScrollView from the custom renderer hoping it should get the job done according to theory.

but the background was panning across the Content size. And it started scrolling alone with the Content.

So let me walk you through what I tried and what actually worked… 🙂

1. Adding the UIImageView as a SubView

So as per the obvious solution I added the UIImage into a UIImageView and added it into the UIScrollView as a SubView as shown below. Also you may have noticed how I have called SendSubviewToBack method to place the UIImageView behind the UIScrollView.

protected override async void OnElementChanged(VisualElementChangedEventArgs e)
{
	base.OnElementChanged(e);

	if (e.NewElement != null)
	{
		var _uiImageViewBackground = new UIImageView(_uiImageBackground);

		this.AddSubview(_uiImageViewBackground);
		this.SendSubviewToBack(_uiImageViewBackground);
	}
}

 

And this was the result as you can see below..

method1

As you can see the UIImageView takes up the Height of the UIScrollView Content, not the UIScrollView actual Height, thereby resulting of the UIImageView spanning across the whole Content size. :O

2. Resizing the UIImage and adding the UIImageView as a SubView

Then I thought what if I resized the Image to the actual Height and Width of the UIScrollView and added as a Subview as show below.

Now in an iOS Custom Renderer we can not access the UIScrollView’s Bounds or Frame right from the OnElementChanged method, we need to override the Draw() method, which provides the Height and Width since it’s actually being drawn on the Parent view.

public override void Draw(CGRect rect)
{
	base.Draw(rect);

	// resize the UIImage to fit the current UIScrollView's width and height
	_uiImageBackground = ResizeUIImage(_uiImageBackground, (float)rect.Width, (float)rect.Height);

	var _uiImageViewBackground = new UIImageView(_uiImageBackground);

	this.AddSubview(_uiImageViewBackground);
	this.SendSubviewToBack(_uiImageViewBackground);
}

 

So as you can see I have resized the UIImage and added it to the UIScrollView thought a UIImageView holder.

Look at the results…

method2

Well the Background Image has been resized but the Background View still scrolls with the Content of UIScrollView. 😦

3. How about InsertSubview() ?

There are couple of methods for Adding a SubView to a View, the most common used one is the AddSubView() method which is also an alias for Add().

Then there also another method call we could use, InsertSubview(). In theory it does the same thing as AddSubView() but in a different manner where you could define a View index, in terms of which index the View should be added to in the array of sub-views in the given View.

So instead of this,

this.AddSubview(_uiImageViewBackground);
this.SendSubviewToBack(_uiImageViewBackground);

 

Let’s call the below, as you can see I’m placing our UIImageView at the very bottom of the SubViews stack by giving index 0 value.

this.InsertSubview(_uiImageViewBackground, 0);

 

Oh well what did you expect! Same result as before. 😦

4. How about InsertSubviewBelow() ?

So this method is also somewhat similar to above, where as this allows you to straightaway as a Subview, and define underneath which SubView you need to add your View in the stack. 😀

So I tried this as well. By the “this” reference I’m referring to the UIScrollView as the sibling and to tell the layout engine to place the UIImageView below the UIScrollView. 🙂

this.InsertSubviewBelow(_uiImageViewBackground, this);

 

But unfortunately the results was the same… 😦

5. What about directly setting the Background?

Frustrated with trying to add SubViews approach, I thought of directly setting the Background property of UIScrollView, specifically set the UIImage directly to the BackgroundColor Property of UIScrollView.

Well there’s no way we could set the BackgroundColor property from the Draw() method override, hence the canvas is already drawn. So we need to set it before its being drawn.

So let’s move back to the OnElementChanged method and set the BackgroundColor.

Since there’s no availability of the Height and Width values within the OnElementChanged event firing, for now we’ll just directly set the UIImage to BackgroundColor without resizing.

protected override async void OnElementChanged(VisualElementChangedEventArgs e)
{
	base.OnElementChanged(e);

	if (e.NewElement != null)
	{
			this.BackgroundColor = UIColor.FromPatternImage(_uiImageImageBackground);
	}
}

 

Oh well, look at the results. It also fills up the whole Content area, without just setting the “background” on UIScrollView.

method3

5. What about directly setting the Background with resized UIImage?

Alright now let’s get a bit serious and retry the above approach properly, by accessing the Height and Width of the UIScrollView and resizing the UIImage accordingly.

So to do this we need to tap into the place where the Height and Width first gets allocated before the Draw method. That’s by subscribing to the OnPropertyChanged() as shown below.

protected override async void OnElementChanged(VisualElementChangedEventArgs e)
{
	base.OnElementChanged(e);

	if (e.NewElement != null)
	{
		((CustomScrollView)e.NewElement).PropertyChanged += OnPropertyChanged;
	}
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
	if (propertyChangedEventArgs.PropertyName == CustomScrollView.HeightProperty.PropertyName)
	{
		// check if the Width and Height are assigned
		if (((CustomScrollView)sender).Width > 0 & ((CustomScrollView)sender).Height > 0)
		{
			// resize the UIImage to fit the current UIScrollView's width and height
			_uiImageImageBackground = ResizeUIImage(_uiImageImageBackground, (float)((CustomScrollView)sender).Width, (float)((CustomScrollView)sender).Height);

			// Set the background Image
			this.BackgroundColor = UIColor.FromPatternImage(_uiImageImageBackground);
		}
	}
}

 

So inside the OnPropertyChanged() event we are waiting till the Width and Height properties are available, as you can see we are looking for the PropertyName in the event args. Then we resize the UIImage according to the retrieved Height and Width and values of UIScrollView and set the UIImage to the Background.

method4

Now as you can see, the Background Image gets resized to the exact size of UIScrollView but the Background is still scrolling with the content. And if you notice closely, you can see the Background has repeated the Image, this is because of the UIColor.FromPatternImage() where as the UIImage gets repeated to fill the whole canvas. This means that the Background still gets spread across the whole Content area of the UIScrollView.

then I witnessed something strange….

What actually worked… (strangely though)

So meanwhile playing around with different override methods and properties, at some point….

I accidentally left the Draw() method overridden in my Custom Renderer as shown below, and moved the setting of the UIScrollView Background to the OnPropertyChanged event like I did in the previous step.

protected override async void OnElementChanged(VisualElementChangedEventArgs e)
{
	base.OnElementChanged(e);

	if (e.NewElement != null)
	{
		((CustomScrollView)e.NewElement).PropertyChanged += OnPropertyChanged;
	}
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
	if (propertyChangedEventArgs.PropertyName == CustomScrollView.HeightProperty.PropertyName)
	{
		// check if the Width and Height are assigned
		if (((CustomScrollView)sender).Width > 0 & ((CustomScrollView)sender).Height > 0)
		{
			// resize the UIImage to fit the current UIScrollView's width and height
			_uiImageImageBackground = ResizeUIImage(_uiImageImageBackground, (float)((CustomScrollView)sender).Width, (float)((CustomScrollView)sender).Height);

			// Set the background Image
			this.BackgroundColor = UIColor.FromPatternImage(_uiImageImageBackground);
		}
	}
}

//We need to override this to have the background image to be fixed
public override void Draw(CGRect rect)
{
	base.Draw(rect);
}

 

As you can see in my above code, I have just overriden the Draw() event and left it just as it is, without writing any code inside the method.

And behold! 😀 IT WORKED! 😀

bloopscrollview-on-ios-lowq

TADAA! 😀 as you can see we have successfully got it to work, a fixed background image in UIScrollView. 😉

Although this does not make any sense, how could the Background of the UIScrollView prevents itself from scaling to the size of Content size just by simply overriding the Draw() event, without even executing any code inside of it.

Either way this trick got the work done. 😀 May be this is just a bug in Xamarin or iOS. 😛

There you have it, how to add a fixed background image to a UIScrollView from custom renderer in Xamarin! 🙂

Enjoy!

An improved ScrollView control for Xamarin Forms by me, myself and I…

Alright now when it comes to the default Xamarin Forms ScrollView, its pretty much generic and limited with the simple common attributes and behaviours, and it does not deliver any specific “cool” features with it.

What’s so cool about it?

So I thought of creating my own Custom ScrollView for Xamarin Forms using Custom Renderers, which would include the following awesome features,

Bouncy Effect – Yeah you gotta admit, the bounce effect of a native scrollview is pretty fun to play with, in a User’s perspective. So I thought of enabling this feature in my custom ScrollView even when the Child Element doesn’t exceeds the ScrollView boundaries… 😉
(PS: this effect is interpreted in native Android and iOS differently)

Disabling and Enabling Horizontal and Vertical Scroll Indicators – Now sometimes these scroll bar indicators are useful but there are times which we want to hide them, as it might look ugly on the UI in certain cases. So yeah let’s have some control over it shall we? 😀

Background Image – Of course who wouldn’t like a background Image on a Scroll view eh! 😉 Well to be specific we are going to add a Fixed Background Image for the ScrollView. And note that this background Image would be fixed, and will not be scrolling with the Content of the ScrollView. (I will do another post to enable that feature).

Yes behold, me, myself and I presenting the “BloopyScrollView” why the name “BloopyScrollView”? I don’t even know. lol 😛

Implementation

Alright let’s go ahead and create our Custom ScrollView Control in the PCL project. Along with the following properties, so that we could have direct control over the above said behaviours.

Alright now expect this to be longer, since I have added the properties as Bindable Properties, so you could use them in any MVVM scenario with ease. 😀

namespace WhateverYourNamespace
{
    public class BloopyScrollView : ScrollView
    {
        public static readonly BindableProperty IsHorizontalScrollbarEnabledProperty =
        BindableProperty.Create(
            nameof(IsHorizontalScrollbarEnabled),
            typeof(bool),
            typeof(BloopyScrollView),
            false,
            BindingMode.Default,
            null);
        /// <summary>
        /// Gets or sets the Horizontal scrollbar visibility
        /// </summary>
        public bool IsHorizontalScrollbarEnabled
        {
            get { return (bool)GetValue(IsHorizontalScrollbarEnabledProperty); }
            set { SetValue(IsHorizontalScrollbarEnabledProperty, value); }
        }


        public static readonly BindableProperty IsVerticalScrollbarEnabledProperty =
        BindableProperty.Create(
            nameof(IsVerticalScrollbarEnabled),
            typeof(bool),
            typeof(BloopyScrollView),
            false,
            BindingMode.Default,
            null);
        /// <summary>
        /// Gets or sets the Vertical scrollbar visibility
        /// </summary>
        public bool IsVerticalScrollbarEnabled
        {
            get { return (bool)GetValue(IsVerticalScrollbarEnabledProperty); }
            set { SetValue(IsVerticalScrollbarEnabledProperty, value); }
        }


        public static readonly BindableProperty IsNativeBouncyEffectEnabledProperty =
        BindableProperty.Create(
            nameof(IsNativeBouncyEffectEnabled),
            typeof(bool),
            typeof(BloopyScrollView),
            true,
            BindingMode.Default,
            null);
        /// <summary>
        /// Gets or sets the Native Bouncy effect status
        /// </summary>
        public bool IsNativeBouncyEffectEnabled
        {
            get { return (bool)GetValue(IsNativeBouncyEffectEnabledProperty); }
            set { SetValue(IsNativeBouncyEffectEnabledProperty, value); }
        }


        public static readonly BindableProperty BackgroundImageProperty =
        BindableProperty.Create(
            nameof(BackgroundImage),
            typeof(ImageSource),
            typeof(BloopyScrollView),
            null,
            BindingMode.Default,
            null);
        /// <summary>
        /// Gets or sets the Background Image of the ScrollView
        /// </summary>
        public ImageSource BackgroundImage
        {
            get { return (ImageSource)GetValue(BackgroundImageProperty); }
            set { SetValue(BackgroundImageProperty, value); }
        }
    }
}

 

There we go IsHorizontalScrollbarEnabled, IsVerticalScrollbarEnabled to disable/enable Horizonal and Vertical Scrollbars.

IsNativeBouncyEffectEnabled to control the Native Bouncy effect.

BackgroundImage to set the ImageSource for the ScrollView’s background Image. And make sure to provide a proper image for this hence we will be resizing the given image in our native renderer level to fit to the background of the ScrollView.(You will see in the next steps below)

Alright let’s head over to creating the Custom Renderers associated with our BloopyScrollView.

Something to keep in mind…

So if you’re a frequent reader of my blog, you may remember sometime ago I created an Extention class for handling Xamarin Forms Images in Native code level: https://theconfuzedsourcecode.wordpress.com/2016/12/12/an-awesome-image-helper-to-convert-xamarin-forms-imagesource-to-ios-uiimage-or-android-bitmap/

Why I’m bringing this up, is because we are going to be needing it for this project. You ask why? Because we need to convert the above BackgroundImage, which is of type Xamarin Forms ImageSource.

So we need to convert that ImageSource to native UIImage or Bitmap image respectively in our Custom renderer levels. 😉

So go ahead and grab that code real quick and add it to your Native Projects. 😀

iOS Implementation

Now let’s create the Custom Renderer for the Control in Xamarin.iOS project.

[assembly: ExportRenderer(typeof(BloopyScrollView), typeof(BloopyScrollViewRenderer))]
namespace WhateverYourNamespace.iOS
{
    public class BloopyScrollViewRenderer : ScrollViewRenderer
    {
        private UIImage _uiImageImageBackground;

        protected override async void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            this.ShowsVerticalScrollIndicator = ((BloopyScrollView)e.NewElement).IsVerticalScrollbarEnabled;
            this.ShowsHorizontalScrollIndicator = ((BloopyScrollView)e.NewElement).IsHorizontalScrollbarEnabled;

            if (e.NewElement != null)
            {
                if (((BloopyScrollView)e.NewElement).IsNativeBouncyEffectEnabled)
                {
                    this.Bounces = true;
                    this.AlwaysBounceVertical = true;
                }

                if (((BloopyScrollView)e.NewElement).BackgroundImage != null)
                {
                    // retrieving the UIImage Image from the ImageSource by converting
                    _uiImageImageBackground = await IosImageHelper.GetUIImageFromImageSourceAsync(((BloopyScrollView)e.NewElement).BackgroundImage);
                }

                ((BloopyScrollView)e.NewElement).PropertyChanged += OnPropertyChanged;
            }
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            if (propertyChangedEventArgs.PropertyName == BloopyScrollView.HeightProperty.PropertyName)
            {
                // check if the Width and Height are assigned
                if (((BloopyScrollView)sender).Width > 0 & ((BloopyScrollView)sender).Height > 0)
                {
                    // resize the UIImage to fit the current UIScrollView's width and height
                    _uiImageImageBackground = ResizeUIImage(_uiImageImageBackground, (float)((BloopyScrollView)sender).Width, (float)((BloopyScrollView)sender).Height);

                    // Set the background Image
                    this.BackgroundColor = UIColor.FromPatternImage(_uiImageImageBackground);
                }
            }
        }

        // We need to override this to have the background image to be fixed
        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
        }

        // Resize the UIImage
        public UIImage ResizeUIImage(UIImage sourceImage, float widthToScale, float heightToScale)
        {
            var sourceSize = sourceImage.Size;
            var maxResizeFactor = Math.Max(widthToScale / sourceSize.Width, heightToScale / sourceSize.Height);
            if (maxResizeFactor > 1) return sourceImage;
            var width = maxResizeFactor * sourceSize.Width;
            var height = maxResizeFactor * sourceSize.Height;
            UIGraphics.BeginImageContext(new CGSize(width, height));
            sourceImage.Draw(new CGRect(0, 0, width, height));
            var resultImage = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return resultImage;
        }
    }
}

 

Inside the method we are assigning the relevant properties of our BloopyScrollView to the native control properties.

The UIScrollView which is associated with the Xamarin Forms ScrollView has the following native properties:

  • ShowsVerticalScrollIndicator: Make the vertical scrollbar visible or hidden
  • ShowsHorizontalScrollIndicator: Make the horizontal scrollbar visible or hidden
  • Bounces: Always enable the native bounce effect on iOS UIScrollView
  • BackgroundColor: Allows to set the background color for the UIScrollView or set an Image as a pattern

Also you may have noted that we are converting our Image Source BackgroundImage to a UIImage using our extension.

And then when the Height and Width are set to the Control, we are resizing the Image to fit those properties and setting that as the Background of the UIScrollView through the UIColor.FromPatternImage() which allows us to set the image as a pattern throughout the canvas of the UIScrollView.

the strange tale of getting the UIScrollView’s Fixed background in Xamarin… :O

Notice that we are overriding the Draw(CGRect rect) method, this is to have the UIScroll Background Image to be fixed within the boundaries, and not to be spanned across the Content area.

Because usually if we set the BackgroundColor property, it will span across the Content area, but strangely if we override the Draw() method, BackgroundColor would only be contained within UIScrollView’s boundaries, without spanning across the Content area. This is something I figured out while playing around with the above implementation. 😀

Alright let’s jump into Android… 😀

Android Implementation

Now let’s create the Custom Renderer for the Control in Xamarin.Android project.

[assembly: ExportRenderer(typeof(BloopyScrollView), typeof(BloopyScrollViewRenderer))]
namespace WhateverYourNamespace.Droid
{
    public class BloopyScrollViewRenderer : ScrollViewRenderer
    {
        private Bitmap _bitmapImageBackground;

        protected override async void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            this.VerticalScrollBarEnabled = ((BloopyScrollView)e.NewElement).IsVerticalScrollbarEnabled;
            this.HorizontalScrollBarEnabled = ((BloopyScrollView)e.NewElement).IsHorizontalScrollbarEnabled;

            if (((BloopyScrollView)e.NewElement).IsNativeBouncyEffectEnabled)
            {
                this.OverScrollMode = OverScrollMode.Always;
            }

            if (((BloopyScrollView) e.NewElement).BackgroundImage != null)
            {
                // retrieving the Bitmap Image from the ImageSource by converting
                _bitmapImageBackground = await AndroidImageHelper.GetBitmapFromImageSourceAsync(((BloopyScrollView)e.NewElement).BackgroundImage, this.Context);

                // resize the Bitmap to fit the current ScrollView's width and height
                var _resizedBitmapImageBackground = new BitmapDrawable(ResizeBitmap(_bitmapImageBackground, this.Width, this.Height));

                // Set the background Image
                this.Background = _resizedBitmapImageBackground;
            }
        }

        // Resize the Bitmap
        private Bitmap ResizeBitmap(Bitmap originalImage, int widthToScae, int heightToScale)
        {
            Bitmap resizedBitmap = Bitmap.CreateBitmap(widthToScae, heightToScale, Bitmap.Config.Argb8888);

            float originalWidth = originalImage.Width;
            float originalHeight = originalImage.Height;

            Canvas canvas = new Canvas(resizedBitmap);

            float scale = this.Width / originalWidth;

            float xTranslation = 0.0f;
            float yTranslation = (this.Height - originalHeight * scale) / 2.0f;

            Matrix transformation = new Matrix();
            transformation.PostTranslate(xTranslation, yTranslation);
            transformation.PreScale(scale, scale);

            Paint paint = new Paint();
            paint.FilterBitmap = true;

            canvas.DrawBitmap(originalImage, transformation, paint);

            return resizedBitmap;
        }
    }
}

 

The Android ScrollView which is associated with the Xamarin Forms ScrollView has the following native properties:

  • VerticalScrollBarEnabled: Make the vertical scrollbar visible or hidden
  • HorizontalScrollBarEnabled: Make the horizontal scrollbar visible or hidden
  • OverScrollMode: Always enable the native bounce effect on Android ScrollView
  • Background: Allows to set the background drawable for the ScrollView

As you may have noticed we are converting our Xamarin Forms Image Source BackgroundImage to a Bitmap image using our extension.

Then we are resizing out Bitmap image according to the Width and Height of the ScrollView to fit to the full background to be wrapped around a BitmapDrawable and set to the Background of ScrollView.

There you go! 😀

Let’s use it… 😉

Alright now that’s done, let’s consume this in our PCL project.

<StackLayout Padding="10,0,10,0">

	<Label Text="Welcome to Xamarin Forms!"
		   VerticalOptions="Center"
		   HorizontalOptions="Center" />

	<local:BloopyScrollView 
	IsNativeBouncyEffectEnabled="True"
	IsVerticalScrollbarEnabled="False"
	IsHorizontalScrollbarEnabled="False">
	<local:BloopyScrollView.BackgroundImage>
	  <FileImageSource File="xamarinBackgroundImage.png"/>
	</local:BloopyScrollView.BackgroundImage>
	
			<Label
			  FontSize="22"
			  HeightRequest="400"
			  Text=
			  "Whatever your text content to be displayed." />
			  
	</local:BloopyScrollView>

</StackLayout>

 

As you can see I have inserted my BloopyScrollView in a StackLayout and as the content of the ScrollView I have added Label. Well you can add any content you want or set any Height or Width as you wish.

Notice that I have set IsNativeBouncyEffectEnabled to be True as I want to see the native Bouncy effect. Then I have disabled the Vertical and Horizontal Scrollbars from the properties we added earlier. Then finally I have added the BackgroundImage and set the FileImageSource to the ImageSource type, where as I have placed the image in the native Resource folder, as you would do with any defualt Xamarin Forms Image. 😉

Now let’s see the results… 😀

bloopscrollview-on-ios-lowq  bloopscrollview-on-android-lowq

Yaay! 😀

As we expected the Vertical and Horizontal Scrollbars are disabled and our ScrollView has full native bouncy effect accordingly.

Also you can see the Background Image nicely resized itself and fit to the background of the BloopyScrollView. 😀

Happy dance! lol

Recap Stuff…

Now there’s some stuff I wanted to recap, that is you may have noticed that when I was resizing the Image, I needed the Control’s Height and Width, and where I have acquired those properties are in two different places on each Android and iOS renderers.

To be specific I have accessed the Control’s Width and Height on Android right from the OnElementChanged method, but on iOS renderer I have accessed those values from the  OnPropertyChanged method’s Height property event. 

This is because of the differences of the Rendering cycling of Android and iOS, whereas on Android right at the firing of the Custom Renderer it assigns itself Width and Height. But on iOS we have to access them indirectly by waiting till those properties are set, by listening to the OnPropertyChanged event.

Get it on Github! 😀 XFImprovedScrollView

Cheers everyone!

Pass this on to another developer to make them smile! 😀
– Udara Alwis

Let’s resize a Bitmap and UIImage with Xamarin…

Since the beginning of computers, developers has been struggled with Images. So did I with Xamarin 😉

So here I am sharing my findings on resizing a Bitmap and UIImage respectively on Android and iOS, meanwhile preserving the aspect ratio. I’m sharing this for the ease of fellow Xamarin devs, if anyone is struggling to find a source to find solution for both Xamarin Android and iOS platforms.

Xamarin Android

Alright here goes resizing of a Bitmap on Xamarin Android, and please note that I merely convered this implementation from Java to C# when I was implementing it in my project, and here’s the reference for it : http://stackoverflow.com/a/8224161

You need to pass in the height and width you need to resize your Bitmap into. Also as you can see this resizing method scales up the Bitmap on the Y Axis, and scaling begins from the center of the Image. 🙂

private Bitmap ResizeBitmap(Bitmap originalImage, int widthToScae, int heightToScale)
{
	Bitmap resizedBitmap = Bitmap.CreateBitmap(widthToScae, heightToScale, Bitmap.Config.Argb8888);

	float originalWidth = originalImage.Width;
	float originalHeight = originalImage.Height;

	Canvas canvas = new Canvas(resizedBitmap);

	float scale = this.Width / originalWidth;

	float xTranslation = 0.0f;
	float yTranslation = (this.Height - originalHeight * scale) / 2.0f;

	Matrix transformation = new Matrix();
	transformation.PostTranslate(xTranslation, yTranslation);
	transformation.PreScale(scale, scale);

	Paint paint = new Paint();
	paint.FilterBitmap = true;

	canvas.DrawBitmap(originalImage, transformation, paint);

	return resizedBitmap;
}

 

Xamarin iOS

So below is what I used for UIImage on iOS, which I was lucky enough to find through the Xamarin Forum: https://forums.xamarin.com/discussion/comment/175585/#Comment_175585 So kudos to the original post! 🙂

public UIImage ResizeUIImage(UIImage sourceImage, float widthToScale, float heightToScale)
{
	var sourceSize = sourceImage.Size;
	var maxResizeFactor = Math.Max(widthToScale / sourceSize.Width, heightToScale / sourceSize.Height);
	if (maxResizeFactor > 1) return sourceImage;
	var width = maxResizeFactor * sourceSize.Width;
	var height = maxResizeFactor * sourceSize.Height;
	UIGraphics.BeginImageContext(new CGSize(width, height));
	sourceImage.Draw(new CGRect(0, 0, width, height));
	var resultImage = UIGraphics.GetImageFromCurrentImageContext();
	UIGraphics.EndImageContext();
	return resultImage;
}

 

Well there you have it.

Enjoy! 😀

An awesome Image Helper to convert Xamarin Forms ImageSource to iOS UIImage or Android Bitmap…

The default Xamarin Forms ImageSource is good, but it doesn’t provide all the properties of an Image, not as much as native Image types of Android or iOS. This is why sometimes we need to drill down to the native level of Image handling sometimes, specially when you’re dealing with Custom Renderers, or complex Image manipulation stuff in Xamarin.

So yeah it’s no surprise you will run into the need of converting the default Xamarin Forms ImageSource to native Image type in iOS and Android, respectively UIImage or Bitmap types.

Well I know I did. lol 😛

How ? 😮

So how could you do this ? Well, something intermediate for both Xamarin Forms ImageSource and the native Image types is the byte[] array. 🙂 But I’m gonna take a pass on it, since it’s too much of trouble and process, which could lead to bad memory consumption. 😦 Instead, why don’t we deal with this straight away. 😀

This is how I did it.. 😉

Now when it comes to Xamarin Forms almost everything is handled by drilling down to the native levels of the platform. Likewise ImageSource  during the runtime is handled through three types of Native Handlers that are as follows,

  • ImageLoaderSourceHandler
  • FileImageSourceHandler
  • StreamImagesourceHandler

Now for each Native environment, these handlers implements a LoadImageAsync() method, which loads the type of Native Type image for a given ImageSource.

This is usually done under the hood, but we need to access this same functionality on the go for our own requirements, so let’s do it by our own implementation.

Let’s create our Android Image Helper…

So we are going to create a Public class with static methods that could be used as extension methods in our Native Project levels. So go ahead and create the AndroidImageHelper class in your Xamarin.Android project level.

sameple

 

public class AndroidImageHelper
{
	private static IImageSourceHandler GetHandler(ImageSource source)
	{
		IImageSourceHandler returnValue = null;
		if (source is UriImageSource)
		{
			returnValue = new ImageLoaderSourceHandler();
		}
		else if (source is FileImageSource)
		{
			returnValue = new FileImageSourceHandler();
		}
		else if (source is StreamImageSource)
		{
			returnValue = new StreamImagesourceHandler();
		}
		return returnValue;
	}

	/// <summary>
	/// For converting Xamarin Forms ImageSource object to Native Image type
	/// </summary>
	/// <param name="source"></param>
	/// <param name="context"></param>
	/// <returns></returns>
	public static async Task<Bitmap> GetBitmapFromImageSourceAsync(ImageSource source, Context context)
	{
		var handler = GetHandler(source);
		var returnValue = (Bitmap)null;

		returnValue = await handler.LoadImageAsync(source, context);

		return returnValue;
	}
}

 

Alright there we go, as you would have expected we are using the native level Handlers of the ImageSource and retrieving the native image type as I explained earlier through the LoadImageAsync() method. Of course you need to pass a reference of your current Context since Android requires the context reference to almost every execution related to the UI stuff.

First we are getting the GetHandler type by the ImageSource, then we are calling the method above to retrieve the Bitmap image and returns back to the caller.

Let’s create our iOS Image Helper…

So just like on Android let’s do the same on iOS and create the public class IosImageHelper in your Xamarin Forms iOS project level.

sameple

public class IosImageHelper
{
	private static IImageSourceHandler GetHandler(ImageSource source)
	{
		IImageSourceHandler returnValue = null;
		if (source is UriImageSource)
		{
			returnValue = new ImageLoaderSourceHandler();
		}
		else if (source is FileImageSource)
		{
			returnValue = new FileImageSourceHandler();
		}
		else if (source is StreamImageSource)
		{
			returnValue = new StreamImagesourceHandler();
		}
		return returnValue;
	}

	/// <summary>
	/// For converting Xamarin Forms ImageSource object to Native Image type
	/// </summary>
	/// <param name="source"></param>
	/// <returns></returns>
	public static async Task<UIImage> GetUIImageFromImageSourceAsync(ImageSource source)
	{
		var handler = GetHandler(source);
		var returnValue = (UIImage)null;

		returnValue = await handler.LoadImageAsync(source);

		return returnValue;
	}

}

 

So here also we are using the same implementation as we used on Android, instead the LoadImageAsync() returns an UIImage.

Now let’s use it… 😉

Alright let’s see how to use these extensions in our code. 🙂

// Useage in iOS

UIImage _uiImageconverted = await IosImageHelper.GetUIImageFromImageSourceAsync(yourImageSourceObject);

// Useage in Android

Bitmap _bitmapImageconverted = await AndroidImageHelper.GetBitmapFromImageSourceAsync(yourImageSourceObject, this.Context);

 

There you have it, now you have your Xamarin Forms ImageSource converted to the given Native Image type, either iOS UIImage or Android Bitmap Image type. 😀

Enjoy! 😀

Cheers everyone!

Why MVVM is Awesome!

I used to be a code behind event driven loving developer! but since I found MVVM, I never looked back, MVVM all the way!

From Code-behind Event-driven addict to MVVM fanatic…

So for a developer who’s coming from a code behind event based implementation loving developer, I understand, adopting MVVM to your application could be pretty confusing and hectic at the beginning!

Because I know it very well by my own experience, whereas I used to be a stubborn noob developer in the good old days thinking Event Driven WinForms approach is the best way to developer software. Which led me to suffocate massively when the code base got bigger and bigger, having massive hard time debugging, maintaining and even upgrading programs I was coding. Honestly I couldn’t understand the cause for this at the beginning due to my stubborn mindset of praising code-behind even driven programming style.

Step 1:

Then when I got into my career I had to force myself to start using MVVM based implementation. And yes it was super confusing and troublesome to understand.

Step 2:

But trust me after a while, step by step,  you start to see how fun it is, makes you feel like wiring up some electronic circuit to get it to work, how all those components gets wired up each other while still having the modules separately.

Step 3:

And you will notice how easy it is to maintain and extend your code base… 😉

Short and sweet,

MVVM stands for Model View View-Model

and it’s AWESOME!

Here is why?

  • MVVM enable true separation between your User Interface(Views) and Logical Code(ViewModel/ Model)! Yes decoupling is ghuuud!
  • Easily handle events with Commands – ICommand
  • Never underestimate the power of INotifyPropertyChanged
  • Take the best use of Binding (View to ViewModel properties)
  • With ViewModel you can easily manipulate Model’s data as you wish and set them to be bound to any Views as you wish and vice versa. Yes it’s that flexible!
  • Yes, the ultimate portability of your project’s components
  • Testing made super easy as the separation between UI and Code behind logic
  • Extremely ease of maintenance and adding changes to your code base

So there you go, a short and sweet post I made during my free time! 😀

hope it helped anyone or may be inspired someone to make the switch! 😉

How to deal with Implementing an iOS optimized UI design on Android with Xamarin Forms?

When it comes to Cross-Platform mobile development, it is very crucial to have Screen Design concepts that are compatible for all the targeting platforms (Android/iOS/WinPhone), or at least to have separate Screen Designs for targeting platforms, when you’re using a platform such as Xamarin Forms (allowing you to develop apps with Native Look and Feels).

but…

What if you are out of luck in such requirements? What if as the developer you’re only given the Design Screens that only optimizes for one specific mobile platform?

and worst…

You’re expected implement the same design for both Android and iOS regardless of the design’s optimization?

my story…

Let me put it this way,

the project I’m currently working is a Cross-Platform Mobile Application building on top of Xamarin Forms. I am given a bunch of Design Screens that are optimized for iOS UI patterns, and my seniors wants me to implement the same UI Design for Android as well, regardless of the Android UI patterns.

So despite Xamarin Forms gives Native Look and Feels I am asked to implement the same design that are optimized for iOS into Android regardless of Android UX patterns.

Oh well.. look at that, so mostly to go against the Android UI Design best practices, just implement the iOS optimized design straightaway. (Well my UX Lead seems to be an iOS geek) 😛

Well this would have been better if we were developing on a Hybrid framework which uses HTML5 so that we could simply throw the same rendered result for both Android and iOS, but since its Xamarin Forms, which allows you to use Native Looks and Feels after compilation, it’s going to be a mess!

…gotta suck it up!

As the developer, I have no choice but to get this done somehow, even though the hell breaks loose! because it’s my JOB! 😛

Well for the User’s perspective, getting rid of the Android looks and feel, will surely disturb the User Experience on Android.

Challenges..

So as the developer, here are some challenges I faced…

Difference between iOS Designs VS Android Designs!

evasion-ios-71

When you take a iOS Mobile App design, its mostly a static UI design, which uses mostly pixel perfect and screen coordination perfect values for placing the components on the Screen. This is because for iOS devices almost all their devices uses a pre-defined common Screen-Size-Resolution or as in Screen Height-Width Ratio.

top-android-phones1

but when it comes to Android devices, there’s a massive sea of fragmented Screen Sizes, and according to researches it only keeps on growing, therefor for Android Mobile App Designs are compiled with non-static flexible UI Design, which has room to stretch and shrink accordingly as much as possible without disrupting the User Experience.

Dealing with the Android sea of Device…

Just to give you a head start take a look at the following illustration which shows the different Android screen sizes that are available in the market by 2016! :O

screen-shot-2014-08-21-at-1-49-11-pm-1280x748

So you have to deal with the completely unexpected screen-sizes and resolutions, when you try to implement an iOS optimized UI Design for Android. Because of the pure difference I mentioned earlier, how could you take a static pixel-perfect, component coordinates fixed design and adopt it and make it flexible for the massive sea of device fragmentation of Android? 😦

…but not giving up!

So as the job role of a Developer we are suppose to solve problems and accept whatever the challenge throws at us, even the hell breaks loose!

So this is how I resolved it with Xamarin Forms!

So how did I do it?

So let’s go through one by one!

1. RelativeLayout for ze rescue…

Yes that’s right, Xamarin Forms provides several types of Layout types for the ease of Developer and luckily they also provide a Layout called Relative Layout. And yes it does exactly from what it’s name shows.

layouts1

RelativeLayout is used to position and size views relative to properties of the layout or sibling views.

Unlike StackLayout and GridLayouts which most developers use in Xamarin Forms, for the ease of use, RelativeLayout allows you to place its Children Relatively to each other or for the parent view.

Therefore when dealing with different screen sizes of Android we could push the UI to render itself Relatively to given parameters while maintaining the expected UI design as much as possible.

Take a look at the below example from Xamarin docs:

flag1

As you can see, using this Layout we could implement and render the same Design across all mobile platforms. Hence we are placing all the components on the screen, RELATIVE to each other.

2. Always use Constraint type as RelativetoParent!

RelativeLayout provdes three types of Constraint type to place your Components inside the layout, that are

  • RelativeToParent: Set the value relatively to the ParentView
  • RelativeToView: Set the value relatively to another View in the same parent Layout
  • Constant: Set the value as a Constant value

So out of these three types, I would recommend always sticking to the RelativeToParent type, which allows you to have more compatibility towards Android screen sizes, because we are relying on the Parent View which takes up the whole screen Heigh/Width/X or Y properties. So its always better to take relative values accordingly to the Parent instead of another View in the same Parent Layout, which may or may not be behaving as we expect, but as of Parent view, we are sure of its layout.

3. Use XConstraints and YConstraints

Now you must remember how I was crying out loud about having to implement a pixel-perfect screen coordinates fixed design on Android. 😛

So we are going to implement the exact same concept but RELATIVELY!

So with RelativeLayout we can set the X Y locations of a component Relatively to the parent or another view, which helps you place the component on the screen without any worries since those values will get set relatively at the run time. Yep no more worries about those coordinates for Android! 😉

4. Do not use StackLayout or GridLayout inside RelativeLayout!

That’s correct do not use them inside the RelativeLayout and place your child components inside them. Which will lead to the same issue we tried to solve at he beginning, because those Child elements will adopt themselves accordingly to the Stack or Grid Layouts, not for the RelativeLayout. So if you can try to place your child components inside RelativeLayout directly by setting the X/Y/Width/ and Height constraints.

5. Avoid Constants and use Factor…

Yes, with Factor you can get the best suited value according to the ratio of the Relative property, whether its X, Y, Width or even Height! 🙂

And please, stop using Constants, unless you really wants to, because then you will be completely killing the purpose of using the RelativeLayout, hence we need to achieve fluid flexibility to render the iOS optimized design on Android with Xamarin Forms! 😉

6. Also you could use Absolute Layout!

This also does something similar but a little bit differently which could also be used in our situation.

AbsoluteLayout positions and sizes child elements proportional to its own size and position or by absolute values.

So there’s something to keep in mind as well. 😉

Something to keep in mind…

Usage of RelativeLayout is going to be very costly during the run time, takes a lot of processing power to render the UI due to its Relative behaviour of the measurements, meanwhile Jason Smith also recommends avoid using RelativeLayout and instead stick to StackLayouts and GridLayouts.

But unfortunately in order to deal with this kind of scenarios, you have to compromise something , not to mention disrupting the native User Experience of the app.

Conclusion

So that’s how deal with my situation when I was given a iOS Optimized mobile design to be implemented on Android with Xamarin Forms! 😀

Very well then, if anyone else has gotten into this situation, I hope this post has helped you in some way! 🙂

Cheers!

So I created a Popup with Transparent background in Xamarin Forms… ;)

Alright so I was supposed to post this few months back, before I got stuck with my day job which led to temporary put my blog on hold. Either way, recently I managed to find some free time off from work, so I would go ahead and post this with some necessary updates! 🙂

So a while back I was asked to create a Transparent popup control in Xamarin Forms, as ordered by my boss (a very cool guy) to be used for instances such as Loading Spinner screens, and Popup Dialog boxes.

Xamarin Forms ContentPage ? Transparency ?

So I tried to derive my custom control from the default ContentPage control of Xamarin Forms, by setting the Background color of the page to Transparent.

Although I’ve failed by pushing the Page to NavigationStack, I managed to get it working as a Modal page by pushing it to the ModalStack but only on Android platform.

Let’s get into coding…

Alright let’s get into some coding, first create the Custom Control by deriving from ContentPage.

    public class TransparentPopup : ContentPage
    {
        public TransparentPopup()
        {
            // set the background to transparent color 
            // (actually darkened-transparency: notice the alpha value at the end)
            this.BackgroundColor = new Color(0,0,0, 0.4);
        }
    }

 

Although this implementation worked out of the box on Android, it didn’t work as expected on iOS, probably due to the differences the page drawing process of Android and iOS, specially as a popup View.

So I played around with iOS and managed to get it working. So let’s create a custom renderer for iOS.

The deal here is to prepare the Popup to draw over the Parent View Controller which is the previous page. So that we could see through the Popup to see the page underneath which is the parent view. Becase in iOS when a new View Controller is introduced the previous View Controller’s View gets removed from the Window.

[assembly: ExportRenderer(typeof(TransparentPopup), typeof(TransparentPopupRenderer))]
namespace WhateverYourNamespace.iOS
{
    public class TransparentPopupRenderer : PageRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
        }

        public override void DidMoveToParentViewController(UIViewController parent)
        {
            base.DidMoveToParentViewController(parent);

            if (ParentViewController != null)
            {
                // Preparing the view to get the presentation of the parent view for the background
                ParentViewController.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
            }
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // Setting the background color to transparent when the view is appearing
            View.BackgroundColor = UIColor.Clear;
        }
    }
}

 

DidMoveToParentViewController called when the current view gets added to the parent ViewController, so at that point we will set the ModalPresentationStyle of the parent controller, to OverCurrentContext property which will draw our popup view over the previous view.

Well that’s the iOS Custom Renderer, and like I mentioned before we are not going to be needing a Custom Rendering for Android, hence the Modal Page get’s drawn directly above the previous page view.

So let’s put it to use eh! 😉

 Navigation.PushModalAsync(new TransparentPopup());

 

Yep! that’s pretty much it. 🙂

Thou shalt grab em code up on my github: XFTransparentPopup

Cheers!

Wait for it……..

A journey through time…

*fast forwards time…*

*forwarding through time 4-6 months…*

*passing through them late night work hours at office…*

*days of procrastinating and laziness…*

*till this date (November, 2016)*

So after time travelling to this date I updated my local Xamarin installation and this project solution’s Xamarin references, hoping to refresh everything an finally finish off this article.

BOOM! EVERYTHING BROKEN!

Yep since the upgrade to the latest Xamarin references the above implementation has broken and transparency is working no more for the Modal Pages.

Hence it appears to be a change in the Xamarin Core implementation for ContentPage and the rendering process of Modal Pages with the latest update, there had been some other complaints in the Xamarin Forums regarding this. Although whatever the changes Xamarin Forms team has done, I’m sure they had their reasons. This seems to be occurring from all the new Xamarin versions, since I’ve been trying out few fresh Project solutions as well

Looks like I need to find an alternative (until I find a workaround)….

Alternative?

Very well… lucky enough I stumbled upon this awesome library called, Rg.Plugins.Popup! Which literally saved me tons of time. This is a Xamarin Forms library that allows you to create Transparent Popup pages, allowing you to open any ContentPage control as a popup page with full transparency background.

And this library solves a massive problem xamarin developers have been facing, which is the Transition animation control between pages, where as in default Xamarin Forms navigation stack, we can not modify the Transition animations between pages, but with this library, it’s all possible and we could add our own custom animations for page transitions.

capture

Go ahead visit their Github page for description: https://github.com/rotorgames/Rg.Plugins.Popup

Looks very promising indeed. Alright let’s try it out!

Praising le third party library…

Alright just for basics add the Rg.Plugins.Popup library to your Xamarin Forms project from Nuget.

This library provides us a base control that is called PopupPage, which gives you full Transparency background properties, therefore instead of deriving from ContentPage, now we are going to derive from PopupPage to our Transparent Page.

namespace WhateverYourNamespace
{
    public class TransparentPopup : PopupPage
    {
        public TransparentPopup()
        {
            // set the background to transparent color 
            // (actually darkened-transparency: notice the alpha value at the end)
            this.BackgroundColor = new Color(0, 0, 0, 0.4);
        }
    }
}

 

There you go, now let’s add some decorations to our Transparent Popup Page. 😉

public TransparentPopup()
{
	Button btnClose = new Button() { Text = "Close this" };
	btnClose.Clicked += BtnCloseOnClicked;

	Content = new StackLayout()
	{
		BackgroundColor = Color.Transparent,
		Children =
		{
			new Label()
			{
				Text = "Hello from Transparent Modal Page",
				FontSize = 18,
				TextColor = Color.White,
				HorizontalTextAlignment = TextAlignment.Center
			},
			new ActivityIndicator()
			{
				IsRunning = true
			},
			btnClose,
		},
		VerticalOptions = LayoutOptions.Center,
		Padding = new Thickness(10,0,10,0),
	};

	// set the background to transparent color 
	// (actually darkened-transparency: notice the alpha value at the end)
	this.BackgroundColor = new Color(0, 0, 0, 0.4);
}

private void BtnCloseOnClicked(object sender, EventArgs eventArgs)
{
	// Close the modal page
	PopupNavigation.PopAsync();
}

 

Alright, shotgun! There we have added a welcome Label, Activity indicator and a Button to close the popup.

Something important!

And as you can see on the BtnCloseOnClicked event, we are accessing a property called PopupNavigation, instead of default Xamarin Forms Navigation property, to remove the page from Stack.

Well its because Rg.Plugins.Popup maintains its own Popup-Navigation Stack which keeps references to the Popups of it’s own kind, which derives from the PopupPage. So we need to access that property to remove the page from our Navigation stack.

It also provides a Page background click behavior, which is if the user clicks on the background of the page, we could trigger an event to exit the page. Well in my case I didn’t want that to happen so let’s disable it. 😀

protected override bool OnBackgroundClicked()
{
	return false;
}

 

Alright, let’s consume this fella right now as below,

Navigation.PushPopupAsync(new TransparentPopup());

 

Now you must have expected to use the ordinary Navigation.PushModalAsync() as what we normally do in Xamarin Forms, yes of course you could do the same to open this Transparent Popup page, but you may loose the Transparency and ability to override the Navigation Transition animations.

Therefore we are using the PushPopupAsync() extension method that’s provided by this library, which is pretty cool. Now the reason for this I shall explain later in this post.

Alright! Let’s run this fella and see for ourselves! 🙂

nexus-5-lollipop-screenshot-1  simulator-screen-shot-6-dec-2016-10-46-02-am

WOOT! WOOT!

there you go! 😀

For You lazy people may fetch my code up on my githubXFTransparentPopupUpdate

Enjoy!

Important after-notes to share…

1. Page Transition Animations

In default Xamarin Forms Navigation we do not have the access to Page Transition Animations, hence we have to suck it up with the default boring Transition animations of Xamarin Forms.

But thanks to this library, Rg.Plugins.Popup maintains its own Popup-Navigation Stack which to allow us to control the Page Navigation Transition effects, unlike in default Xamarin Forms Navigation Stack. This is a great feature that is provided by this solution hence a lot of developers were having issues with this restriction of Xamarin Forms since long time back. 🙂

2. PushPopupAsync()

Also it is important to mention that, when using Popup pages of Rg.Plugins.Popup  we should always use the Navigation.PushPopupAsync() extension if we want to preserve the Transparency and Custom Page transition features. Meanwhile using the PopupNavigation.PopAsync() to remove the pages from the stack while maintaining transition effects. 😀

3. PushPopupAsync()

We are all aware of how on Android run time, Xamarin Forms uses a Single Activity to populate the Pages of our app. And usually when we add a Modal Page, it gets populated on top of the Single Activity the app is running on. But in this Library it uses a separate Android Dialog View which doesn’t use the Activity Stack, instead it draws itself over the Activity, (blocking the whole Activity content) such as in AndHUD library. So that’s something to keep in mind if you wonder why you couldn’t Push a Page on top of this popup page. 😉

Finally kudos to the developers of Rg.Plugins.Popup plugin for Xamarin Forms!