страница с вкладками, требующая больше времени для загрузки приложения - PullRequest
0 голосов
/ 04 июня 2019

Я пытаюсь разработать приложение xamarin, содержащее страницы с вкладками.

У меня есть 3 основные вкладки. На каждой странице конструктор модели просмотра имеет 3-5 вызовов API. Так что загрузка моего приложения (для открытия) занимает больше времени (20 секунд).

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage  xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Myapplication.Views.MenuPage"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True" 
              xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
             xmlns:views="clr-namespace:Dyocense.Views"
             android:TabbedPage.ToolbarPlacement="Bottom"
             android:TabbedPage.IsSwipePagingEnabled="False"
             >

        <views:A Title="A" Icon="dsjsdsd_18dp.png" ></views:A>
        <views:B Title="B" Icon="askjasa.png"></views:B>
        <views:C Title="C" Icon="abc.png"></views:C>
        <views:D Title="D" Icon="abc.png"></views:D>


</TabbedPage>

Как загрузить только первую страницу сведений о вкладке (A) при загрузке приложения, а остальные страницы при изменении вкладки.

1 Ответ

1 голос
/ 05 июня 2019

Решение состоит в том, чтобы заставить тяжелые страницы загружать свое содержимое ленивым способом, только когда их вкладка становится выбранной. Таким образом, поскольку эти страницы теперь пусты при создании TabbedPage, переход к TabbedPage внезапно становится очень быстрым!

1.создать поведение для страницы TabbedPage, которое называется ActivePageTabbedPageBehavior .

class ActivePageTabbedPageBehavior : Behavior<TabbedPage>
{
 protected override void OnAttachedTo(TabbedPage tabbedPage)
  {
    base.OnAttachedTo(tabbedPage);
    tabbedPage.CurrentPageChanged += OnTabbedPageCurrentPageChanged;
  }

 protected override void OnDetachingFrom(TabbedPage tabbedPage)
  {
    base.OnDetachingFrom(tabbedPage);
    tabbedPage.CurrentPageChanged -= OnTabbedPageCurrentPageChanged;
  }

 private void OnTabbedPageCurrentPageChanged(object sender, EventArgs e)
  {
    var tabbedPage = (TabbedPage)sender;

    // Deactivate previously selected page
    IActiveAware prevActiveAwarePage = tabbedPage.Children.OfType<IActiveAware>()
        .FirstOrDefault(c => c.IsActive && tabbedPage.CurrentPage != c);
    if (prevActiveAwarePage != null)
    {
        prevActiveAwarePage.IsActive = false;
    }

    // Activate selected page
    if (tabbedPage.CurrentPage is IActiveAware activeAwarePage)
    {
        activeAwarePage.IsActive = true;
    }
  }
}

2.define IActiveAware interface

interface IActiveAware
  {
    bool IsActive { get; set; }
    event EventHandler IsActiveChanged;
  }

3.создать базовый обобщенный абстрактный класс с именем LoadContentOnActivateBehavior

abstract class LoadContentOnActivateBehavior<TActivateAwareElement> : Behavior<TActivateAwareElement>
   where TActivateAwareElement : VisualElement
 {
  public DataTemplate ContentTemplate { get; set; }

  protected override void OnAttachedTo(TActivateAwareElement element)
   {
     base.OnAttachedTo(element);
     (element as IActiveAware).IsActiveChanged += OnIsActiveChanged;
   }

  protected override void OnDetachingFrom(TActivateAwareElement element)
   {
     (element as IActiveAware).IsActiveChanged -= OnIsActiveChanged;
     base.OnDetachingFrom(element);
   }

  void OnIsActiveChanged(object sender, EventArgs e)
   {
     var element = (TActivateAwareElement)sender;
     element.Behaviors.Remove(this);
     SetContent(element, (View)ContentTemplate.CreateContent());
   }

  protected abstract void SetContent(TActivateAwareElement element, View contentView);
}

4. Специализированный LazyContentPagePehavior

class LazyContentPageBehavior : LoadContentOnActivateBehavior<ContentView>
 {
   protected override void SetContent(ContentView element, View contentView)
    {
      element.Content = contentView;
    }
 }

тогда мы можем использовать в xaml вот так:

<TabbedPage>
  <TabbedPage.Behaviors>
    <local:ActivePageTabbedPageBehavior />
  </TabbedPage.Behaviors>

<ContentPage Title="First tab">
    <Label Text="First tab layout" />
</ContentPage>

<local:LazyLoadedContentPage Title="Second tab">
    <ContentPage.Behaviors>
        <local:LazyContentPageBehavior ContentTemplate="{StaticResource ContentTemplate}" />
    </ContentPage.Behaviors>
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="ContentTemplate">
                <!-- Complex and slow to render layout -->
                <local:SlowContentView />
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>
</local:LazyLoadedContentPage>
</TabbedPage>

мы переместили сложный макет ContentPage в DataTemplate.

Вот пользовательская LazyLoadedContentPage страница с активацией:

class LazyLoadedContentPage : ContentPage, IActiveAware
{
  public event EventHandler IsActiveChanged;

  bool _isActive;
  public bool IsActive
   {
     get => _isActive;
     set
      {
        if (_isActive != value)
        {
            _isActive = value;
            IsActiveChanged?.Invoke(this, EventArgs.Empty);
        }
      }
   }
 }

SlowContentView делать некоторые сложные вещи

 public partial class SlowContentView : ContentView
{
    public SlowContentView()
    {
        InitializeComponent();

        // Simulating a complex view
        ...
    }
}

Вы можете сослаться на ссылку

...