Écrans de contenu manquants dans une application mobile à l'aide de l'exemple Xamarin

Comment tout a commencé

Très souvent, lorsque nous travaillons avec des applications Enterprise, nous devons faire face à de tels écrans en l'absence de données reçues du backend, alors que nous avons simplement besoin d'afficher une liste à l'écran.





, , , , , .





, , . , .





-, . -, UI- - .





public class EmptyStateViewModel : ViewModel
{
    public EmptyStateViewModel(string image, string title, string description)
    {
        Image = image;
        Title = title;
        Description = description;
    }

    public string Image { get; }

    public string Title { get; }

    public string Description { get; }
}
      
      



( xaml Xamarin Forms) Bindings , , mvvm- .





?

- , - . - EmptyStateView, Retry, . EmptyStateViewModel, , .





public class ErrorStateViewModel : EmptyStateViewModel
{
    public ErrorStateViewModel(string image, string title, string description, string actionTitle, Command actionCommand)
        : base(image, title, description)
    {
        ActionTitle = actionTitle;
        ActionCommand = actionCommand;
    }

    public string ActionTitle { get; }

    public Command ActionCommand { get; }
}
      
      



?

- . . , -. None, null.





public static class OverlayFactory
{
    public static T None<T>()
        where T : EmptyStateViewModel
    {
        return null;
    }

    public static EmptyStateViewModel CreateCustom(string image, string title, string description)
    {
        return new EmptyStateViewModel(image, title, description);
    }

    public static ErrorStateViewModel CreateCustom(string image, string title, string description, string actionTitle, Command actionCommand)
    {
        return new ErrorStateViewModel(image, title, description, actionTitle, actionCommand);
    }
}
      
      



- -, , ,





public class SomeViewModel : BaseViewModel
{
    private IItemsLoadingService _itemsLoadingService;
    
    public SomeViewModel(IItemsLoadingService itemsLoadingService)
    {
        _itemsLoadingService = itemsLoadingService;
    }

    public ObservableCollection<ItemViewModel> Items { get; } = new ObservableCollection<ItemViewModel>();

    public EmptyStateViewModel EmptyState { get; protected set; }

    public ErrorStateViewModel ErrorState { get; protected set; }

    public override async Task InitializeAsync()
    {
        await base.InitializeAsync();

        await LoadItemsAsync();
    }

    private async Task LoadItemsAsync()
    {
        try
        {
            var result = await _itemsLoadingService.GetItemsAsync();
            var items = result.ToList();

            ErrorState = OverlayFactory.None<ErrorStateViewModel>();

            if (items.Count == 0)
            {
                EmptyState = OverlayFactory.CreateCustom("img_empty_state", "Title", "Description");
            }
            else
            {
                EmptyState = OverlayFactory.None<ErrorStateViewModel>();
                // Add items to list
            }
        }
        catch
        {
            ErrorState = OverlayFactory.CreateCustom("img_error_state", "Title", "Description", "Retry", new Command(() => LoadItemsAsync));
        }
    }
}
      
      



Binding EmptyState/ErrorState , mvvm-, , EmptyStateViewModel/ErrorStateViewModel null, . SetViewModel.





, View ViewModel View ViewState . ViewModel null - ViewState Gone, - Visible:





public void SetViewModel(EmptyStateViewModel viewModel)
{
    ViewModel = viewModel;

    View.Visibility = viewModel != null ? ViewStates.Visible : ViewStates.Gone;
}
      
      



iOS - constraints , - . enum, Android.





public void SetViewModel(EmptyStateViewModel viewModel)
{
    ViewModel = viewModel;

    View.SetVisibility(viewModel != null ? ViewStates.Visible : ViewStates.Gone);
}
      
      



extension





public static void SetVisibility(this UIView view, ViewVisibility visibility)
{
    var constraints = GetViewConstraints(view) ?? new NSLayoutConstraint[] {};

    if (visibility == ViewVisibility.Gone)
    {
        SaveViewConstraints(view, constraints);
        NSLayoutConstraint.DeactivateConstraints(constraints);
        view.Hidden = true;
        return;
    }
  
    if (visibility == ViewVisibility.Visible)
    {
        SaveViewConstraints(view, null);
        NSLayoutConstraint.ActivateConstraints(constraints);
        view.Hidden = false;
        return;
    }
}
      
      



Ici, dans le cas de la définition de ViewVisibility.Gone, nous pré-sauvegardons les contraintes de notre vue et les désactivons, et lorsque la visibilité est activée, au contraire, nous récupérons les contraintes précédemment enregistrées, réinitialisons la préservation, puis les activons.





private static NSLayoutConstraint[] GetViewConstraints(UIView view)
{
    return view.GetAssociatedObject<NSMutableArray<NSLayoutConstraint>>(Key)?.ToArray() ??
           view.Superview?.Constraints
               .Where(constraint => (constraint.FirstItem?.Equals(view) == true) || constraint.SecondItem.Equals(view))
               .ToArray();
}

private static void SaveViewConstraints(UIView view, NSLayoutConstraint[] constraints)
{
    NSMutableArray<NSLayoutConstraint> viewConstraints = null;

    if (constraints.Length > 0)
    {
        viewConstraints = new NSMutableArray<NSLayoutConstraint>();
        viewConstraints.AddObjects(constraints);
    }

    view.SetAssociatedObject(Key, viewConstraints, AssociationPolicy.RetainNonAtomic);
}
      
      



La première méthode vous permet d'obtenir les contraintes précédemment enregistrées, le cas échéant, ou, dans le cas contraire, d'obtenir les contraintes actuelles. S'il n'y a pas de vue parent, alors null sera retourné.





La deuxième méthode enregistrera les contraintes actuelles afin qu'elles puissent être restaurées ultérieurement.





Ainsi, il s'est avéré faire des écrans plus agréables avec des données manquantes, ou des écrans d'état d'erreur.





PS - le premier article sur Habré, ne juge donc pas strictement. Mais vous devez commencer quelque part.








All Articles