iOS

#CASBAN6: Creating A Serverless Blog on Azure with .NET 6 (new series)

#CASBAN6: Creating A Serverless Blog on Azure with .NET 6 (new series)

Motivation

I was planning to run my blog without WordPress for quite some time. For one, because WordPress is really blown up as a platform. The second reason is more of a practical nature – this project gives me lots of stuff to improve my programming skills. I already started to move my developer website away from WordPress with ASP.NET CORE and Razor Pages. Eventually I arrived at the point where I needed to implement a blog engine for the news section. So, I have two websites (including this one here) that will take advantage of the outcome of this journey.

High Level Architecture

Now that the ‘why’ is clear, let’s have a look at the ‘how’:

There are several layers in my concept. The data layer consists of a serverless MS SQL instance on Azure, on which I will work with the help of Entity Framework Core and Azure Functions for all the CRUD operations of the blog. I will use the powers of Azure API Management, which will allow me to provide a secure layer for the clients – of course, an ASP.NET CORE Website with RazorPages, flanked by a .NET MAUI admin client (no web administration). Once the former two are done, I will also add a mobile client for this blog. It will be the next major update for my existing blog reader that is already in the app stores.

For comments, I will use Disqus. This way, I have a proven comment system where anyone can use his/her favorite account to participate in discussions. They also have an API, so there is a good chance that I will be able to implement Disqus in the Desktop and Mobile clients.

Last but not least, there are (for now) two open points – performance measuring/logging and notifications. I haven’t decided yet how to implement these – but I guess there will be an Azure based implementation as well (until there are good reasons to use another service).

Open Source

Most of the software I will write and blog about in this series will be available publicly on GitHub. You can find the repository already there, including stuff for the next two upcoming blog posts already in there.

Index

I will update this blog post regularly with a link new entries of the series.

Additional note

Please note that I am working on this in my spare time. This may result in delays between the blog posts and the updates committed into the repository on GitHub.

Until the next post – happy coding, everyone!


Title Image by Roman from Pixabay

Posted by msicc in Android, Azure, Dev Stories, iOS, MAUI, Web, 2 comments
Use the iOS system colors in Xamarin.Forms (Updated)

Use the iOS system colors in Xamarin.Forms (Updated)

Update

After publishing this post, Gerald Versluis from Microsoft responded on Twitter with an interesting information on how to get the system colors into our ResourceDictionary without using the DependencyService:

I had a quick look at the NamedPlatformColor class, but noticed that the implementation in Xamarin.Forms is incomplete. Gerald will try to update them. Once that is done, I will update the library on Github and this post again.

Original version below:


Overview

Let me give you a short overview first. To achieve our goal to use the iOS system colors, we need just a few easy steps:

  1. Xamarin.Forms interface that defines the colors
  2. Xamarin.iOS implementation of that interface
  3. ResourceDictionary to make the colors available in XAML
  4. Merging this dictionary with the application’s resource
  5. Handling of the OnRequestedThemeChanged event

Now that the plan is clear, let’s go into details.

ISystemColors interface

We will use the Xamarin.Forms DependencyService to get the colors from iOS to Xamarin.Forms. Let’s create our common interface:

using Xamarin.Forms;

namespace [YOURNAMESPACEHERE]
{
    public interface ISystemColors
    {
        Color SystemRed { get; }
        Color SystemOrange { get; }
        Color SystemYellow { get; }
        Color SystemGreen { get; }
        Color SystemMint { get; }
        Color SystemTeal { get; }
        Color SystemCyan { get; }
        Color SystemBlue { get; }
        Color SystemIndigo { get; }
        Color SystemPurple { get; }
        Color SystemPink { get; }
        Color SystemBrown { get; }
        Color SystemGray { get; }
        Color SystemGray2 { get; }
        Color SystemGray3 { get; }
        Color SystemGray4 { get; }
        Color SystemGray5 { get; }
        Color SystemGray6 { get; }
        Color SystemLabel { get; }
        Color SecondaryLabel { get; }
        Color TertiaryLabel { get; }
        Color QuaternaryLabel { get; }
        Color Placeholder { get; }
        Color Separator { get; }
        Color OpaqueSeparator { get; }
        Color LinkColor { get; }
        Color FillColor { get; }
        Color SecondaryFillColor { get; }
        Color TertiaryFillColor { get; }
        Color QuaternaryFillColor { get; }
        Color SystemBackgroundColor { get; }
        Color SecondarySystemBackgroundColor { get; }
        Color TertiarySystemBackgroundColor { get; }
        Color SystemGroupedBackgroundColor { get; }
        Color SecondarySystemGroupedBackgroundColor { get; }
        Color TertiarySystemGroupedBackgroundColor { get; }
        Color DarkTextColor { get; }
        Color LightTextColor { get; }
    }
}

As we are not able to change any of the system colors, we are just defining getters in the interface.

The Xamarin.iOS platform implementation

The implementation is straight forward. We are implementing the interface and just get the values for each system color. The list is based on Apple’s documentation for human interface and UI element colors.

using [YOURNAMESPACEHERE];

using UIKit;

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: Dependency(typeof(SystemColors))]
namespace [YOURNAMESPACEHERE]
{
    //https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/
    //https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors

    public class SystemColors : ISystemColors
    {
        #region System Colors
        public Color SystemRed => UIColor.SystemRedColor.ToColor();
        public Color SystemOrange => UIColor.SystemOrangeColor.ToColor();
        public Color SystemYellow => UIColor.SystemYellowColor.ToColor();
        public Color SystemGreen => UIColor.SystemGreenColor.ToColor();
        public Color SystemMint => UIColor.SystemMintColor.ToColor();
        public Color SystemTeal => UIColor.SystemTealColor.ToColor();
        public Color SystemCyan => UIColor.SystemCyanColor.ToColor();
        public Color SystemBlue => UIColor.SystemBlueColor.ToColor();
        public Color SystemIndigo => UIColor.SystemIndigoColor.ToColor();
        public Color SystemPurple => UIColor.SystemPurpleColor.ToColor();
        public Color SystemPink => UIColor.SystemPinkColor.ToColor();
        public Color SystemBrown => UIColor.SystemBrownColor.ToColor();


        public Color SystemGray => UIColor.SystemGrayColor.ToColor();
        public Color SystemGray2 => UIColor.SystemGray2Color.ToColor();
        public Color SystemGray3 => UIColor.SystemGray3Color.ToColor();
        public Color SystemGray4 => UIColor.SystemGray4Color.ToColor();
        public Color SystemGray5 => UIColor.SystemGray5Color.ToColor();
        public Color SystemGray6 => UIColor.SystemGray6Color.ToColor();
        #endregion

