Fifth Cloud
Fifth Cloud

Reputation: 160

How to stack two image buttons in Maui

I have a dotnet Maui app and within one of my forms, I would like the end-user to select a picture they would like as one of their background images. To make it clear that they have selected an image I would like to show them the image they have chosen.

This is the result I am trying to achieve.

ImageButtons stacked

Here is the code in creating this form. MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:SampleGridWithImage.ViewModels"
             x:Class="SampleGridWithImage.Views.MainPage"
             x:DataType="vm:MainViewModel">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="3*"/>
            <RowDefinition Height="5*"/>
            <RowDefinition Height="2*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*"/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>
        <Label
            Grid.Row="0" Grid.Column="0"
            Text="Add a picture to commemorate this moment."
            VerticalTextAlignment="Center"
            Margin="10"/>
        <Frame
            Grid.Row="0" Grid.Column="1"
            BackgroundColor="Transparent"
            BorderColor="AntiqueWhite">
            <StackLayout Orientation="Vertical">
                <ImageButton
                    Source="attach_image.svg"
                    Aspect="AspectFit"
                    Command="{Binding SelectPictureCommand}"
                    BorderColor="AntiqueWhite"
                    BorderWidth="4"
                    HeightRequest="75"/>
                <!--Source="{Binding ImagePath}"-->
                <ImageButton
                    Aspect="AspectFit"
                    Source="pxl1.jpg"
                    BorderColor="AntiqueWhite"
                    BorderWidth="4"
                    x:Name="addImage"
                    HeightRequest="75"/>
            </StackLayout>
        </Frame>
        <Editor
            Grid.Row="1" Grid.ColumnSpan="2"
            Placeholder="What would you like to say..."
            Margin="20"
            Text="{Binding TextEntry}"
            BackgroundColor="LightGray"/>
        <ImageButton
            Grid.Row="2" Grid.Column="0"
            Source="cancel.svg"
            x:Name="CancelEntry"
            Margin="40"
            Command="{Binding CancelEntryCommand}"/>
        <ImageButton
            Grid.Row="2" Grid.Column="1"
            Source="sim_card.svg"
            x:Name="SaveEntry"
            Margin="40"
            Command="{Binding SaveEntryCommand}"/>
    </Grid>
</ContentPage>

MainViewModel

namespace SampleGridWithImage.ViewModels;

public partial class MainViewModel : BaseViewModel
{
    [ObservableProperty]
    string textEntry;

    [ObservableProperty]
    string imagePath;

    [RelayCommand]
    public void CancelEntry()
    {
        // Cancel
        return;
    }

    [RelayCommand]
    public void SaveEntry()
    {
        if (!String.IsNullOrEmpty(TextEntry))
        {
            // Save the entry
        }
    }

    [RelayCommand]
    public async Task SelectPicture()
    {
        // Ask for permission for the user to select an image.
        if (PermissionStatus.Granted == await CheckAndRequestPhotosPermission())
        {
            var fileChosen = await FilePicker.PickAsync(new PickOptions
            {
                PickerTitle = "Select an image.",
                FileTypes = FilePickerFileType.Images
            });

            if (fileChosen != null)
            {
                ImagePath = fileChosen.FullPath;
            }
        }
    }

    public async Task<PermissionStatus> CheckAndRequestPhotosPermission()
    {
        PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Photos>();

        if (status == PermissionStatus.Granted)
            return status;

        if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
        {
            // Prompt the user to turn on in settings
            // On iOS once a permission has been denied it may not be requested again from the application
            return status;
        }

        // The only platform that uses this is ANDROID. Every other platform returns false automatically.
        if (Permissions.ShouldShowRationale<Permissions.Photos>())
        {
            // Prompt the user with additional information as to why the permission is needed
        }

        status = await Permissions.RequestAsync<Permissions.Photos>();

        return status;
    }
}

What I need help with is configuring the Images within the ImageButton so as not to have the HeightRequest. How can I tell Maui to use the space given to display the images within their "container"? I have used AspectFit and if I were to remove the HeightRequest the images would overflow and will not show within the frame. I am not sure what I need to do. I am not committed to using a frame and stacklayout to hold the ImageButtons so if you can make any recommendations on what I need to change I would greatly appreciate it!

Upvotes: 0

Views: 246

Answers (1)

Fifth Cloud
Fifth Cloud

Reputation: 160

Re-examining the Grid documentation I don't remember seeing this before but I found the section on Nested Grid objects.

Gave this a try and got what I was looking for. Seems I had to nest Grids to get the look I was going for. Here is the final code.

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:SampleGridWithImage.ViewModels"
             x:Class="SampleGridWithImage.Views.MainPage"
             x:DataType="vm:MainViewModel">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="2*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label
            Grid.Row="0" Grid.Column="0"
            Text="Add a picture to commemorate this moment."
            VerticalTextAlignment="Center"
            Margin="10"/>
        <Grid Grid.Row="0" Grid.Column="1" Margin="2">
            <Grid.RowDefinitions>
                <RowDefinition Height="4*"/>
                <RowDefinition Height="6*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <ImageButton
                Grid.Row="0" Grid.ColumnSpan="2"
                Source="attach_image.svg"
                Aspect="AspectFit"
                Command="{Binding SelectPictureCommand}"
                BorderColor="AntiqueWhite"
                BorderWidth="4"/>
            <Image
                Grid.Row="1" Grid.Column="0"
                Aspect="AspectFit"
                Source="pxl1.jpg"
                x:Name="addImage"
                />
            <ImageButton
                Grid.Row="1" Grid.Column="1"
                Source="empty_trash.svg"
                HorizontalOptions="Center"
                Margin="10"/>
        </Grid>
        <Editor
            Grid.Row="1" Grid.ColumnSpan="2"
            Placeholder="What would you like to say..."
            Margin="20"
            Text="{Binding TextEntry}"
            BackgroundColor="LightGray"/>
        <ImageButton
            Grid.Row="2" Grid.Column="0"
            Source="cancel.svg"
            x:Name="CancelEntry"
            Margin="40"
            Command="{Binding CancelEntryCommand}"/>
        <ImageButton
            Grid.Row="2" Grid.Column="1"
            Source="sim_card.svg"
            x:Name="SaveEntry"
            Margin="40"
            Command="{Binding SaveEntryCommand}"/>
    </Grid>
</ContentPage>

Picture of the outcome

Stacked Images

Upvotes: 0

Related Questions