Category Archives: Experimentation

A Keyboard disabled Entry control in Xamarin Forms?

A Xamarin Forms Entry Control without a keyboard? So when the user clicks on the Entry, the keyboard wouldn’t pop up? Yep, that’s what I’m talking about yo!

Oh sweet! So that I could use my custom keyboard or key buttons to enter values into it without the keyboard popping over and covering up the view? Oh yeah! that’s awesome! 😀

So it all began..

There was this one time where I was asked to implement a page which had an Entry with a bunch of custom buttons in the page, which would insert their specific values into the Entry controls when they’re clicked.
But if the User somehow clicked on the Entry, the Keyboard shouldn’t pop up and hover over the custom keyboard. And keep on mind the Entry field or the whatever alternative text editor view should be exactly similar to an entry looks and feel! 😮

Why such a requirement you ask? Imagine an text field which has limited or custom character inputs or a security code input field, where you want to have a custom keyboard on the view without using the default system keyboard for security reason, and many more. 🙂

Alternatives?

You could say, use a Label control where you would append its text value upon the custom key button clicks.
But the problem is, Label control doesn’t have the looks and feel of an Entry control, and it would be a big hassle to customize it to look as an Entry. Also from the performance aspect as well, since it will surely require custom rendering approach. 😦

Then you might say use the Keyboard dismissal service which I posted last time in my blog, and call up on it every time the user clicks on the Entry? But nope, that would look extremely distracting while the keyboard keep on popping up and down when the User clicks on the Entry every time.

So the solution?

So the only solution here is to have a Custom Entry control which doesn’t allow the popping up of the keyboard, or in other words, an Entry which has no Keyboard attachment up on focus.  😉

This is obviously the easiest and the fastest solution to execute, since we already got the Entry’s generic look and feel, along with all the behavior, except for the on Focus Keyboard attachment behavior. 😀

^there you go 😉

How could we do this?

Alright since we are going to customize our Entry control, we need to drill down to native levels of the actual Entry’s control rendering.

The Android EditText control that associates with the Xamarin Forms Entry’s has a property called ShowSoftInputOnFocus property which allows you to disable Keyboard attachment behavior upon focus for the EditText.

Then for iOS UITextField control that associates with the Xamarin Forms Entry’s has a property called InputView property which allows you to disable the Keyboard attachment by assigning it to an empty UIView object.

So we are going to use those native properties to implement this awesomeness! 😀

Coding it is!

First of all create a Custom Entry control by sub-classing it.

namespace WhateverYourNamespace
{
    public class SoftkeyboardDisabledEntry : Entry
    {

    }
}

 

Let’s call it SoftKeyboardDisabledEntry, just for the kicks of it 😉 !

iOS Custom Renderer…

Alright let’s drill down to iOS renderering of our custom control.

[assembly: ExportRenderer(typeof(SoftkeyboardDisabledEntry), typeof(SoftkeyboardDisabledEntryRenderer))]
namespace WhateverYourNamespace.iOS
{
    public class SoftkeyboardDisabledEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            // Disabling the keyboard
            this.Control.InputView = new UIView();
        }
    }
}

 

Alright there we assign an empty UIView to the InputView property of the native control instance, which will replace Keyboard attachment at run time.

Android Custom Renderer…

Ok then comes the Android renderer, with a bit of work though.

[assembly: ExportRenderer(typeof(SoftkeyboardDisabledEntry), typeof(SoftkeyboardDisabledEntryRenderer))]
namespace WhateverYourNamespace.Droid
{
    public class SoftkeyboardDisabledEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);
        
            if (e.NewElement != null)
            {
                ((SoftkeyboardDisabledEntry)e.NewElement).PropertyChanging += OnPropertyChanging;
            }

            if (e.OldElement != null)
            {
                ((SoftkeyboardDisabledEntry)e.OldElement).PropertyChanging -= OnPropertyChanging;
            }

            // Disable the Keyboard on Focus
            this.Control.ShowSoftInputOnFocus = false;
        }

        private void OnPropertyChanging(object sender, PropertyChangingEventArgs propertyChangingEventArgs)
        {
            // Check if the view is about to get Focus
            if (propertyChangingEventArgs.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
            {
                // incase if the focus was moved from another Entry
                // Forcefully dismiss the Keyboard 
                InputMethodManager imm = (InputMethodManager)this.Context.GetSystemService(Context.InputMethodService);
                imm.HideSoftInputFromWindow(this.Control.WindowToken, 0);
            }
        }
    }
}

 

So there we are disabling ShowSoftInputOnFocus property by setting it false, to disable Keyboard attachment event. 😀

But then you notice that we are subscribing to the IsFocused PropertyChanged event as well. This is because in Android if we move the focus to our Custom Entry from another Entry which already had the Keyboard attached, the Keyboard wouldn’t dismiss itself. So in order to dismiss the Keyboard in case if it was already popped up, we are calling the InputMethodManager to forcefully dismiss the Keyboard. 🙂  Well this is more of a fail safe for our object, but if you think you wouldn’t run into such a scenario as above then you could remove the additional fail safe bit. 😉

Try it out?

Alright to test this out, below is a cool demo I threw in together, which you could also find in my github repo: https://github.com/XFNoSoftKeyboadEntryControl

Here’s how to consume it in your XAML!

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

	<Label Text="Welcome to the Entry with disabled Keyboard!"
		   FontSize="22" FontAttributes="Bold" Margin="0,0,0,10"/>

	<Label Text="here is the normal Entry with Keyboard popping up on Focus"  TextColor="Gray" />
	<Entry Placeholder="Normal Entry Control..."/>

	<BoxView HeightRequest="0.7"  Margin="0,5,0,5"/>

	<Label Text="and here is our Entry with Keyboard disabled on Focus (but still editable)"  TextColor="Gray" />
	<local:SoftkeyboardDisabledEntry Placeholder="Keyboard disabled Entry Control..." x:Name="SoftkeyboardDisabledEntry" />
	
	
	<StackLayout VerticalOptions="EndAndExpand" Margin="0,0,0,10">
		<Label Text="So a simple custom keyboard may be? 😉 "  TextColor="Gray" />
		<StackLayout Orientation="Horizontal">
			<Button Text="A" Clicked="Button_OnClicked" WidthRequest="35" />
			<Button Text="B" Clicked="Button_OnClicked" WidthRequest="35" />
			<Button Text="C"  Clicked="Button_OnClicked" WidthRequest="35" />
			<Button Text="D"  Clicked="Button_OnClicked" WidthRequest="35" />
			<Button Text="E"  Clicked="Button_OnClicked" WidthRequest="35" />
			<Button Text="Clear All"  Clicked="ButtonClear_OnClicked" />
		</StackLayout>
	</StackLayout>

</StackLayout>

 

