Xamarin – UI/UX practices

Create a warning box

  • Warning box is displayed when Camera permission is disabled
  • Warning box is hidden when Camera permission is enabled
  • Tap a button in warning box to popup dialog for asking permission

HomePage.xaml

<StackLayout>
<Frame BorderColor="{StaticResource WarningFrameYellowColour}" BackgroundColor="White" CornerRadius="3" Padding="8,0" Margin="8" HasShadow="false" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" IsVisible="{Binding CameraPermissionContentVisible}">
    <!-- This warning box can be hidden by "IsVisible" -->

    <StackLayout Orientation="Vertical" Spacing="0" HorizontalOptions="FillAndExpand" VerticalOptions="Start" Padding="0">
        <StackLayout Orientation="Horizontal" Spacing="8" Padding="0">
            <Image Source="{Binding HomePageWarningIcon}" HorizontalOptions="Center" VerticalOptions="Center"/>
            <!-- Top left icon can be changed by "HomePageWarningIcon"-->

            <Label Text="{Binding CameraWarningText}" TextColor="{StaticResource DarkGrayColour55}" FontAttributes="Bold" FontSize="14" HorizontalTextAlignment="Start" VerticalTextAlignment="Center" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand"/>
            <!-- Title text can be changed by "CameraWarningText"-->

            <v:EnhancedButton ImageSource="{Binding CameraExpandButtonIcon}" HorizontalOptions="End" VerticalOptions="Center" WidthRequest="36" HeightRequest="36" Clicked="CameraExpandWarningClicked" Margin="0,0,-8,0"/>
            <!-- Top right button is to expand the warning box by "CameraExpandWarningClicked" method -->

        </StackLayout>
        
        <v:EnhancedLabel TextColor="{StaticResource DarkGrayColour55}" FontSize="14" FmtText="{Binding CameraWarningDesc}" HorizontalTextAlignment="Start" HorizontalOptions="FillAndExpand" VerticalOptions="Start" IsVisible="{Binding CameraInfoBoxExpanded}" Margin="0"/>
        <!-- Description text can be changed by "CameraWarningDesc" -->
        <!-- Description text can be hidden by "CameraInfoBoxExpanded" -->

        <StackLayout Orientation="Horizontal" Spacing="24" HorizontalOptions="EndAndExpand" VerticalOptions="Center" IsVisible="{Binding CameraInfoBoxExpanded}" Margin="0,0,8,0">
        <!-- Button can be hidden by "CameraInfoBoxExpanded" -->

            <v:EnhancedButton Text="{Binding CameraWarningButtonText}" FontAttributes="Bold" FontSize="14" TextColor="{StaticResource VaultOrange}" Clicked="EnableCameraAction"
                                HorizontalOptions="Center" VerticalOptions="Center" HorizontalContentAlignment="Center" HeightRequest="40"/>
            <!-- Button text can be changed by "CameraWarningButtonText" -->
            <!-- Button can be triggered by "EnableCameraAction" method -->

        </StackLayout>
    </StackLayout>
</Frame>
</StackLayout>

HomePage.xaml.cs

public partial class HomePage : BaseContentPage
{
    public HomePageViewModel Model => BindingContext as HomePageViewModel;

    ...

    // Events from UI
    public void CameraExpandWarningClicked(object sender, EventArgs e) => Model.CameraInfoBoxExpanded = !Model.CameraInfoBoxExpanded;

    public void EnableCameraAction(object sender, EventArgs e)
    {
        CrossVideoStreaming.VideoStreaming.RequestPermissions();
    }

    /////////////////////////////////////////
    // Listen to permission state change
    /////////////////////////////////////////
    public override void CameraStateChange()
    {
        Model.RefreshCameraPermissionState();
    }
    ...
}

HomePageViewModel.cs

/// <summary>
/// Camera permission
/// </summary>
public bool CameraPermissionContentVisible => !AppState.CameraPermissionEnabled;

public string CameraWarningIcon => !AppState.CameraPermissionEnabled ? "ic_location_disabled.png" : "ic_activity_disabled.png";

public string CameraWarningText => i18n.AppResources.HomePageCameraWarningText;

public string CameraWarningDesc => i18n.AppResources.HomePageCameraWarningDesc;

public string CameraWarningButtonText => i18n.AppResources.HomePageCameraButtonText;

bool _cameraExpanded = true;
public bool CameraInfoBoxExpanded
{
    get => _cameraExpanded;
    set
    {
        if (_cameraExpanded != value)
        {
            _cameraExpanded = value;
            OnPropertyChanged(nameof(CameraInfoBoxExpanded));
            OnPropertyChanged(nameof(CameraExpandButtonIcon));
        }
    }
}

public string CameraExpandButtonIcon => CameraInfoBoxExpanded ? "ic_arrow_up_black.png" : "ic_arrow_down_black.png";

//////////////////////////////////////////
// Listen to permission state change
//////////////////////////////////////////
public void RefreshCameraPermissionState()
{
    OnPropertyChanged(nameof(CameraPermissionContentVisible));
}

AppState.cs

static bool? cameraPermissionEnabled;
public static bool CameraPermissionEnabled
{
    get => cameraPermissionEnabled ?? false;
    set
    {
        if (!cameraPermissionEnabled.HasValue || cameraPermissionEnabled.Value != value)
        {
            cameraPermissionEnabled = value;
        }
    }
}

public static Task CheckCameraPermissionState()
{
    foreach (var p in Application.Current.MainPage.Navigation.NavigationStack)
        if (p is BaseContentPage b)
        {
            //////////////////////////////////////
            // Listen to permission state change
            //////////////////////////////////////
            CameraPermissionEnabled = CrossVideoStreaming.VideoStreaming.IsCameraPermissionOn();
            b.CameraStateChange();
        }

    return Task.CompletedTask;
}

BaseContentPage.cs

public class BaseContentPage : ContentPage, IDisposable
{
    ...
    protected override void OnAppearing()
    {
        base.OnAppearing();

        //////////////////////////////////////
        // Listen to permission state change
        //////////////////////////////////////
        AppState.CheckCameraPermissionState();
    }
 
    //////////////////////////////////////
    // Listen to permission state change
    //////////////////////////////////////
    public virtual void CameraStateChange() { }

    ...
}

How to generate Android image set?

AndroidAssetStudio

How to pick color code in Mac?

Use “Digital Colour Meter.app

How to set iOS icon?

  • Use “xxxhdpi” icon for “3x”, “xhdpi” icon for “2x”, “mdpi” for “1x”

Be the first to comment

Leave a Reply

Your email address will not be published.


*