すべての始まり
多くの場合、エンタープライズアプリケーションを使用する場合、バックエンドからデータを受信せずに、画面にリストを表示するだけで、このような画面を処理する必要があります。
これは通常、設計者がまったく不在であり、すべてのウォーフレームが顧客からのスケッチの形式で提供されるか、設計者がいるという事実によるものですが、この要素は顧客にとってそれほど重要ではないと見なされ、単に無視されます。
, , . , .
-, . -, 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;
}
}
ここで、ViewVisibility.Goneを設定する場合、ビューの制約を事前に保存して非アクティブ化します。逆に、可視性をオンにすると、以前に保存した制約を取得し、保存をリセットしてからアクティブにします。
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);
}
最初の方法では、以前に保存した制約がある場合はそれを取得でき、そうでない場合は現在の制約を取得できます。親ビューがない場合は、nullが返されます。
2番目の方法では、現在の制約を保存して、後で復元できるようにします。
したがって、データが欠落しているより快適な画面、またはエラーステータス画面を作成することが判明しました。
PS-ハブレに関する最初の記事なので、厳密に判断しないでください。しかし、どこかから始める必要があります。