Next let’s add some Custom Key buttons to enter text to our Custom Entry with no Keyboard attached control! 😉

public partial class MainPage : ContentPage
{
	public MainPage()
	{
		InitializeComponent();
	}

	private void Button_OnClicked(object sender, EventArgs e)
	{
		SoftkeyboardDisabledEntry.Text 
                                  += ((Button) sender).Text;
	}

	private void ButtonClear_OnClicked(object sender, EventArgs e)
	{
		SoftkeyboardDisabledEntry.Text = "";
	}
}

 

that’s it.

Fire it up!

Hit that F5 and see the magic! 😀

 

WOOT! WOOT!

How cool is that eh! 😉

github repo: https://github.com/XFNoSoftKeyboadEntryControl

Enjoy and share.

Forcefully dismissing Keyboard in Xamarin Forms…

Wait… what? You want to forcefully dismiss your keyboard? A-B-S-O-L-U-T-E-L-Y!

Thanks to my experience in  working with high-expectation- seniors at my company, who demands me to push the limits of the Xamarin Forms Framework (frankly I love it, although it is kind of exhausting at times), I keep on sharing cool stuff which is quite out of the norm. And heyyy buckle up, since this is one of those instances where I pushed the limitations of Xamarin Forms! 😉

Once upon a time…

So there was this one time where I had to mimic a translucent layer on top of a login screen, where once the user enters username and password, I would simple capture a screenshot, blur it, and display as a blurred view on top of the page. But the problem there was as soon as user hits “Enter” on the keyboard, the screenshot will be captured but the keyboard would also be visible in the screenshot, since keyboard still stays up until a new layer is popped on top of the page (until the Entry’s focus is dismissed). 😦

Thereby the screenshot and the blurred view had the Keyboard visibility, which was pretty ugly, and my UX Lead wasn’t happy about it (perfectionists! lol).

“YOU MUST GET RID OF THE KEYBOARD VISIBILITY INSTANTLY, NO EXCUSE!”, demanded the UX Lead. 😮

Although this was no way possible out of the box from Xamarin Forms, I was asked to get rid of it one way or the other.

Nah I Didn’t give up!

You might think it’s just a matter of dismissing the focus of the Entry’s Completed event, but hell no it wasn’t! Because there was a specific delay from the Completed event to the keyboard dismissal event firing, which caused our screenshot capturing to capture the page with the Keyboard in view. 😮

So I knew I had to override or interrupt or short-wire the keyboard dismissal event myself forcefully. 😉

So after trying out many different solutions to get rid of the Keyboard visibility when the screenshot was captured, which ended up failing, I finally had the moment of “eureka!”.

le moment of eureka! 😀

Basically, what I did was to create a dependency service which would forcefully dismiss the keyboard, as in, push down the keyboard from which ever the current view of focus.

Sounds pretty simple eh? nah it wasn’t. lol

Up on the Entry’s Completed event I would first of all call up on my custom Keyboard dismissal service and then perform the screen capture and blurring view effect and so on. Which worked out pretty nicely!

Behold the results…

Yeah here’s something I built up to demonstrate the awesomeness of this hack!

How cool is that right? 😉

Besides the coolness, now you might ask what else could this be used for? Isn’t that obvious bro? 😛

Instances where,

  • you want to limit the user from entering text into an Entry after a given timeout?
  • may be dismiss the keyboard after a certain text length is reached?
  • instantly dismiss the keyboard straight from the ViewModel itself without having to go through a UI Event chain?

and so many other aspects, or it might as well be the same situation I had. 😉

Let me show you how it’s done…

So there’s no doubt we need to drill down to the native level when we try to push the limits of Xamarin Forms Framework, as usual.

In Android we could gain the access for the InputMethodManager which gives us the capability to hide the keyboard on demand.

And on iOS we use the UIApplication instance which gives us the access to the PresentedViewController property (current active ViewController), in return allowing us to call the EndEditing on its View to resign the first responder.

Finally I unite those two native calls via dependency service and be used from Xamarin Forms PCL level.

Here’s how to code it…

Blah blah blah.. yeah I talk too much when I’m enthusiastic about a hack I came across lol! 😀

First step create the interface for the keyboard dismissal service…

namespace WhateverYourNamespace
{
    /// <summary>
    /// Forcefully dismiss the keyboard
    /// </summary>
    public interface IForceKeyboardDismissalService
    {
        void DismissKeyboard();
    }
}

 

Now we could use this interface to do the native implementations which could be used via DependencyService of Xamarin Forms.

Next native hacking… or short circuiting you could say!

This is the time for native project level implementation of our service. Go ahead create your platform specific implementation of the IForceKeyboardDismissalService interface.

So for Android, we need to access the current Activity to access the InputMethodManager, for which we would use the Plugin.CurrentActivity library. So if you don’t have it, you might as well go ahead add that to your solution via nuget before implementing the below.

[assembly: Xamarin.Forms.Dependency(typeof(AndroidForceKeyboardDismissalService))]
namespace WhateverYourNamespace.Droid
{
    public class AndroidForceKeyboardDismissalService : IForceKeyboardDismissalService
    {
        public void DismissKeyboard()
        {
            InputMethodManager imm = InputMethodManager.FromContext(CrossCurrentActivity.Current.Activity.ApplicationContext);

            imm.HideSoftInputFromWindow(
                CrossCurrentActivity.Current.Activity.Window.DecorView.WindowToken, HideSoftInputFlags.NotAlways);
        }
    }
}

 

As you can see we are calling up the HideSoftInputFromWindow() method to dismiss the Keyboard via the InputMethodManager instance we retrieved.

Oh don’t forget to add the assembly attributes to register this for the Xamarin Forms DependencyService.

Then on iOS, we already have the singleton access to UIApplication where we are given access to the active PresentedViewController, which holds the instance for the current active view controller.

[assembly: Xamarin.Forms.Dependency(typeof(IosForceKeyboardDismissalService))]
namespace WhateverYourNamespace.iOS
{
    public class IosForceKeyboardDismissalService : IForceKeyboardDismissalService
    {
        public void DismissKeyboard()
        {
            UIApplication.SharedApplication.InvokeOnMainThread(() =>
            {
                var window = UIApplication.SharedApplication.KeyWindow;
                var vc = window.RootViewController;
                while (vc.PresentedViewController != null)
                {
                    vc = vc.PresentedViewController;
                }

                vc.View.EndEditing(true);
            });

        }
    }
}

 

Alright we are then calling the EndEditing() method from the current active View related to the active ViewController. There we are passing true as the parameter to let it know we mean business! 😛 lol uikit/uiview/1619630-endediting

Alright now time for the consumption of some cool code.

Consume it. (not literally) 😛

Here’s how you could use the above awesome service in Xamarin Forms.

DependencyService.Get<IForceKeyboardDismissalService>().DismissKeyboard();

 

