Button ContentLayout OnPlatform

xWeSTxWeST ✭✭USMember ✭✭

Hi,

in my Xamarin.Forms cross-platform project I'm using a Button with Text and Icon.
The attribut <ContentLayout="Right,100"> works fine on Android but I want to change the Value on iOS.

So I try something like that:

 <Button.ContentLayout>
                    <OnPlatform x:TypeArguments="???"
                                        Android="Right,100"
                                        WinPhone="Right,100"
                                        iOS="Right,50" />
 </Button.ContentLayout>

But I don't know what to insert as TypeArgument? I'm often on this problem and have to google what to insert here. Is there any overview with all TypeArguments?

Btw. is it correct that WinPhone can't handle this attribut? because even with <ContentLayout="Right,100"> it's align the items from left not from right and with ugly spacing between.

Answers

  • xWeSTxWeST ✭✭ USMember ✭✭

    Anyone?

  • PaulDistonPaulDiston ✭✭✭✭ USUniversity ✭✭✭✭

    As ButtonContentLayout is nested in the Button class I don't think you are going to be able to define it as a type for x:TypeArguments.

    An alternative might be to use a Markup Extension, as below :-

    using System; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace Sample { [ContentProperty("ButtonContentLayout")] public class ButtonContentLayoutExtension : IMarkupExtension { public string ButtonContentLayout { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { var elements = ButtonContentLayout.Split('|'); var android = elements[0]; var ios = elements[1]; var winphone = elements[2]; switch (Device.OS) { case TargetPlatform.Android: { return CreateButtonContentLayout(android); } case TargetPlatform.iOS: { return CreateButtonContentLayout(ios); } case TargetPlatform.WinPhone: { return CreateButtonContentLayout(winphone); } default: { return null; } } } private static object CreateButtonContentLayout(string buttonContentLayoutElement) { Button.ButtonContentLayout.ImagePosition imagePosition; double spacing; if (Enum.TryParse(buttonContentLayoutElement.Split(',')[0], out imagePosition) && double.TryParse(buttonContentLayoutElement.Split(',')[1], out spacing)) { return new Button.ButtonContentLayout(imagePosition, spacing); } return null; } } }

    Usage :-

    <Button Text="My Button" ContentLayout="{sample:ButtonContentLayout 'Right,100|Right,100|Right,50'}"/>

    I have only tried this on Android.

    Hope this helps.

  • xWeSTxWeST ✭✭ USMember ✭✭

    Thanks for your help Paul, I'm going to check this as soon as possible :)

  • SzymonCywinskiSzymonCywinski USMember
    edited July 2017

    I had the same problem.
    You can simply use x:TypeArguments="x:String"

  • Kramer_Kramer_ ✭✭ USMember ✭✭

    Using what @SzymonCywinski said, you can also apply this to a Resource Dictionary

    <ResourceDictionary>
        <OnPlatform x:Key="ItemButtonContentLayout" x:TypeArguments="x:String" iOS="Left,10" Android="Left,40" />
        <Style x:Key="ItemButton" TargetType="Button">
            <Setter Property="ContentLayout" Value="{StaticResource ItemButtonContentLayout}" />
        </Style>
    </ResourceDictionary>
    
  • Kramer_Kramer_ ✭✭ USMember ✭✭

    After doing some testing, I've noticed that the x:TypeArguments="x:String" is not working for me. So I had to go the markup extension route similar to what @PaulDiston did.

    I created a ContentLayoutExtension, where I basically use the Button.ButtonContentTypeConverter to convert the values from a string (which is what I'd expect the original code to do). I'm only supporting Android and iOS.

    using System;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    namespace APPNAME.MarkupExtensions
    {
        [ContentProperty("ContentLayout")]
        public class ContentLayoutExtension : IMarkupExtension
        {
            public string AndroidPosition { get; set; }
            public double AndroidSpacing { get; set; }
            public string iOSPosition { get; set; }
            public double iOSSpacing { get; set; }
    
            public object ProvideValue(IServiceProvider serviceProvider)
            {
                string position = null;
                double? spacing = null;
    
                switch(Device.RuntimePlatform)
                {
                    case Device.Android:
                        position = AndroidPosition;
                        spacing = AndroidSpacing;
                        break;
                    case Device.iOS:
                        position = iOSPosition;
                        spacing = iOSSpacing;
                        break;
                }
    
                if (string.IsNullOrEmpty(position))
                {
                    position = "Left";
                }
                if (spacing == null)
                {
                    spacing = 10;
                }
    
                var converter = new Button.ButtonContentTypeConverter();
                return converter.ConvertFromInvariantString(string.Format("{0},{1}", position, spacing));
            }
        }
    }
    

    And then call it in my Style Setter:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="PAGECLASS"
        xmlns:markup="clr-namespace:APPNAME.MarkupExtensions">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style x:Key="ItemButton" TargetType="Button">
                    <Setter Property="BackgroundColor" Value="Transparent" />
                    <Setter Property="BorderRadius" Value="0" />
                    <Setter Property="ContentLayout" Value="{markup:ContentLayout AndroidPosition=Left, AndroidSpacing=30, iOSPosition=Left, iOSSpacing=10}" />
                </Style>
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            ...
        </ContentPage.Content>
    </ContentPage>
    
Sign In or Register to comment.