        #region UI Element Colors
        public Color SystemLabel => UIColor.LabelColor.ToColor();
        public Color SecondaryLabel => UIColor.SecondaryLabelColor.ToColor();
        public Color TertiaryLabel => UIColor.TertiaryLabelColor.ToColor();
        public Color QuaternaryLabel => UIColor.QuaternaryLabelColor.ToColor();
        public Color Placeholder => UIColor.PlaceholderTextColor.ToColor();
        public Color Separator => UIColor.SeparatorColor.ToColor();
        public Color OpaqueSeparator => UIColor.SeparatorColor.ToColor();
        public Color LinkColor => UIColor.SeparatorColor.ToColor();

        public Color FillColor => UIColor.SystemFillColor.ToColor();
        public Color SecondaryFillColor => UIColor.SecondarySystemFillColor.ToColor();
        public Color TertiaryFillColor => UIColor.TertiarySystemFillColor.ToColor();
        public Color QuaternaryFillColor => UIColor.QuaternarySystemFillColor.ToColor();

        public Color SystemBackgroundColor => UIColor.SystemBackgroundColor.ToColor();
        public Color SecondarySystemBackgroundColor => UIColor.SecondarySystemBackgroundColor.ToColor();
        public Color TertiarySystemBackgroundColor => UIColor.TertiarySystemBackgroundColor.ToColor();

        public Color SystemGroupedBackgroundColor => UIColor.SystemGroupedBackgroundColor.ToColor();
        public Color SecondarySystemGroupedBackgroundColor => UIColor.SecondarySystemGroupedBackgroundColor.ToColor();
        public Color TertiarySystemGroupedBackgroundColor => UIColor.TertiarySystemGroupedBackgroundColor.ToColor();

        public Color DarkTextColor => UIColor.DarkTextColor.ToColor();
        public Color LightTextColor => UIColor.LightTextColor.ToColor();

        #endregion
    }
}

Do not forget to add the Dependency attribute on top of the implementation, otherwise it won’t work.

The ResourceDictionary

As I prefer defining my UI in XAML in Xamarin.Forms, I naturally want those colors to be available there as well. This can be done by loading the colors into a ResourceDictionary. As you might remember, I prefer codeless ResourceDictionary implementations. This time, however, we need the code-behind file to make the ResourceDictionary work for us.

First, add a new ResourceDictionary:

Add_ResourceDictionary_XAML