That’s it!

Where’s the cool demo? 😮

Now don’t worry I shall not leave you hanging fellas!

You may be wondering where’s the cool implementation you saw at the beginning of the post… 😉
 

Here I have shared it on my github: UdaraAlwis/XFForcefulKeyboardDismiss

Alright, happy coding fellas! 😀

Enjoy and Share!

-Udara Alwis

Advanced decorating of Xamarin Forms Slider for Android…

Alright so today I’m gonna take you guys through a journey of decorating a Xamarin Forms Slider control in Android…

Well we all know how basic the default Slider control in Xamarin Forms, but worry not, there are plenty of ways to decorate it with awesome features,specifically for Xamarin Android! 😀

It all started a few weeks back when I was playing around with the Slider control to add  a whole bunch of complex visual features in one of my company apps.

Let’s get started…

Alright, first thing first, we need set up our Custom Slider control first and attach it’s Custom renderer in Android.

So here goes the Custom Slider control subclassing in Xamarin Forms project…

namespace WhateverYourNamespace
{
    public class CustomSlider : Slider
    {

    }
}

 

Next set up the Custom Slider Renderer in your Android project…

[assembly:ExportRenderer(typeof(CustomSlider), typeof(CustomSliderRenderer))]
namespace WhateverYourNamespace.Droid
{
    public class CustomSliderRenderer : SliderRenderer
    {
        protected override void
                 OnElementChanged(ElementChangedEventArgs<Slider> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
		// All the customization will go here
            }
        }
    }
}

 

How would I consume this in XAML you ask? Just as another ordinary view… 😉

<StackLayout>

	<local:CustomSlider 
	HeightRequest="7" 
	WidthRequest="350" 
	HorizontalOptions="Center"
	Minimum="0" Maximum="100" />

</StackLayout>

 

Now keep in mind all the customization that we are doing later will be done within this custom renderer.

Something to keep in mind is that,

the Xamarin Forms Slider control’s Android run time native counterpart is the SeekBar…

So the more you aware of the SeekBar’s properties, the more customization you could play around with! 😉

Alright let’s start decorating… 😀

Decoration 1 : Change color theme!

Want to change the color theme of your Slider? Here we go…

Let’s see the code.

if (e.NewElement != null)
{
	// progressbar and progressbar background color
	Control.ProgressDrawable.SetColorFilter(
		new PorterDuffColorFilter(
		Xamarin.Forms.Color.FromHex("#ff0066").ToAndroid(),
		PorterDuff.Mode.SrcIn));
}

 

Use the ProgressDrawable Property and set the ColorFilter to it as you wish… 😉 which will set the color theme to your Progress Bar , Progress Thumb, and the background bar…

Decoration 2 : Change only the Slider’s Thumb Color?

How about changing just the Progress Thumb’s color? Yes you may…

Look at that funky looking Progress Thumb! 😉

Code?

if (e.NewElement != null)
{
	// Set Progress bar Thumb color
	Control.Thumb.SetColorFilter(
		Xamarin.Forms.Color.FromHex("#8000ff").ToAndroid(), 
		PorterDuff.Mode.SrcIn);
}

 

Android SeekBar (which is the native handler of Xamarin Forms Slider on Android) has the Thumb property which allows you to customize the appearance of the little thumbnail head of the Slider control as we have used above.

Next! 😀

Decoration 3 : Change progress background Color?

How about changing only the Progress Bar’s background color? As you can see below..

Look at the boring default progress bar’s background color vs the purple background color! 😉 pretty cool!

Here’s how you do it,

if (e.NewElement != null)
{
	//Set Background Progress bar color
	Control.ProgressBackgroundTintList 
           = ColorStateList.ValueOf(
            Xamarin.Forms.Color.FromHex("#8000ff").ToAndroid());
	Control.ProgressBackgroundTintMode
           = PorterDuff.Mode.SrcIn;
}

 

Use the ProgressBackground property to set the TintList and the TintMode! 🙂

TADAA!

Decoration 4 : How about adding a secondary progress indicator?

Now we all have seen secondary progress indicators in progress bars, specially in online video stream players… 🙂 example take the Youtube player! 😉 So have you ever wanted to add such a cool feature to your Xamarin Forms Slider in Android? Let me show you how its done… 😉

Look how cool that is yeah! 😉

Alright let’s get into coding…

Now in Android we have this built in property called SecondayProgress which allows you to set a secondary progress value to your Slider or Seekbar as of native Android handler.

if (e.NewElement != null)
{
	// secondary progress value in Xamarin Forms units
	int secondaryProgressValue = 50;
	
	// secondary progress value in 
	// Android native Seekbar units
	int secondaryProgressValueInAndroidUnits =
	(int)((secondaryProgressValue - 
			((CustomSlider)Element).Minimum) /
	(((CustomSlider)Element).Maximum -  
			 ((CustomSlider)Element).Minimum) * 1000.0);

	// set the secondary progress value
	Control.SecondaryProgress = 
	secondaryProgressValueInAndroidUnits;
}

 

There you go, you can see that we are setting the SecondaryProgress value, but also take a closer look at the calculation that we are doing before setting it.

Now Xamarin Forms Slider and Xamarin Android Seekbar which is the handler for the Slider control, uses different value types or unit types for setting the Progress and the Secondary Progress values in native level. If we want to set the value from Xamarin Forms value units then we need to convert that value to Android Seekbar’s native values which is exactly what we are doing at the calculation. So basically we are setting the Xamarin Forms unit value according to the native units to Seekbar control.

Oh if you want to set the Secondary Progress from Xamarin Forms level then you can easily create a property in the CustomSlider class and use it down here in your Custom Renderer class 🙂 Imagination is the limit! 😉

Decoration 5 : May be change the Color of secondary progress indicator?

How about we spice it up by changing the color a little of the secondary progress? 😉

Look at that!

Time for coding…

Android Seekbar has this property called SecondaryProgressTintList and SecondaryProgressTintMode which allows you to achieve the above results and set the secondary progress color as you wish…

if (e.NewElement != null)
{
	//Set Seconday Progress bar color
	Control.SecondaryProgressTintList = 
	      ColorStateList.ValueOf(
		Xamarin.Forms.Color.FromHex("#8000ff").ToAndroid());
	Control.SecondaryProgressTintMode = 
	      PorterDuff.Mode.SrcIn;

	// secondary progress value in Xamarin Forms units
	int secondaryProgressValue = 50;
	
	// secondary progress value in 
	// Android native Seekbar units
	int secondaryProgressValueInAndroidUnits =
	(int)((secondaryProgressValue - 
	((CustomSlider)Element).Minimum) /
	(((CustomSlider)Element).Maximum - 
	 ((CustomSlider)Element).Minimum) * 1000.0);

	// set the secondary progress value
	Control.SecondaryProgress = 
		secondaryProgressValueInAndroidUnits;
}

 

