Placement

JohnErnestJohnErnest USMember ✭✭

This one's a brain teaser. I want to build a reusable control that's composed of multiple controls, with a placement feature.

I'm illustrating the abstract general concept here for a reusable control with multiple placement capabilities, which extend a bit outside of Xamarin's normal placement capabilities for layouts, making me question a lot of things about adaptive layouts, both in Xamarin and CSS, that suggest the opportunity for improvement where things get a tad fiddly at times in layouts, especially around the areas of explicit widths and heights.

Let's just say for simplicity's sake you had a control with an image and a text. Maybe you want the text vertically above, right under the top, right under the bottom, below, or in the center of the image. Same with the horizontal layout, left outside, left inside, center, right inside, right outside. You may also want to take into account things like shadowing and rounding of corners, since it's common.

Now you could say use a RelativeLayout, but you may not know the exact widths and heights of the text or the image, making you set them explicitly ahead of time, which is a fair bit of a lackluster solution, it's not very elegant that's an "80-20" kind of solution that leads to a lot of rework later that could be simplified.

Not to mention the fact that, if you had said control embedded within a form, and the text on the vertical were say at 1.1'ish, outside the image, well it would most likely overlap other controls, so that's not really a solution to me.

You've also got this problem of the lack of conditionality in XAML, except for triggers, which doesn't easily apply here. That would mean a static layout case for all permutations of horizontal and vertical placement, which isn't very elegant.

So the next thing up, I tried something like so, this is chicken scratch code btw:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:SelfieMirroring" 
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"

    x:Class="SelfieMirroring.Controls.AuraButton"
    x:Name="auraMainButton">
    <ContentView.Content>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label x:Name="imageHolder" Text="Hello"></Label>
            <Label x:Name="textHolder" 
                   Grid.Row="1" 
                   Text="{Binding Source=auraMainButton, Path=ImageVerticalPlacement, Mode=TwoWay}"
                   >
            </Label>
        </Grid>
    </ContentView.Content>
</ContentView>


using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace SelfieMirroring.Controls
{
    public partial class AuraButton : ContentView
    {
        public AuraButton()
        {
            InitializeComponent();
        }

        public enum VerticalPlacement
        {
            Top, Middle, Below
        }

        public enum HorizontalPlacement
        {
            Left, Center, Right
        }

        public static readonly BindableProperty ImageHorizontalPlacementProperty =
            BindableProperty.Create("ImageHorizontalPlacement", typeof(HorizontalPlacement), typeof(AuraButton), HorizontalPlacement.Left);
        public HorizontalPlacement ImageHorizontalPlacement
        {
            get { return (HorizontalPlacement)GetValue(ImageHorizontalPlacementProperty); }
            set { SetValue(ImageHorizontalPlacementProperty, value); }
        }

        public static readonly BindableProperty ImageVerticalPlacementProperty =
            BindableProperty.Create("ImageVerticalPlacement", typeof(VerticalPlacement), typeof(AuraButton), VerticalPlacement.Middle);
        public VerticalPlacement ImageVerticalPlacement
        {
            get { return (VerticalPlacement)GetValue(ImageVerticalPlacementProperty); }
            set { SetValue(ImageVerticalPlacementProperty, value); }
        }

        public static readonly BindableProperty TextHorizontalPlacementProperty =
            BindableProperty.Create("TextHorizontalPlacement", typeof(HorizontalPlacement), typeof(AuraButton), HorizontalPlacement.Left);
        public HorizontalPlacement TextHorizontalPlacement
        {
            get { return (HorizontalPlacement)GetValue(TextHorizontalPlacementProperty); }
            set { SetValue(TextHorizontalPlacementProperty, value); }
        }

        public static readonly BindableProperty TextVerticalPlacementProperty =
            BindableProperty.Create("TextVerticalPlacement", typeof(VerticalPlacement), typeof(AuraButton), VerticalPlacement.Below);
        public VerticalPlacement TextVerticalPlacement
        {
            get { return (VerticalPlacement)GetValue(TextVerticalPlacementProperty); }
            set { SetValue(TextVerticalPlacementProperty, value); }
        }
    }
}

Except that, even with the Source and Path set, it doesn't show up in the designer, making it basically useless, since I would want said control to be designable.

Don't get hung up on the fact that I have multiple grid columns and rows there and am using a random property as a placeholder for a label, simply to show that, setting the BindingContext to the ContentView still want show the value of the property in the previewer, in a place where "design time data" is not a tenable solution here since we're talking about a visual property not exactly reliant on actual data.

Sign In or Register to comment.