Then, in the code-behind file, we are using the DependencyService of Xamarin.Forms to add the colors to the ResourceDictionary:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace [YOURNAMESPACEHERE]
{
    public partial class SystemColorsIosResourceDictionary
    {
        public SystemColorsIosResourceDictionary()
        {
            InitializeComponent();

            this.Add(nameof(ISystemColors.SystemRed), DependencyService.Get<ISystemColors>().SystemRed);
            this.Add(nameof(ISystemColors.SystemOrange), DependencyService.Get<ISystemColors>().SystemOrange);
            this.Add(nameof(ISystemColors.SystemYellow), DependencyService.Get<ISystemColors>().SystemYellow);
            this.Add(nameof(ISystemColors.SystemGreen), DependencyService.Get<ISystemColors>().SystemGreen);
            this.Add(nameof(ISystemColors.SystemMint), DependencyService.Get<ISystemColors>().SystemMint);
            this.Add(nameof(ISystemColors.SystemTeal), DependencyService.Get<ISystemColors>().SystemTeal);
            this.Add(nameof(ISystemColors.SystemCyan), DependencyService.Get<ISystemColors>().SystemCyan);
            this.Add(nameof(ISystemColors.SystemBlue), DependencyService.Get<ISystemColors>().SystemBlue);
            this.Add(nameof(ISystemColors.SystemIndigo), DependencyService.Get<ISystemColors>().SystemIndigo);
            this.Add(nameof(ISystemColors.SystemPurple), DependencyService.Get<ISystemColors>().SystemPurple);
            this.Add(nameof(ISystemColors.SystemPink), DependencyService.Get<ISystemColors>().SystemPink);
            this.Add(nameof(ISystemColors.SystemBrown), DependencyService.Get<ISystemColors>().SystemBrown);


            this.Add(nameof(ISystemColors.SystemGray), DependencyService.Get<ISystemColors>().SystemGray);
            this.Add(nameof(ISystemColors.SystemGray2), DependencyService.Get<ISystemColors>().SystemGray2);
            this.Add(nameof(ISystemColors.SystemGray3), DependencyService.Get<ISystemColors>().SystemGray3);
            this.Add(nameof(ISystemColors.SystemGray4), DependencyService.Get<ISystemColors>().SystemGray4);
            this.Add(nameof(ISystemColors.SystemGray5), DependencyService.Get<ISystemColors>().SystemGray5);
            this.Add(nameof(ISystemColors.SystemGray6), DependencyService.Get<ISystemColors>().SystemGray6);

            this.Add(nameof(ISystemColors.SystemLabel), DependencyService.Get<ISystemColors>().SystemLabel);
            this.Add(nameof(ISystemColors.SecondaryLabel), DependencyService.Get<ISystemColors>().SecondaryLabel);
            this.Add(nameof(ISystemColors.TertiaryLabel), DependencyService.Get<ISystemColors>().TertiaryLabel);
            this.Add(nameof(ISystemColors.QuaternaryLabel), DependencyService.Get<ISystemColors>().QuaternaryLabel);

            this.Add(nameof(ISystemColors.Placeholder), DependencyService.Get<ISystemColors>().Placeholder);
            this.Add(nameof(ISystemColors.Separator), DependencyService.Get<ISystemColors>().Separator);
            this.Add(nameof(ISystemColors.OpaqueSeparator), DependencyService.Get<ISystemColors>().OpaqueSeparator);
            this.Add(nameof(ISystemColors.LinkColor), DependencyService.Get<ISystemColors>().LinkColor);

            this.Add(nameof(ISystemColors.FillColor), DependencyService.Get<ISystemColors>().FillColor);
            this.Add(nameof(ISystemColors.SecondaryFillColor), DependencyService.Get<ISystemColors>().SecondaryFillColor);
            this.Add(nameof(ISystemColors.TertiaryFillColor), DependencyService.Get<ISystemColors>().TertiaryFillColor);
            this.Add(nameof(ISystemColors.QuaternaryFillColor), DependencyService.Get<ISystemColors>().QuaternaryFillColor);

            this.Add(nameof(ISystemColors.SystemBackgroundColor), DependencyService.Get<ISystemColors>().SystemBackgroundColor);
            this.Add(nameof(ISystemColors.SecondarySystemBackgroundColor), DependencyService.Get<ISystemColors>().SecondarySystemBackgroundColor);
            this.Add(nameof(ISystemColors.TertiarySystemBackgroundColor), DependencyService.Get<ISystemColors>().TertiarySystemBackgroundColor);

            this.Add(nameof(ISystemColors.SystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().SystemGroupedBackgroundColor);
            this.Add(nameof(ISystemColors.SecondarySystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().SecondarySystemGroupedBackgroundColor);
            this.Add(nameof(ISystemColors.TertiarySystemGroupedBackgroundColor), DependencyService.Get<ISystemColors>().TertiarySystemGroupedBackgroundColor);

            this.Add(nameof(ISystemColors.DarkTextColor), DependencyService.Get<ISystemColors>().DarkTextColor);
            this.Add(nameof(ISystemColors.LightTextColor), DependencyService.Get<ISystemColors>().LightTextColor);

        }
    }
}

That’s all for the implementation. Now let’s start having a look at how to use the whole code we wrote until now.

Merging the ResourceDictionary

In Xamarin.Forms, we are able to merge ResourceDictionary classes to make them available for the whole app or on view/page level only. I consider our above created dictionary as an app-level dictionary. On top, to make it reusable, I put all these classes in a separate multi-platform library, which you can find here on Github.

Please note that the syntax will be a little different if you implement the ResourceDictionary directly in your app. Using the library approach, you will merge the dictionary in this way in App.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<Application
    x:Class="SystemColorsTest.App"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:systemcolors="clr-namespace:MSiccDev.Libs.iOS.SystemColors;assembly=MSiccDev.Libs.iOS.SystemColors">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <systemcolors:SystemColorsIosResourceDictionary />
                <!--  more dictionaries here  -->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Responding to system theme changes

Even if I personally only change the system theme at runtime for testing themes in my apps, your users may do so frequently. Luckily, it is just a matter of handling an event to handle this scenario. In your App.xaml.cs file, register for the RequestedThemeChanged event within the constructor:

        public App()
        {
            InitializeComponent();

            Application.Current.RequestedThemeChanged += OnRequestedThemeChanged;

            this.MainVm = new MainViewModel();
            MainPage mainPage = new MainPage()
            {
                BindingContext = this.MainVm
            };

            MainPage = mainPage;
        }

As the system colors respond to the system theme change, we need to reload them to get these changes.

Within the OnRequestedThemeChanged method, we are first getting the actual merged ResourceDictionary instance. Then, we will remove this instance and register a new instance of the ResourceDictionary. This will lead to a full reload of the system colors from iOS into the app. Here is the code:

private void OnRequestedThemeChanged(object sender, AppThemeChangedEventArgs e)
{
    ResourceDictionary iosResourceDict = App.Current.Resources.MergedDictionaries.SingleOrDefault(dict => dict.GetType() == typeof(SystemColorsIosResourceDictionary));

    if (iosResourceDict != null)
    {
        App.Current.Resources.MergedDictionaries.Remove(iosResourceDict);
        App.Current.Resources.MergedDictionaries.Add(new SystemColorsIosResourceDictionary());
    }
}

That’s it, we are now ready to use the colors in XAML and our app adapts to system theme changes. Here is a sample XAML which I wrote to test the colors:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="SystemColorsTest.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:SystemColorsTest"
    x:DataType="local:MainViewModel"
    BackgroundColor="{DynamicResource SystemBackgroundColor}">

    <StackLayout>
        <Frame
            Padding="12,42,24,12"
            BackgroundColor="{DynamicResource SystemGray3}"
            CornerRadius="0">
            <Label
                FontSize="36"
                HorizontalTextAlignment="Center"
                Text="iOS SystemColors in XF"
                TextColor="{AppThemeBinding Dark={DynamicResource LightTextColor},
                                            Light={DynamicResource DarkTextColor}}" />
        </Frame>

        <ScrollView>
            <StackLayout BindableLayout.ItemsSource="{Binding SystemColors}">
                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <Frame
                            Margin="6,3"
                            x:DataType="local:SystemColorViewModel"
                            BackgroundColor="{Binding Value}">
                            <Label Text="{Binding Name}" />
                        </Frame>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
        </ScrollView>
    </StackLayout>
</ContentPage>

Please note that I use DynamicResource instead of StaticResource, even if some colors are static. Using DynamicResource forces the app to reload the colors, and there are some that change (like the SystemGray color palette).

Conclusion

Using the iOS system colors in Xamarin.Forms isn’t that complicated with this implementation. If you have more platforms, you could implement the same technique for the other platforms. As I am focusing on iOS for the moment, I just wrote that part. But who knows, maybe this will be extended in the future.

As always, I hope this post will be helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Dev Stories, iOS, Xamarin, 5 comments
Dealing with the System UI on iOS in Xamarin.Forms

Dealing with the System UI on iOS in Xamarin.Forms

Having written a few applications with Xamarin.Forms by now, there was always the one part where you have to go platform specific. Over time, this part got easier as the collection of Platform-specifics in the Xamarin.Forms package was growing and growing.

This post will show (my) most used implementations leveraging the comfort of Platform-specifics as well as some other gotchas I collected over time. At the end of this post, you will also find a link to a demo project on my Github.

Large page title

Let’s start on top (literally). With iOS 11, Apple introduced large title’s that go back to small once the user is scrolling the content.

To make your app use this feature, you need two perform two steps. The first step is to tell your NavigationPage instance to prefer large titles. I often do this when creating my apps MainPage in App.xaml.cs:

public App()
{
    InitializeComponent();

    var navigationPage = new Xamarin.Forms.NavigationPage(new MainPage())
    {
        BarBackgroundColor = Color.DarkGreen,
        BarTextColor = Color.White
    };

    navigationPage.On<iOS>().SetPrefersLargeTitles(true);

    MainPage = navigationPage; 
}

This opens the door to show large titles on all pages that are managed by this NavigationPage instance. Sometimes, however, you need to actively tell the page it should use the large title (mostly happened to me in my base page implementation – never was able to nail it down to a specific point. I just opted in to always explicitly handle it on every page. In the sample application for this post, you will find a switch to toggle and untoggle the large title on the app’s MainPage:

On<iOS>().SetLargeTitleDisplay(_useLargeTitle ? 
LargeTitleDisplayMode.Always : 
LargeTitleDisplayMode.Never);

You can read more in the documentation.

StatusBar text color

Chances are high that we are customizing the BarBackgroundColor and BarTextColor properties. Of course, it makes absolutely sense that the StatusBar text follows the BarTextColor. Luckily, there is a Platform-specific for that as well:

if (this.Parent is Xamarin.Forms.NavigationPage navigationPage)
{
    navigationPage.On<iOS>().SetStatusBarTextColorMode(_statusBarTextFollowNavBarTextColor ? 
                             StatusBarTextColorMode.MatchNavigationBarTextLuminosity : 
                             StatusBarTextColorMode.DoNotAdjust);
}

The documentation ends here. However, I always need to add/change the Info.plist file as well:

<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

Only after adding this value the above-mentioned trick for the StatusBar text works.

On iOS, the NavigationBar has a separator on its bottom. If you want to hide this separator (which always disturbs the view), you can leverage another Platform-specific on your page:

if (this.Parent is Xamarin.Forms.NavigationPage navigationPage)
{
    navigationPage.On<iOS>().SetHideNavigationBarSeparator(_hideNavBarSeparator);
}

Home indicator visibility

All iPhones after the iPhone 8 (except the SE 2) do not have the home button. Instead, they have a home indicator on the bottom of the device (at least in app). If you are trying to set the color on it, I have bad news for you: you can’t (read on to learn why).

You can hide the indicator in your app, however. Just use this Platform-specific:

On<iOS>().SetPrefersHomeIndicatorAutoHidden(_hideHomeIndicator);

Home indicator background color

Hiding the home indicator is a hard measure. Most users do not even really recognize the indicator if it is incorporated into the app’s UI. To better understand how the home indicator works, I absolutely recommend to read Nathan Gitter’s great post on the topic.

The home indicator is adaptive to its surroundings. Most probably using a matching background color is all it needs to integrate the indicator nicely in your app(s).

Safe area

Thanks to the notch and the home indicator, putting content of our apps got trickier than before. However, Xamarin.Forms has you covered as well. All we have to do is to use the SetUseSafeArea Platform-specific – it will allow us to just use the area where we are not covering any System UI like the StatusBar or the home indicator:

On<iOS>().SetUseSafeArea(_useSafeArea);

Conclusion

Even though iOS has some specialties when it comes to the System UI, Xamarin.Forms has the most important tools built in to deal with them. I absolutely recommend creating a base page for your applications and set the most common specifics there. You can find the promised demo project here on Github. Like always, I hope this post is helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Dev Stories, iOS, Xamarin, 2 comments
Fix ‘Xcode is not currently installed or could not be found’ error in Visual Studio 2019 for Mac

Fix ‘Xcode is not currently installed or could not be found’ error in Visual Studio 2019 for Mac

Every now and then, our IDE’s get some updates. This week, Visual Studio for MacOS got updated once again. After that, there was a separated Download initiated for the Xcode Command Line Tools. Two days later, Visual Studio started to greet me with this little message:

Xcode missing message VS Mac

Of course, I checked first that my installed version of Xcode is still working – it stopped already for me some time ago and I had to reinstall it. As you can see, that was not the case:

Xcode 12.5 about window

After doing some research on the web, others had similar issues. The problem was that the installation of the Xcode CLI tools has overridden the location of Xcode in Preferences – as you can see in the

The fix is easy, just paste /Applications/Xcode.app/ into the location field. Please note that the trailing slash is also important:

The dialog will immediately verify the existence of Xcode (at least in version 8.9.10). Just hit that restart button and you are once again good to go.

As always, I hope this short post will be helpful for some of you.

Until the next post – happy coding, everyone.

Posted by msicc in Dev Stories, iOS, Xamarin, 3 comments
Extending Xamarin.Forms.Nuke on iOS to load a placeholder for images that fail to load

Extending Xamarin.Forms.Nuke on iOS to load a placeholder for images that fail to load

What is Xamarin.Forms.Nuke?

Xamarin.Forms.Nuke is a Xamarin.Forms implementation of Nuke, one of the most advanced image libraries on iOS today. The Xamarin.Forms implementation focuses heavily on caching only, while the original library has a bunch of more features. I learned about this library when I started to look for an alternative to cache images via Akavache which I used before (I never blogged about that part because it wasn’t ready for that, tbh).

Why do we need to extend the library?

The library currently does only one thing (pretty well) – handling the caching of web images. It uses the default settings of the native Nuke library. The Xamarin.Forms implementation overwrites the ImageSourceHandler for UriImageSource and FileImageSource (optionally), but the case of placeholder loading is not intended in the original version. As I have multiple scenarios where a placeholder comes in handy, I decided to extend the library – and maintain my own fork of it from now on. (Maybe there will be a pull request to the original source, too).

Show me some code, finally!

For our extension, we modify the FormsHandler class as well as the ImageSourceHandler class. Let’s have a look at the FormsHandler class first. We are adding a new property for the placeholder:

public static ImageSource PlaceholderImageSource { get; private set; }

With that property in place, let’s add two methods. One method is for loading a placeholder image from an embedded resource file, while the second one is for specifying a FontImageSource.

public static void PlaceholderFromResource(string resourceName, Assembly assembly) =>
    PlaceholderImageSource = ImageSource.FromResource(resourceName, assembly);

public static void PlaceholderFromFontImageSource(FontImageSource fontImageSource) =>
    PlaceholderImageSource = fontImageSource;

I have chosen the FormsHandler class because setting the placeholder is a global thing (in my scenarios, your mileage may vary). That’s already everything in takes in the FormsHandler class, so let’s have a look at the ImageSourceHandler class.

As we are using the default Xamarin.Forms ImageSourceHandler for the resource image (which is a StreamImageSource) and the FontImageSource, we need to add the static fields for them first:

private static readonly StreamImagesourceHandler DefaultStreamImageSourceHandler = new StreamImagesourceHandler();

private static readonly FontImageSourceHandler DefaultFontImageSourcehandler = new FontImageSourceHandler();

Now let’s implement the loading of the placeholder in a separate method:

private static Task<UIImage> LoadPlaceholderAsync()
{
    switch (FormsHandler.PlaceholderImageSource)
    {
        case StreamImageSource streamImageSource:
            FormsHandler.Warn($"loading placeholder from resource");
            return DefaultStreamImageSourceHandler.LoadImageAsync(streamImageSource);
                    
        case FontImageSource fontImageSource:
            FormsHandler.Warn($"loading placeholder from Font");
            return DefaultFontImageSourcehandler.LoadImageAsync(fontImageSource);
        default:
            FormsHandler.Warn($"no valid placeholder found");
            return null;
    }
}

As you can see, there is nothing overly complicated in this method. Based on the type of the placeholder set in the FormsHandler class, we are calling the default Xamarin.Forms implementation for the placeholder image. Let’s take this code into action by changing the LoadImageAsync method of the ImageSourceHandler:

public async Task<UIImage> LoadImageAsync(
    ImageSource imageSource,
    CancellationToken cancellationToken = new CancellationToken(),
    float scale = 1)
{
    var result = await NukeHelper.LoadViaNuke(imageSource, cancellationToken, scale);
    if (result == null)
        result = await LoadPlaceholderAsync();

    return result;
}

As we need to know if the Nukehelper class is able to load the image, we are already running the code by awaiting it at this level. If the result is null, we are loading the placeholder image via our prior implemented method. That’s all we need to do in our forked Xamarin.Forms.Nuke repository.

How to use it in your Xamarin.Forms – iOS project

First, clone my fork (or fork it if you want) of the Xamarin.Forms.Nuke repository and import it into your Xamarin.Forms solution and reference it in your iOS project. Once that is done, we need to initialize the Nuke library (like in the original source) in the AppDelegate‘s FinishedLaunching method:

Xamarin.Forms.Nuke.FormsHandler.Init(true, false);

The second step is to define the placeholder image source. The FontImageSource should be defined after the LoadApplication method. This way, you can the Xamarin.Forms way of loading the font as a resource.

//Resource image
Xamarin.Forms.Nuke.FormsHandler.PlaceholderFromResource("CachedImageTest.MSicc_Logo_Base_Blue_1024px_pad25.png", Assembly.GetAssembly(typeof(MainViewModel)));

//FontImageSource
Xamarin.Forms.Nuke.FormsHandler.PlaceholderFromFontImageSource(new FontImageSource
{
    Glyph = CachedImageTest.Resources.MaterialDesignIcons.ImageBroken,
    FontFamily = "MaterialDesignIcons",
    Color = Color.Red
});

Now use the Xamarin.Forms Image control like you always do. If the image from the web cannot be loaded, you will see the placeholder, like in these two examples:

cached image placeholder sample
Left: Single image failed loading, right image in CollectionView failed loading

With a few additions to the Xamarin.Forms.Nuke library, we have implemented a placeholder mechanism for images that can’t be loaded. As always, I hope this post will be useful for some of you. Now that I have the iOS implementation of a fast cached image with placeholder loading in place, I will turn to Android, where I will try to achieve the same using the Glidex.Forms library and extend it to load a placeholder. There will be a full sample once that is implemented as well. Stay tuned for that one!

Until the next post, happy coding, everyone!
Posted by msicc in Dev Stories, iOS, Xamarin, 2 comments
Create scrollable tabs in Xamarin.Forms with CollectionView and CarouselView

Create scrollable tabs in Xamarin.Forms with CollectionView and CarouselView

When it comes to navigation patterns in mobile apps, the tabbed interface is one of the most popular options. While Xamarin.Forms has the TabbedPage (and Shell) to fulfill that need, it lacks one essential feature: scrollable tabs. After studying some of the samples floating around the web and some of the packages that provide such functionality, I tried find an easier solution.

The View

Let’s have a look at the View first. Like you may have guessed from the title, we are using a CollectionView for the tabs and a CarouselView for the Content. This combination makes it quite easy to implement tabs that cover a whole page size or smaller ones within a page.

Here’s the XAML:

<Grid x:DataType="{x:Null}" RowSpacing="0">
    <Grid.RowDefinitions>
        <RowDefinition Height="45" />
        <RowDefinition Height="45" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <CollectionView
        x:Name="CustomTabsView"
        Grid.Row="1"
        HorizontalScrollBarVisibility="Never"
        ItemSizingStrategy="MeasureAllItems"
        ItemsSource="{Binding TabVms}"
        ItemsUpdatingScrollMode="KeepItemsInView"
        SelectedItem="{Binding CurrentTabVm, Mode=TwoWay}"
        SelectionMode="Single"
        VerticalScrollBarVisibility="Never">
        <CollectionView.ItemsLayout>
            <LinearItemsLayout Orientation="Horizontal" />
        </CollectionView.ItemsLayout>
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="local:TabViewModel">
                <Grid RowSpacing="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="3" />
                    </Grid.RowDefinitions>
                    <Label
                        x:Name="TitleLabel"
                        Grid.Row="0"
                        Padding="15,0"
                        FontAttributes="Bold"
                        FontSize="Small"
                        HeightRequest="50"
                        HorizontalTextAlignment="Center"
                        Text="{Binding Title}"
                        TextColor="White"
                        VerticalTextAlignment="Center" />
                    <BoxView
                        x:Name="ActiveIndicator"
                        Grid.Row="1"
                        BackgroundColor="Red"
                        IsVisible="{Binding IsSelected, Mode=TwoWay}" />
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

    <CarouselView
        Grid.Row="2"
        CurrentItem="{Binding CurrentTabVm, Mode=TwoWay}"
        CurrentItemChanged="CarouselView_CurrentItemChanged"
        HorizontalScrollBarVisibility="Never"
        IsScrollAnimated="True"
        IsSwipeEnabled="True"
        ItemsSource="{Binding TabVms}"
        VerticalScrollBarVisibility="Never">
        <CarouselView.ItemTemplate>
            <DataTemplate x:DataType="local:TabViewModel">
                <Grid Margin="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Label
                        Grid.Row="0"
                        Margin="10"
                        LineBreakMode="WordWrap"
                        Text="{Binding Content}"
                        VerticalTextAlignment="Center" />
                </Grid>
            </DataTemplate>
        </CarouselView.ItemTemplate>
    </CarouselView>
</Grid>

Let me break that piece down. First, I wrapped everything in a Grid for this sample. The CollectionView of course should be horizontally scrolling but should not show any scroll bar. The tab item template is not a complex one – it is just a Label and a BoxView below it to help with indication of the selection. You are free to make the tab looking whatever you want because of the CollectionView, however.

Below that, we put a CarouselView. For this sample, I just made a simple one with a Lorem Ipsum Label in it on every item.

The ViewModels

Most of you know that I absolutely love the MVVM pattern. And this sample proves me right once again. We need just need two ViewModels to handle scrolling and synchronizing.

The first ViewModel is the TabViewModel:

Snippet

public class TabViewModel : ObservableObject
{
    private string _title;
    private string _content;
    private bool _isSelected;

    public TabViewModel(string title)
    {
        this.Title = title;
        this.Content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tempor id eu nisl nunc mi ipsum faucibus vitae aliquet. Turpis egestas integer eget aliquet nibh praesent tristique magna. In fermentum posuere urna nec tincidunt. Vitae congue eu consequat ac felis donec et odio pellentesque. Augue lacus viverra vitae congue. Viverra vitae congue eu consequat. Orci nulla pellentesque dignissim enim sit amet venenatis urna. Et ultrices neque ornare aenean euismod elementum nisi. Id consectetur purus ut faucibus pulvinar. In cursus turpis massa tincidunt. Egestas pretium aenean pharetra magna. Et pharetra pharetra massa massa ultricies mi quis. Nunc sed blandit libero volutpat. Purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae.";
    }

    public string Title { get => _title; set => Set(ref _title, value); }

    public string Content { get => _content; set => Set(ref _content, value); }

    public bool IsSelected { get => _isSelected; set =>Set(ref _isSelected, value); }
}

The TabViewModel in this sample just has the bare minimum, namely the Title, the Content and the IsSelectedFlag to control the Visibility of the Indicator-BoxView. Nothing dramatic so far.

The MainViewModel glues everything together, so let’s have a look:

Snippet

public class MainViewModel : ObservableObject
{
    private TabViewModel _currentTabVm;

    public MainViewModel()
    {

        this.TabVms = new ObservableCollection<TabViewModel>();
        this.TabVms.Add(new TabViewModel("Short Title"));
        this.TabVms.Add(new TabViewModel("A Little Longer Title"));
        this.TabVms.Add(new TabViewModel("An Even Longer Title Than Before"));
        this.TabVms.Add(new TabViewModel("Again Short Title"));
        this.TabVms.Add(new TabViewModel("Mini Title"));
        this.TabVms.Add(new TabViewModel("Different Title"));

        this.CurrentTabVm = this.TabVms.FirstOrDefault();
    }


    public ObservableCollection<TabViewModel> TabVms { get; set; } 

    public TabViewModel CurrentTabVm 
    { 
        get => _currentTabVm;
        set
        {
            Set(ref _currentTabVm, value);
            SetSelection();
        }
    }

    private void SetSelection()
    {
        this.TabVms.ForEach(vm => vm.IsSelected = false);
        this.CurrentTabVm.IsSelected = true;
    }
}

Once again, there is nothing complex in it. We are mocking a collection of TabViewModel and handle the tab selection via Binding. After the current item got selected, we are setting the IsSelected property on it to true to show the Indicator in the CollectionView.

For this sample, I didn’t use a fully blown MVVM framework, so I am setting the BindingContext in the MainPage‘s constructor. The Binding engine in Xamarin.Forms already does almost everything to make this work.

The only thing left is to handle the positioning of the tabs if we are swiping the CarouselView. As this is purely View related, I am using the CurrentItemChanged event in code behind to center the CollectionView‘s selected item:

Snippet

private void CarouselView_CurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
{
    this.CustomTabsView.ScrollTo(e.CurrentItem, null, ScrollToPosition.Center, true);
}

The result of this setup looks like this:

Conclusion

Xamarin.Forms provides a lot of solutions out of the box. Sometimes, however, these are not enough. Luckily, we can combine some of the solutions the framework provides to create fresh solutions within our apps. This post showed one of these. The additional bonus you get with this implementation is the ability to style the tabs in whatever way you want. As always, I hope this post will be helpful for some of you.

Of course, there is also sample for this post on Github.

Until the next post, happy coding, everyone!
Posted by msicc in Dev Stories, Xamarin, 2 comments
MSicc’s Blog version 1.6.0 out now for Android and iOS

MSicc’s Blog version 1.6.0 out now for Android and iOS

Here are the new features:

Push Notifications

With version 1.6.0 of the app, you can opt-in to receive push notifications once I publish a new blog post. I use an Azure Function (v1, for the ease of bindings – at least for now), and of course, an Azure NotificationHub. The Function gets called from a WebHook (via a plugin on WordPress), which triggers it to run (the next blog posts I write will be about how I achieved this, btw.)

New Design using Xamarin.Forms Shell

I also overhauled the design of the application. Initially, it was a MasterDetail app, but I never felt happy with that. Using Xamarin.Forms.Shell, I optimized the app to only show the last 30 posts I wrote. If you need older articles, you’ll be able to search for them within the app. The new design is a “v1” and will be constantly improved along with new features.

Bugs fixed in this release
  • fixed a bug where code snippets were not correctly displayed
  • fixed a bug where the app did not refresh posts after cleaning the cache
  • other minor fixes and improvements

I hope some of you will use the application and give me some feedback.

You can download the app using these links:
iOS | Android

Until the next post, happy coding, everyone!

Posted by msicc in Android, Azure, Dev Stories, iOS, Xamarin, 0 comments
#XfEffects: Forms Effect to automatically scale FontSize on Label

#XfEffects: Forms Effect to automatically scale FontSize on Label

Why do I need this?

When working with text, we often have to deal with some or all of the following:

  • dynamic text with different length on every instance
  • multiple devices with different screen resolutions
  • limited number of lines

As the amount of places where I need to automatically scale the FontSize is steadily increasing within my apps, I had to come up with a solution – the AutoFitFontSizeEffect.

The shared code

Of course, every Effect has a shared code part. Like in my first post, there are two classes for this – the Effect wrapper and the static parameter class on top of it. The wrapper is pretty straight forward:

    public class AutoFitFontSizeEffect : RoutingEffect
    {
        #region Protected Constructors

        public AutoFitFontSizeEffect() : base($"XfEffects.{nameof(AutoFitFontSizeEffect)}")
        {
        }

        #endregion Protected Constructors
    }

Like with all effects, we are deriving from RoutingEffect and initializing the class with the effect’s id. As I wanted the effect to be configurable with a minimum and a maximum size, I added a static class that takes these two parameters:

    public static class AutoFitFontSizeEffectParameters
    {
        #region Public Fields

        public static BindableProperty MaxFontSizeProperty = BindableProperty.CreateAttached("MaxFontSize", typeof(NamedSize), typeof(AutoFitFontSizeEffectParameters), NamedSize.Large, BindingMode.Default);
        public static BindableProperty MinFontSizeProperty = BindableProperty.CreateAttached("MinFontSize", typeof(NamedSize), typeof(AutoFitFontSizeEffectParameters), NamedSize.Default, BindingMode.Default);

        #endregion Public Fields

        #region Public Methods

        public static NamedSize GetMaxFontSize(BindableObject bindable)
        {
            return (NamedSize)bindable.GetValue(MaxFontSizeProperty);
        }

        public static NamedSize GetMinFontSize(BindableObject bindable)
        {
            return (NamedSize)bindable.GetValue(MinFontSizeProperty);
        }

        public static double MaxFontSizeNumeric(BindableObject bindable)
        {
            return Device.GetNamedSize(GetMaxFontSize(bindable), typeof(Label));
        }

        public static double MinFontSizeNumeric(BindableObject bindable)
        {
            return Device.GetNamedSize(GetMinFontSize(bindable), typeof(Label));
        }

        public static void SetMaxFontSize(BindableObject bindable, NamedSize value)
        {
            bindable.SetValue(MaxFontSizeProperty, value);
        }

        public static void SetMinFontSize(BindableObject bindable, NamedSize value)
        {
            bindable.SetValue(MinFontSizeProperty, value);
        }

        #endregion Public Methods
    }

Let’s break that class down. First, I created two attached BindableProperty objects of type NamedSize. The NamedSize enumeration makes it easy for us to determine the minimum and maximum sizes. If you want to know the values behind the enum entries, check this table in the docs.

To get and set those values out of the BindableProperty, I implemented corresponding methods. As we will see later on, I implemented also two methods that get the numeric values, which will be used in our platform-specific implementations.

Android implementation

Android has a built-in method on TextView to achieve the auto-scaling functionality we desire (read more about it on the Android docs). This makes the implementation pretty straight forward:

    public class AutoFitFontSizeEffect : PlatformEffect
    {
        #region Protected Methods

        protected override void OnAttached()
        {
            if (this.Control is TextView textView)
            {
                if (AutoFitFontSizeEffectParameters.GetMinFontSize(this.Element) == NamedSize.Default &&
                    AutoFitFontSizeEffectParameters.GetMaxFontSize(this.Element) == NamedSize.Default)
                    return;

                var min = (int)AutoFitFontSizeEffectParameters.MinFontSizeNumeric(this.Element);
                var max = (int)AutoFitFontSizeEffectParameters.MaxFontSizeNumeric(this.Element);

                if (max <= min)
                    return;

                textView.SetAutoSizeTextTypeUniformWithConfiguration(min, max, 1, (int)ComplexUnitType.Sp);
            }
        }

        protected override void OnDetached()
        {
        }

        #endregion Protected Methods
    }

Before using the SetAutoSizeTextTypeUniformWithConfiguration method on the TextView, I am running two checks: one if both parameters are set to NamedSize.Default, and the other one if the minimum value is bigger than the maximum value. If we pass past these check, we are using the above mentioned method. That is already everything it needs to make the text scaling automatically within the bounds of the TextView on Android.

iOS implementation

Like Android, also iOS has a pretty easy way to automatically scale the FontSize:

    public class AutoFitFontSizeEffect : PlatformEffect
    {
        #region Protected Methods

        protected override void OnAttached()
        {
            if (this.Control is UILabel label)
            {
                if (AutoFitFontSizeEffectParameters.GetMinFontSize(this.Element) == NamedSize.Default &&
                    AutoFitFontSizeEffectParameters.GetMaxFontSize(this.Element) == NamedSize.Default)
                    return;

                var min = (int)AutoFitFontSizeEffectParameters.MinFontSizeNumeric(this.Element);
                var max = (int)AutoFitFontSizeEffectParameters.MaxFontSizeNumeric(this.Element);

                if (max <= min)
                    return;

                label.AdjustsFontSizeToFitWidth = true;
                label.MinimumFontSize = (float)min;
                label.Font = label.Font.WithSize((float)max);
            }
        }

        protected override void OnDetached()
        {
        }

        #endregion Protected Methods
    }

We are running the same checks as on Android before we are effectively changing the properties on the UILabel that will make the text scale automatically. With setting AdjustsFontSizeToFitWidth to true and setting the MinimumFontSize to our min value as well as the max value as FontSize, we have already done everything it needs on iOS.

Conclusion

The checks we run before using the codes are not random. It may happen that you only add the effect to your Xamarin.Forms.Label without setting the MinFontSize and MaxFontSize. In this case, I am just returning.

Besides mixing up the sizes, the main reason for the second check is that the platform-specific size values are different between platforms. Also in this case, I am just returning.

Besides that, we are able to use all other properties of the default Xamarin.Forms.Label implementation, with MaxLines and LineBreakMode being the two most important ones.

As always, I hope this post will be helpful for some of you. Of course, the sample project for this series is updated on GitHub.

Happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Xamarin, 3 comments
My 2019 (a short review)

My 2019 (a short review)

Bitcoin, Crypto payments & Linux (moving out of my comfort zone)

At the beginning of 2019, I was working on the C#-SDK for AtomicPay, a crypto payment provider. I was also working on a mobile administration app for AtomicPay but during the year, the regulatory rules changed in Switzerland for KYC (know your customer). I had to stop my efforts in this area because, for an indie developer, they are just impossible to handle.

That didn’t stop me to discover other crypto/blockchain stuff, and so I did move out of my comfort zone to play around with a Linux Server and implementing a Bitcoin full node on it. You can read more on this in the Crypto&Blockchain section of my blog.

Even though my efforts have shifted back towards mobile applications, the blockchain area is still of interest to me.

Xamarin, Xamarin, Xamarin

All of my mobile side projects this year were deeply tied into the Xamarin universe. The biggest milestone I finally achieved this year was to finish the porting of my very first application ever from Windows Phone to Android and iOS. I wrote about some of the things I learned right here:

Barcode Scanning

The last few weeks I was busy to write a barcode scanning control for Xamarin Forms that uses native capabilities on iOS and Firebase ML on Android. It was only last week that I finally got both variants working.

Blogging

I attempted to write more regularly this year, but I clearly failed to keep up with it. One of my new year’s resolution is to keep a steady schedule of writing, as the list of what I want(ed) to write about is growing. I will go through this list during my upcoming vacation and try to find a better rhythm for my blogging efforts besides work and working on my side projects.

This year’s review is a bit different from the years before. I kept it short, focusing on the important parts (from my point of view). There is just one thing left to do in this post – to wish you all

A Merry Xmas and a Happy New Year!

Title-Image by Johan L from Pixabay

Posted by msicc in Dev Stories, Editorials, 0 comments
What I’ve learned from porting my first app ever to Android and iOS with Xamarin

What I’ve learned from porting my first app ever to Android and iOS with Xamarin

What’s the app about?

The app is about fishing knots. It sounds boring for most people, but for me, this app made me becoming a developer. So I have a somewhat emotional connection to it. It was back in time when Windows Phone 7 was new and hot. A new shiny OS from Microsoft, but clearly lacking the loads of apps that were available on iOS and Android. At that time, I also managed to get my fishing license in Germany.

As I had a hard time to remember how to tie fishing knots, I searched the store and found… nothing. I got very angry over that fact, partly because it meant I had to use one of the static websites back then, but more about the fact that there was this damn app gap (WP7 users will remember). So I finally decided to learn how to write code for Windows Phone and wrote my first app ever after some heavy self-studying months.

Why porting it?

Writing code should soon become my favorite spare-time activity, effectively replacing fishing. And so the years went on, I made some more apps (most of them for Windows Phone) and also managed to become employed as a developer. After some time, S. Nadella became the CEO of Microsoft, and Windows for mobile phones was dead. So I had created all my “babies”, and they were now set to die as Windows Phone/Mobile did. Not accepting this, I started to create a plan to port my apps over to the remaining mobile platforms. After Facebook effectively killed my most successful app (UniShare – that’s another story, though), I stopped porting that one and started with Fishing Knots +.

Reading your own old code (may) hurt

When I was starting to analyze which parts of the code I could reuse, I was kind of shocked. Of course, I knew that there was this code that I wrote when I didn’t know it better, but I refused to have a look into it and refactor it (for obvious reasons from today’s perspective). I violated a lot of best practices back then, the most prominent ones

  • No MVVM
  • Repeating myself over and over again
  • Monster methods with more than 100 lines within

In the end, I did the only right thing and did not reuse any line of my old code.

Reusing the concept without reusing old code

After I took the right decision to not use my old codebase, I needed to abstract the concept from the old app and translate it into what I know now about best practices and MVVM. I did not immediately start with the implementation, however.

The first thing I did was drawing the concept on a piece of paper. I used a no-code language in that sketch and asked my family if they understand the idea behind the app (you could also ask your non-tech friends). This approach helped me to identify the top 3 features of the app:

  • Controllable animation of each knot
  • Easy-to-follow 3-step instructions for each knot
  • Read-Aloud function of the instructions

Having defined the so-called “Minimum Viable Product“, I was ready to think about the implementation(s).

The new implementation

Finding the right implementation isn’t always straight forward. The first thing I wrote was the custom control that powers the controllable animation behind the scenes. I wrote it out of the context in a separated solution as I packed it into a NuGet package after finishing. It turned out to be also the most complex part of the whole app. It uses a common API in Xamarin.Forms, and custom renderers for Android and iOS. I had to go that route because of performance reasons – which is one of the learnings I took away from the porting.

It was also clear that I will use the MVVM pattern in the new version. So I was setting up some basic things using my own Nuget packages that I wrote during working on other Xamarin based projects.

When it came to the overall structure of my app, I thought a Master/Detail implementation would be fine. However, somehow this never felt right, and so I turned to Shell (which was pretty new, so I tried to give it a shot). In the end, I went with a more custom approach. The app uses a TabbedPage with 3 tabs, one being for the animation, the second for the 3-Step tutorial, and last but not least the Settings/About page. The first two pages share a custom top-down menu implementation, bound to the same ViewModel for its items and selection.

More Xamarin.Forms features I learned (to love)

Xamarin and Xamarin.Forms itself are already powerful and have matured a lot since the time I used it to write my first Xamarin app for Telefonicá Germany. Here is a (high level) list of features I started to use:

  • Xamarin.Essentials – the one library that kickstarts your application – seriously!
  • Xamarin Forms Animations – polish the appearance of your app with some nice looking visual activity within the UI
  • Xamarin Forms Effects – easily modify/enhance existing controls without creating a full-blown custom renderer
  • Xamarin Forms VisualStateManager – makes it (sometimes) a whole lot easier to change the UI based on property changes
  • Xamarin.Forms Triggers – alternative approach to modify the UI based on property changes (but not limited to that)

The three musketeers

Because of Xamarin and Xamarin.Forms are such powerful tools, you may run into the situation of needing help/more information. My three musketeers to get missing information, implementation help or solution ideas:

  • Microsoft Xamarin Docs – the docs for Xamarin are pretty extensive and by reading them (even again), I often had one of these “gotcha!”- moments
  • Github – if the docs don’t help, Github may. Be it in the issues of Xamarin(.Forms) or studying the renderers, Github has been as helpful as the docs to me.
  • Web Search – chances are high that someone had similar problems/ideas solved and wrote a blog about it. I don’t blindly copy those solutions. First I read them, then I try to understand them and finally, I implement my own abstraction of them. This way, I am in a steady learning process.

Learn to understand native implementations

I guarantee you will run into a situation where the musketeers do not help when focusing solely on Xamarin. Accept the situation that Xamarin is sitting on top of the native code of others and does the heavy conversion for us. Learn to read Objective-C, Swift, Java and Kotlin code and translate it into C# code. Once you found possible solutions in one of the native samples, blog posts or docs, you will see that most of them are easy to translate into Xamarin code. Do not avoid this part of Xamarin development, it will help you in future, trust me.

Conclusion

Porting over my first app ever to Android and iOS has provided me not only a lot of fun but also huge learnings/practicing. Some of them are of behavioral nature, some of them are code implementations. This post is about the behavioral part – I will write about some of the implementations in my upcoming blog posts.

I hope you enjoyed reading this post. If you have questions or have similar experiences and want to discuss, feel free to leave a comment on this post or connect to me via social media.

Until the next post, happy coding!

Helpful links:

Posted by msicc in Dev Stories, Xamarin, 2 comments