And hey of course don’t forget to set the SecondaryProgress value while you’re at it!

Decoration 6 : I would call it Funky delight!

Alright, now all that being said, how about blending some of those different colors adding some funky delight-ness to the Slider? 😉

Well what I mean is, let’s try adding different color’s to Thumb, Progress Bar, Progress Bar background and Secondary Progress Bar!

Too much funky? I thought so!

How about these??? 😉

I know, I love playing with colors being a Visual oriented developer! 😀 lol

Your imagination is the limit fellas!

Here’s how you play around with the colors…

if (e.NewElement != null)
{
	// Different colors for ProgressBar components
	// Set Primary Progress bar color
	Control.ProgressTintList = 
		ColorStateList.ValueOf(
		Xamarin.Forms.Color.FromHex("#6200ea").ToAndroid());
	Control.ProgressTintMode 
		= PorterDuff.Mode.SrcIn;

	//Set Seconday Progress bar color
	Control.SecondaryProgressTintList = 
		ColorStateList.ValueOf(
		Xamarin.Forms.Color.FromHex("#b388ff").ToAndroid());
	Control.SecondaryProgressTintMode 
		= PorterDuff.Mode.SrcIn;

	//Set Progress bar Background color
	Control.ProgressBackgroundTintList = 
		ColorStateList.ValueOf(
		Xamarin.Forms.Color.FromHex("#b39ddb").ToAndroid());
	Control.ProgressBackgroundTintMode 
		= PorterDuff.Mode.SrcIn;

	// Set Progress bar Thumb color
	Control.Thumb.SetColorFilter(
		Xamarin.Forms.Color.FromHex("#311b92").ToAndroid(),
		PorterDuff.Mode.SrcIn);
}

 

Decide your flavor of colors and go crazy fellas! 😉

Decoration 7 : Remove Thumb Header may be?

Absolutely, check this out…

It’s pretty simply actually, simply set a Tranparent ColorDrawable to the Thumb property.

if (e.NewElement != null)
{
	// Hide thumb
	Control.SetThumb(
		new ColorDrawable(Color.Transparent));
}

 

Woot!

Decoration 8 : Let’s kick it up a notch!

Let’s add some more vibrant and complex customization to our Slider for Android! 🙂

How about throwing in some cool gradient effects…

So to achieve that, we shall be using Android native Styling with Drawables such as Shape, Gradients and so on.

We will create a native android xml Style file in your Resources/Drawable folder with the name “custom_progressbar_style.xml”

Here’s what you’ll be placing inside of it…

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

  <item android:id="@android:id/background">
    <shape>
      <corners android:radius="15dip" />
      <gradient
       android:startColor="#d9d9d9"
       android:centerColor="#e6e6e6"
       android:endColor="#d9d9d9"
       android:centerY="0.50"
       android:angle="270" />
    </shape>
  </item>
  
  <item android:id="@android:id/secondaryProgress">
    <clip>
      <shape>
        <corners android:radius="15dip" />
        <gradient
             android:startColor="#e6b3e6"
             android:centerColor="#ffcce0"
             android:endColor="#e6b3e6"
             android:centerY="0.50"
             android:angle="270" />
      </shape>
    </clip>
  </item>
  
  <item android:id="@android:id/progress">
    <clip>
      <shape>
        <corners android:radius="15dip" />
        <gradient
         android:startColor="#ff0066"
         android:centerColor="#ff00ff"
         android:centerY="0.50"
         android:endColor="#cc0052"
         android:angle="270" />
      </shape>
    </clip>
  </item>
  
</layer-list>

 

So to explain the above a little bit, we have created a Style layer-list which assigns the given styling items to the specific id’s of the SeekBar native control, such as the background, secondaryprogress, progress as you have noticed. Those drawable objects will replace the default styles of those segments in the SeekBar with these defined drawable objects.

First we are using a Shape drawable to to the Background property, which creates a gradient layer with the given colors and angle for creating a gradient effect! Also we are setting a radius value to corner so that the corners will be curved nicely.

Next for the Progress and the SecondaryProgress properties we are creating a similar Shape gradient as before but we are clipping it according to the given values of each of them.

if (e.NewElement != null)
{
	// Set custom drawable resource
	Control.SetProgressDrawableTiled(
	Resources.GetDrawable(
	Resource.Drawable.custom_progressbar_style,
	(this.Context).Theme));

	// Hide thumb to make it look cool lol
	Control.SetThumb(new ColorDrawable(Color.Transparent));
}

 

There’s how you set it in the custom renderer level, simply call the SetProgressDrawableTiled() method by passing the custom style of what we created above.

Also I have disabled the Thumb, just to make it look cooler. Its up to you though.

If you want to do more extensible customization like above and may be preserve the Thumb view and style that as well? then refer to this stackoverflow article: http://stackoverflow.com/questions/16163215/android-styling-seek-bar

Additionally you could have bitmap images or nine patch images as drawables to styling and so may other stuff.

Now this is like the holy grail.. where as you can see with Android you get full flexibility for any kind of complex customization!

Its only limited by your imagination! 😉

WooT! 😀

Decoration 9 : Can I reduce the above overridden Height?

So you’re worried of the height after setting the custom styling drawables as above? simply reduce the HeightRequest value in your Xamarin Forms code for our custom Slider view.

Right after we set the Custom ProgressDrawable styles in the renderer level, it overrides the Height property of native SeekBar  that’s assigned from Xamarin Forms level for each of those sub-views (ProgressBar, SecondaryProgressBar and Background sub views), so they expands themselves to the fullest as possible with the new Drawable objects.

<local:CustomSlider HeightRequest="7" WidthRequest="350"  HorizontalOptions="Center"
        Minimum="0" Maximum="100" />

 

So the above should give you control over the Height issue!

Or else you could set the dip IntrinsicHeight values in your XML style drawables itself as well (something extra)! 😉

Decoration 9 : Can I  have the above cool-ness programmatically without resources?

So you don’t like to deal with Android Resources and creating the Style XMLs and stuff?

Oh sure, no worries! but you will have to do a little bit of work to get the above simple XML Styling into pure code generated objects!

Let me begin by giving credit to this example written in Java which I found while I was in the same situation: FlatUI/FlatSeekBar.cs

So let’s see how we could create Drawable Style objects in C# code!

Now keep in mind all the Drawable objects we used in our XML file “custom_progressbar_style.xml” has their own programmatical counterparts such as Shape, Gradient and Clip by the names as ShapeDrawable, GradientDrawable, and ClipDrawable and so on likewise.

So we can convert any given XML style to a C# generated style drawable. (any native Android developer should be well aware of this)

So let’s do something similar! 😉

So we are going to create our own Drawable objects and set them to the sub-views of our Slider control for Android, just like how we did with the XML styling, but this time programmatically. Here is how it will look like…

There you haveit, let’s see how we did this…

if (e.NewElement != null)
{
	// Setting drawable styling programatically

	// progress
	var progress = new PaintDrawable(Color.Red);
	progress.SetCornerRadius(
		(int)DpToPixels(this.Context, 10));
	progress.SetIntrinsicHeight(
		(int)DpToPixels(this.Context,10));
	var progressClip = 
		new ClipDrawable(progress, GravityFlags.Left,
		ClipDrawableOrientation.Horizontal);

	// secondary progress
	var secondary = new PaintDrawable(Color.Gray);
	secondary.SetCornerRadius(
		(int)DpToPixels(this.Context, 10));
	secondary.SetIntrinsicHeight(
		(int)DpToPixels(this.Context, 10));
	var secondaryProgressClip = 
		new ClipDrawable(secondary, GravityFlags.Left, 
		ClipDrawableOrientation.Horizontal);

	// background
	PaintDrawable background = new 
                 PaintDrawable(Color.LightGray);
	background.SetCornerRadius(
		(int)DpToPixels(this.Context, 10));
	background.SetIntrinsicHeight(
		(int)DpToPixels(this.Context, 10));

	// retrieve LayerDrawable reference of the SeekBar control
	LayerDrawable layeredDrawableReference 
		= (LayerDrawable)Control.ProgressDrawable;
		
	// apply our custom drawable objects to the 
	// given sub-views through their IDs
	layeredDrawableReference.
	    SetDrawableByLayerId(
		Android.Resource.Id.Background, background);
	layeredDrawableReference.
	    SetDrawableByLayerId(
		Android.Resource.Id.Progress, progressClip);
	layeredDrawableReference.
	    SetDrawableByLayerId(
		Android.Resource.Id.SecondaryProgress, 
                  secondaryProgressClip);
}

 

So basically we are creating our our Drawable objects programatically, in this case PainDrawable objects and giving them different styling values such as Radius, Clipping, IntrinsicHeight and so on.

And then at the end we are going to retrieve the references for the sub-views of our native SeekBar in Android which is the after-rendering counterpart of Xamarin Forms Slider as I mentioned at the beginning. This is going to be a LayerDrawable object, which is going to allow us to set our own custom Drawable objects to each drawable layer by their IDs.

As you can see we are calling the SetDrawableByLayerId() on our LayerDrawable object and passing in the each sub-view reference and custom drawable objects we want to set to them. 😀

Now keep this in mind, here you could have any kind of drawable objects to create your custom drawable styling just like you previously did with GradientDrawable in XML style, have the exact same beautiful visual result rendered programatically! 🙂

That’s it…

Well fellas that’s it for now, well at least that’s all I came across while I was playing around with my Custom Renderer for Xamarin Forms Slider on Android! 😀

Enjoy and share!

CHEERS!

Let’s Override Navigation Bar back button click in Xamarin Forms…

So you would like to override the Navigation Bar back button click event in your Xamarin Forms App? 😉 Yeah could be for a Sign up Page, Order Details Page, or any kind of a Page where you want to do some execution or confirmation before the user actually navigates back to the previous page in your app…

It’s BACKWARD navigation time…

Yes we are not talking about forward navigation here, but BACKWARD navigation! where the user clicks on the back button on the Navigation Bar, or the actual Back button in Android phones, where we need to have some validation before the user actually navigates…

Oh hello! Where do you think you’re going? Are you sure you want to go back?

:\

Do you want to save your changes before you go back?

Please complete the empty fields because you go back!

😮

Do you want to go back before you save your changes?

Please confirm you want to cancel your changes and go back…

😛

Blah blah…

Well you know the scenarios… 😉

ummhh… but in Xamarin Forms?

Yeah the question is can we actually implement this behavior in Xamarin Forms?

YES! you can, but…

well yes obviously you can override the OnBackPressed() method in ContentPage control, but…

it works only on Android and only for the physical back button…

not the Navigation Bar back button…

owwhh SNAP!

Yes fellas, if you want to achieve the above behavior in Xamarin Forms, you literally can not do it straight out of the box, because the override-able  OnBackPressed() method in ContentPage only gets fired on Android’s physical (or screen bottom) back button’s click. It does not work for the Navigation Bar’s back button click.

But I did it…

So here’s a sneak preview of the results of my implementation…

  

Now look at that awesomeness.. When the user clicks on the Navigation Bar’s back button, I’m popping up a confirmation dialog.. 🙂

Alright, how did I do this?

So in order to do this we need to drill down to the native level and handle these Navigation Bar back button click. Let me explain further….

Android

So after compilation the Navigation Bar that we call in Xamarin Forms, turns into the Action Bar for Android during run time. So in order to capture the back button click the Action Bar we need to override the OnOptionsItemSelected() in your MainActivity class, which allows us to capture the navigation bar’s back button click. Since Xamarin Forms runs on a single Activity overriding the above event on your parent Activity class is enough to get our job done. 😉

iOS

And for iOS , the Xamarin Forms’s Navigation Bar is mapped to the UINavigationBar in iOS run time. But unfortunately there’s no way to override the back button click on the default back button in the UINavigationBar, the only solution is to replace the default back button with a custom back button and do our necessary event subscriptions with it. We can replace the default back button with our custom back button at the ViewWillAppear() event call of the UIViewController, and set our custom back button to UILeftBarButtonItem property. 😀

Bridging between Native Xamarin and Xamarin Forms?

Yep just by native implementation is not enough since we need to get a call back to our Xamrin Forms PCL or Shared project level right? So for that we shall be using a simple Action event where we subscribe to in our Xamarin Forms code level, and do the necessary execution when the mentioned Action event gets fired from the native project levels. 😉

Simple as that! 😀

Alright! time for coding.. 😀

So first we need to create a Custom ContentPage to be used as our Page in our Xamarin Forms project, where as we could enable or disable the Nav bar Back button event overriding. And we shall name it as the “CoolContentPage” lol, well why not, it is indeed cool! 😉 lol

namespace WhateverYourNamespace
{
    public class CoolContentPage : ContentPage
    {
        /// <summary>
        /// Gets or Sets the Back button click overriden custom action
        /// </summary>
        public Action CustomBackButtonAction { get; set; }

        public static readonly BindableProperty EnableBackButtonOverrideProperty =
               BindableProperty.Create(
               nameof(EnableBackButtonOverride),
               typeof(bool),
               typeof(CoolContentPage),
               false);
			   
        /// <summary>
        /// Gets or Sets Custom Back button overriding state
        /// </summary>
        public bool EnableBackButtonOverride
        {
            get
            {
                return (bool)GetValue(EnableBackButtonOverrideProperty);
            }
            set
            {
                SetValue(EnableBackButtonOverrideProperty, value);
            }
        }
    }
}

 

So there we have created the Action event that we are going to subscribe to in our Xamarin Forms code level and to be invoked from Xamarin native project level.

You can also see that I’m using a bool property to enable or disable the overriding of the Back Button click event, so that we can decide whether to subscribe to the overriding event or not as a page property.

next Xamarin Android stuff…

So as I explained at the beginning we need to override the OnOptionsItemSelected() event in our MainActivity class in order to capture the nav bar back button click in Android for Xamarin Forms.

public override bool OnOptionsItemSelected(IMenuItem item)
{
	// check if the current item id 
	// is equals to the back button id
	if (item.ItemId == 16908332)
	{
	   // retrieve the current xamarin forms page instance
	   var currentpage = (CoolContentPage)
	   Xamarin.Forms.Application.
	   Current.MainPage.Navigation.
	   NavigationStack.LastOrDefault();

	   // check if the page has subscribed to 
	   // the custom back button event
	   if (currentpage?.CustomBackButtonAction != null)
	   {
		 // invoke the Custom back button action
		 currentpage?.CustomBackButtonAction.Invoke();
		 // and disable the default back button action
		 return false;
	   }

	   // if its not subscribed then go ahead 
	   // with the default back button action
	   return base.OnOptionsItemSelected(item);
	}
	else
	{
	   // since its not the back button 
	   //click, pass the event to the base
	   return base.OnOptionsItemSelected(item);
	}
}

public override void OnBackPressed()
{
	// this is not necessary, but in Android user 
	// has both Nav bar back button and
	// physical back button its safe 
	// to cover the both events

	// retrieve the current xamarin forms page instance
	var currentpage = (CoolContentPage)
	Xamarin.Forms.Application.
	Current.MainPage.Navigation.
	NavigationStack.LastOrDefault();

	// check if the page has subscribed to 
	// the custom back button event
	if (currentpage?.CustomBackButtonAction != null)
	{
		currentpage?.CustomBackButtonAction.Invoke();
	}
	else
	{
		base.OnBackPressed();
	}
}

 

phewww… that was some long code snippet yeah! fear not child! let me explain…

So as I mentioned before when the user clicks on anything on the default Android navigation bar the above OnOptionsItemSelected() gets fired, where as we will check the clicked item’s id and check for the back button’s default id. Yes the default back button id is the same 16908332 integer in Xamarin Forms – Android applications.

There we will get an instance of the current Xamarin Forms page in the Navigation stack and look if the page has been subscribed to the Custom Back button click event, if so there we will invoke our CustomBackButtonAction, and disable the default click event. If the page hasn’t subscribed to the Action, then we shall pass the click event to the base allowing the default back stack navigation. 🙂 Simple as that! 😀

Now you may see that I have also overridden the OnBackPressed event as well. This is really not necessary if you don’t want to but as a good practice it’s better to override both Nav bar back button and physical back button click events at the same time.

then Xamarin iOS stuff…

Here comes the iOS implementation where we are going to replace the custom Navigation Bar back button and use our own Custom button for the back button as I explained at the beginning. 😀

Now I know when we are to replace the Back button of iOS, we need to replace it with the same similar looking back button, although its custom. This is not really an easy task, because we need to construct the identical back button from the scratch, including the image, fonts and inset values and so on. I have written a complete blog post about this in one of my previous posts. If you want you could refer to it as for the complete explanation here : Creating an identical Custom Navigation Bar Back Button in Xamarin iOS…

But for the sake of this post, I shall post the whole implementation here, but I shall not drill down to detailed explanation. 🙂 You can always prefer to the original post up there.. 😉

Now keep in mind for iOS you need to override the ViewWillAppear() method in your CoolContentPageRenderer class.

So the below code should be placed inside your CoolContentPageRenderer class…

public override void ViewWillAppear(bool animated)
{
     base.ViewWillAppear(animated);
     
     if (((CoolContentPage)Element).EnableBackButtonOverride)
     {
          SetCustomBackButton();
     }
}

private void SetCustomBackButton()
{
     // Load the Back arrow Image
     var backBtnImage = 
     UIImage.FromBundle("iosbackarrow.png");

     backBtnImage = 
     backBtnImage.ImageWithRenderingMode
     (UIImageRenderingMode.AlwaysTemplate);

     // Create our Button and set Edge 
     // Insets for Title and Image
     var backBtn = new UIButton(UIButtonType.Custom)
     {
          HorizontalAlignment =   
          UIControlContentHorizontalAlignment.Left,
          TitleEdgeInsets = 
          new UIEdgeInsets(11.5f, 15f, 10f, 0f),
          ImageEdgeInsets = 
          new UIEdgeInsets(1f, 8f, 0f, 0f)
     };

     // Set the styling for Title
     // You could set any Text as you wish here
     backBtn.SetTitle("Back", UIControlState.Normal);
     // use the white color in ios back button text
     backBtn.SetTitleColor(UIColor.White,
     UIControlState.Normal); 
     backBtn.SetTitleColor(UIColor.LightGray, 
     UIControlState.Highlighted);
     backBtn.Font = UIFont.FromName("HelveticaNeue",
     (nfloat)17);

     // Set the Image to the button
     backBtn.SetImage(backBtnImage, UIControlState.Normal);

     // Allow the button to Size itself
     backBtn.SizeToFit();

     // Add the Custom Click event you would like to 
     // execute upon the Back button click
     backBtn.TouchDown += (sender, e) =>
     {
          // Whatever your custom back button click handling
          if(((CoolContentPage)Element)?.
          CustomBackButtonAction != null)
          {    
            ((CoolContentPage)Element)?.
               CustomBackButtonAction.Invoke();
          }
     };

     //Set the frame of the button
     backBtn.Frame = new CGRect(
          0,
          0,
          UIScreen.MainScreen.Bounds.Width / 4,
          NavigationController.NavigationBar.Frame.Height);

     // Add our button to a container
     var btnContainer = new UIView(
     new CGRect(0, 0, 
     backBtn.Frame.Width, backBtn.Frame.Height));
     btnContainer.AddSubview(backBtn);

     // A dummy button item to push our custom  back button to
     // the edge of screen (sort of a hack)
     var fixedSpace = 
     new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace)
     {
          Width = -16f
     };
     // wrap our custom back button with a UIBarButtonItem
     var backButtonItem = new UIBarButtonItem("",
     UIBarButtonItemStyle.Plain, null)
     {
          CustomView = backBtn
     };

     // Add it to the ViewController
     NavigationController.TopViewController.
     NavigationItem.LeftBarButtonItems 
     = new[] { fixedSpace, backButtonItem };
}

 

Alright there you have it, now keep in mind you need to attach the iosbackarrow.png image to your Xamarin Forms solution’s iOS project’s Resources folder. 😉

As I mentioned above I will not be getting down to the details of the above implementation, but I will explain the nuts and bolts related to this post.

So if you notice above we are creating a custom button and we are subscribing to the TouchDown event of it, which is where we are going to check if the current page has subscribed to the CustomBackButtonAction event or not and proceed with the custom action or default back stack navigation event… 😀

Simple as that! 😉

How to use it, you asked?

Alright let’s consume this beautiful implementation! 😉

So here I’m using our CoolContentPage as a XAML page in my Xamarin Forms solution.

<WhateverYourNamespace:CoolContentPage 
 xmlns="http://xamarin.com/schemas/2014/forms"
 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
 xmlns:WhateverYourNamespace=
 "clrnamespace:XFNavBarBackBtnClickOverride;
 assembly=XFNavBarBackBtnClickOverride"
 x:Class="XFNavBarBackBtnClickOverride.Page2"             
 Title="Page 3"
 EnableBackButtonOverride="True"
 BackgroundColor="#00bfff">
  <StackLayout
    Spacing="20"
    Padding="20,10,20,10"
    VerticalOptions="Center"
    HorizontalOptions="Center" >

    <Label Text="This is the cool page, 
	which has the Navigation Bar Back button 
	click overriden. How go ahead and click that Back     
        button! ;)"
           FontSize="20"
           HorizontalTextAlignment="Center"
           TextColor="White"/>
    
  </StackLayout>
</WhateverYourNamespace:CoolContentPage>

 

You can notice that I’m setting the EnableBackButtonOverride=”True” property for enabling the overriding of the nav bar custom back button click.

So here’s in the code behind we are subscribing to the CustomBackButtonAction with our Alert dialog asking a verification if the user is sure that they want to go back.

namespace WhateverYourNamespace
{
    public partial class Page2 : CoolContentPage
    {
        public Page2()
        {
            InitializeComponent();
            
            if (EnableBackButtonOverride)
            {
                this.CustomBackButtonAction = async () =>
                {
                    var result = await this.DisplayAlert(null,
                        "Hey wait now! are you sure " +
                        "you want to go back?",
                        "Yes go back", "Nope");

                    if (result)
                    {
                        await Navigation.PopAsync(true);
                    }
                };
            }
        }
    }
}

 

Pay good attention here where if the user confirms they want to go back, then we will manually Pop the page by calling  Navigation.PopAsync() method. If not the back button click event will be ignored thanks to our custom back button click event overriding implementation. 😀

Now keep in mind, subscribing to the Action can be done in many other different ways, code-behind may not be the best practice if you’re heavy MVVM minded, where as may be you could move the custom Action event subscription to the CoolContentPage’s OnAppearing event or base class. All up to your preferences… 😉

Alright, let’s fire it up!

Oh child, just hit that F5! 😉

  

Look at that beauty! 😀 Well the colors and stylings I added myself though.. 😉

So you may grab the code up in my Github: Xamarin-Playground/XFNavBarBackBtnClickOverride

There you go fellas!

Happy coding and share the love! 😀

Udara Alwis out!

Creating an identical Custom Navigation Bar Back Button in Xamarin iOS…

Now there comes a time when the Developer has to override or customize the Back Button in their Xamarin iOS app. Well I’ve been there, hence let me share my experience…

Now the origin of my experience is that, I wanted to override the Back button click event of my Xamarin iOS, but since there’s no way to actually “override” the back button event, I had to completely get rid of the default back button and implement my own custom back button, but it had to be exactly similar as the original iOS back button…

45ffk

So let me ask you…

Have you ever wanted to override your Navigation Bar Back button in iOS  with Xamarin? or specially override it with an identical or similar looking custom button? may be to gain control of the Back button click event?

Then this post is for you… 😀

tumblr_inline_nl7ryzqono1rkrh6k

Custom, but Similar to the actual Back Button…

Yes that’s right, let me highlight the identical or similar looking custom back button, because it’s pretty simple and straightforward to override or replace the back button, but its a bit of struggle when you want to implement a custom back button which looks identical or similar to the original back button in iOS.

The key…

So the key things to keep in mind is that,

  • We need use an Image with a “Back Arrow” that is similar from look and size of the original back button.
  • Use similar Font size to display the Text
  • Use necessary padding and x/y values to place the Image and Text Title properly

Alright, let’s get into it…

Image with Back Arrow…

Now to find the image for the Back Arrow just google “iphone back button png” or something similar, you could easily find lots, I would recommend to use the icons8 website, which is where I got mine, https://icons8.com/web-app/15157/back

Make sure there’s no padding between the Image pixel space and the borders, in my case the image was 24×41 size

screen-shot-2017-03-02-at-1-09-15-pm

Oh another thing, make sure the Image is PNG, White color with a transparent back ground, so that you can edit the Tint as you go later if needed… 🙂

Title Text Font…

So for this one, I had to do a bit of playing around, which I found that “HelveticaNeue” and Font Size 17 is perfect for this. 🙂

Time for the coding… 😉

So let’s start off with loading the UIImage and initializing our UIButton.

// Load the Back arrow Image
var backBtnImage = UIImage.FromBundle("iosbackarrow.png");

backBtnImage = 
	backBtnImage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);

// Create our Button and set Edge Insets for Title and Image
var backBtn = new UIButton(UIButtonType.Custom)
{
	HorizontalAlignment = UIControlContentHorizontalAlignment.Left,
	TitleEdgeInsets = new UIEdgeInsets(11.5f, 15f, 10f, 0f),
	ImageEdgeInsets = new UIEdgeInsets(1f, 8f, 0f, 0f)
};

 

And set up the necessary Edge Insets for the button Title and Image as shown above. Well those values I figured out by playing around with the positioning values for hours.. 😛 lol

Next let’s dive into the Button’s customization…

// Set the styling for Title
// You could set any Text as you wish here
backBtn.SetTitle("Back", UIControlState.Normal);
// use the default blue color in ios back button text
backBtn.SetTitleColor(UIColor.FromRGB(0, 129, 249), UIControlState.Normal); 
backBtn.SetTitleColor(UIColor.LightGray, UIControlState.Highlighted);
backBtn.Font = UIFont.FromName("HelveticaNeue", (nfloat)17);

// Set the Image to the button
backBtn.SetImage(backBtnImage, UIControlState.Normal);

// Allow the button to Size itself
backBtn.SizeToFit();

 

Alright, that’s quite a bit of code to swallow, so first we set the Title Text of the button, and keep in mind you could set any Text as you wish there, for now I’m just using “Back” text.. 🙂

Next for the Text Color in the Normal state, I have used the default Blue color variation that iOS use by default, you could also use any color you prefer as well 🙂 Next we set the Highlight state of Text to Light Gray.

As we discussed at the beginning we will use HelveticaNeue with Font size of 17 for the Title Text. And finally set the Image to the Button and allow it to fit to the required size. 😀

// Add the Custom Click event you would like to 
// execute upon the Back button click
backBtn.TouchDown += (sender, e) =>
{
	// Whatever your custom back button click handling
};

 

Now here’s something very important, we need to make sure we handle our custom back button click as shown above… 😉

So next we shall do the preparation for the Frame.

//Set the frame of the button
backBtn.Frame = new CGRect(
	0,
	0,
	UIScreen.MainScreen.Bounds.Width / 4,
	NavigationController.NavigationBar.Frame.Height);

// Add our button to a container
var btnContainer = new UIView(
	new CGRect(0, 0, backBtn.Frame.Width, backBtn.Frame.Height));
btnContainer.AddSubview(backBtn);

 

So there we are adding the Frame values to our Button, where as I’m setting the width to a quarter of the Screen width, and as of the Height, I’m retrieving the NavigationBar’s height for it.

Next we need to add our UIButton to a UIView container as show above and make sure it has the same Height and Width as our UIButton.

Time to wrap things up fellas…

// A dummy button item to push our custom  back button to
// the edge of screen (sort of a hack)
var fixedSpace = new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace)
{
	Width = -16f
};
// wrap our custom back button with a UIBarButtonItem
var backButtonItem = new UIBarButtonItem("", UIBarButtonItemStyle.Plain, null)
{
	CustomView = backBtn
};

// Add it to the ViewController
NavigationController.TopViewController.NavigationItem.LeftBarButtonItems 
= new[] { fixedSpace, backButtonItem };

 

So here’s the final steps, we are wrapping our button’s uiview container inside the UIBarButtonItem by setting it to the CustomView property. And then add it to the LeftBarButtonItems , which overrides the default existing Back Button.

Now you may wonder why there’s another UIBarButtonItem with the Width set to -16 value, this is actually to forcefully push our custom back button to the edge of the Navigation Bar. 😀 So that right, it is more of a hack to get the job done… 😉

See it in action…

So here’s our Custom iOS Back Button in action… 😀

screen-shot-2017-03-02-at-12-16-10-pm

Just for the sake of comparing here’s the default system Back Button in iOS…

screen-shot-2017-03-02-at-12-15-54-pm

Looks almost identical yeah! 😀

Well, that’s it fellas!

Enjoy! 😀

PS: I may have gotten some help from these posts on StackOverflow:

http://stackoverflow.com/questions/18384488/ios-7-uibarbutton-back-button-arrow-color
http://stackoverflow.com/questions/227078/creating-a-left-arrow-button-like-uinavigationbars-back-style-on-a-uitoolba

Le silly meaningless random string generator…

So here’s something I put together quickly by grabbing from stackoverflow, to generate some meaningless random string based on a given length of letters. 😀 This is actually a simple dot net implementation where as you could use it as a static class and use it anywhere you want. may be? up to you!

Here it is!

namespace WhateverYourNamespace
{
    public static class RandomWordGenerator
    {
        /// <summary>
        /// Just to generate some random words! 😛
        /// </summary>
        /// <param name="requestedLength"></param>
        /// <returns></returns>
        public static string GetMeaninglessRandomString(int requestedLength)
        {
            Random rnd = new Random();
            string[] consonants = { "b", "c", "d", "f", "g", "h", "j", "k",
                "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z" };
            string[] vowels = { "a", "e", "i", "o", "u" };

            string word = "";

            if (requestedLength == 1)
            {
                word = GetRandomLetter(rnd, vowels);
            }
            else
            {
                for (int i = 0; i < requestedLength; i += 2)
                {
                    word += GetRandomLetter(rnd, consonants) + 
                        GetRandomLetter(rnd, vowels);
                }

                word = word.Replace("q", "qu").Substring(0, requestedLength);
                // We may generate a string longer than requested length, 
                // but it doesn't matter if cut off the excess.
            }

            return word;
        }

        private static string GetRandomLetter(Random rnd, string[] letters)
        {
            return letters[rnd.Next(0, letters.Length - 1)];
        }
    }
}

 

Now I don’t own this original implementation, I just put it into a static class and used in one of my apps. Sorry I don’t have the actual source of it. 😦 but I do recall I grab it from stackoverflow.

Anyways use it as you wish.

KTHANKSBYE!

lol

Is your Visual Studio stuck at, Emulator is already running?

So few days back after doing a fresh installation on my WIndows 10 laptop, and installing Visual Studio, I tried running a Xamarin Forms project, with the Visual Studio Android Emulator.

The project was successfully building itself, and the Visual Studio Android Emulator also started running successfully, but then the build process was on a hang state after the Emulator started running. Specifically the build log was on a hang state after “Emulator is already running” step, as I saw in the output log in VS.

So after Googling a while I figured out the problem thanks to wasting a bunch on hours on google search and forums, since many others were also having the same issue.

So let me post the solution for you right here.

Cause?

You must keep in mind that my project was building fine, and the Emulator also started running successfully and booted up itself. I was having a already built solution and up and running Emulator, but the VS couldn’t connect to the Emulator.

The cause for this is Visual Studio debugger was unable to connect to the started Emulator through the ADB (Android Debug Bridge).

This is due a wrong registry entry in the system, where as Visual Studio is looking to start up the ADB and connect to it, in order to connect to the Emulator, but due to this wrong registry entry, VS is unable to find the path to ADB, to start it up.

This is very well explained in this Visual Studio troubleshoot article:

https://msdn.microsoft.com/en-us/library/mt228282.aspx?f=255&MSPPError=-2147217396#ADB

This seem to be happening by default with fresh installations of VS lately, where as the Android SDK installation path in the above registry entry doesn’t seem to be matching with the actual SDK installation location in our system, which is probably done by default when installing Visual Studio 2015.

Solution!

So yeah as the article explains we just have to update the registry entry with the accurate path to the Android SDK installation in our system, so that Visual Studio can start up ADB to connect to the Emulator.

Step1 : Copy the actual Android SDK installation path

to find the actual Android SDK path in your system, that is referred by Visual Studio, go to the top tool bar of Visual Studio, and open the Android SDK Manager as shown below.

capture-3

If you did the default Visual Studio installation with the Cross-Platform mobile dev tools, then your path location should also look similar as above.

Copy that path, or type the same exact path on Run command and open the folder and copy the full path from there.

Step2 : Update the invalid registry entry

Open registry editor, by “regedit” in Run window and navigate to the following Registry.

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools

Now open the Path registry key and change the value with the above Android SDK path which you copied earlier.

capture-2

Well, that’s it.

There goes the solution. Now you should close the Emulator and Visual Studio and reopen your solution, hit F5! you’re all good! 😀

Cheers!

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