Nativní zobrazení v jazyce C#

Download Sample Stažení ukázky

Nativní zobrazení z iOSu, Androidu a UPW je možné přímo odkazovat ze Xamarin.Forms stránek vytvořených pomocí jazyka C#. Tento článek ukazuje, jak přidat nativní zobrazení do rozložení vytvořeného pomocí jazyka C# a jak přepsat rozložení vlastních zobrazení a opravit tak jejich Xamarin.Forms využití rozhraní API měření.

Přehled

Libovolný Xamarin.Forms ovládací prvek, Content který umožňuje nastavení nebo který obsahuje Children kolekci, může přidávat zobrazení specifická pro platformu. Například iOS UILabel lze přidat přímo do vlastnosti nebo do ContentView.ContentStackLayout.Children kolekce. Upozorňujeme ale, že tato funkce vyžaduje použití definic v řešeních sdílených Project a není dostupná v řešeních #ifXamarin.Forms .NET Standard Xamarin.Forms knihovnách.

Následující snímky obrazovky ukazují, že zobrazení specifická pro platformu byla přidána do Xamarin.FormsStackLayout :

StackLayout Containing Platform-Specific Views

Možnost přidávat zobrazení specifická pro platformu do rozložení je Xamarin.Forms povolená dvěma rozšiřujícími metodami na každé platformě:

  • Add – přidá do kolekce rozložení zobrazení Children specifické pro platformu.
  • ToView– vezme zobrazení specifické pro platformu a zabalí ho jako , který lze nastavit Xamarin.FormsView jako vlastnost Content ovládacího prvku.

Použití těchto metod ve Xamarin.Forms sdíleném projektu vyžaduje import vhodného oboru názvů specifického pro Xamarin.Forms platformu:

  • iOS . Platform.iOS
  • Android . Platform.Android
  • Univerzální Windows Platform (UPW) . Platform.UWP

Přidání Platform-Specific zobrazení na jednotlivých platformách

Následující části ukazují, jak přidat zobrazení specifická pro platformu do Xamarin.Forms rozložení na jednotlivých platformách.

iOS

Následující příklad kódu ukazuje, jak přidat do UILabel a StackLayoutContentView :

var uiLabel = new UILabel {
  MinimumFontSize = 14f,
  Lines = 0,
  LineBreakMode = UILineBreakMode.WordWrap,
  Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();

Příklad předpokládá, že instance a byly dříve vytvořeny stackLayoutcontentView v jazyce XAML nebo C#.

Android

Následující příklad kódu ukazuje, jak přidat do TextView a StackLayoutContentView :

var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();

Příklad předpokládá, že instance a byly dříve vytvořeny stackLayoutcontentView v jazyce XAML nebo C#.

Univerzální platforma Windows

Následující příklad kódu ukazuje, jak přidat do TextBlock a StackLayoutContentView :

var textBlock = new TextBlock
{
    Text = originalText,
    FontSize = 14,
    FontFamily = new FontFamily("HelveticaNeue"),
    TextWrapping = TextWrapping.Wrap
};
stackLayout.Children.Add(textBlock);
contentView.Content = textBlock.ToView();

Příklad předpokládá, že instance a byly dříve vytvořeny stackLayoutcontentView v jazyce XAML nebo C#.

Přepsání měření platformy pro vlastní zobrazení

Vlastní zobrazení na každé platformě často správně implementují měření pouze pro scénář rozložení, pro který byly navrženy. Vlastní zobrazení může být například navrženo tak, aby zabírá pouze polovinu dostupné šířky zařízení. Po sdílení s ostatními uživateli se ale může požadováno, aby vlastní zobrazení zabírá celou dostupnou šířku zařízení. Proto může být nutné přepsat implementaci vlastního měření zobrazení při opakovaném použití v Xamarin.Forms rozložení. Z tohoto důvodu rozšiřující metody a poskytují přepsání, která umožňují zadat delegáty měření, což může po přidání do rozložení přepsat rozložení vlastního AddToViewXamarin.Forms zobrazení.

Následující části ukazují, jak přepsat rozložení vlastních zobrazení a opravit tak jejich využití rozhraní API měření.

iOS

Následující příklad kódu ukazuje třídu CustomControl , která dědí z UILabel :

public class CustomControl : UILabel
{
  public override string Text {
    get { return base.Text; }
    set { base.Text = value.ToUpper (); }
  }

  public override CGSize SizeThatFits (CGSize size)
  {
    return new CGSize (size.Width, 150);
  }
}

Instance tohoto zobrazení je přidána do StackLayout objektu , jak je znázorněno v následujícím příkladu kódu:

var customControl = new CustomControl {
  MinimumFontSize = 14,
  Lines = 0,
  LineBreakMode = UILineBreakMode.WordWrap,
  Text = "This control has incorrect sizing - there's empty space above and below it."
};
stackLayout.Children.Add (customControl);

Vzhledem k tomu, že přepsání vždy vrací výšku 150, zobrazí se zobrazení s prázdným mezerou nad a pod ním, jak je znázorněno na CustomControl.SizeThatFits následujícím snímku obrazovky:

iOS CustomControl with Bad SizeThatFits Implementation

Řešením tohoto problému je implementace, jak je znázorněno v GetDesiredSizeDelegate následujícím příkladu kódu:

SizeRequest? FixSize (NativeViewWrapperRenderer renderer, double width, double height)
{
  var uiView = renderer.Control;

  if (uiView == null) {
    return null;
  }

  var constraint = new CGSize (width, height);

  // Let the CustomControl determine its size (which will be wrong)
  var badRect = uiView.SizeThatFits (constraint);

  // Use the width and substitute the height
  return new SizeRequest (new Size (badRect.Width, 70));
}

Tato metoda používá šířku poskytovanou metodou , ale nahradí výšku CustomControl.SizeThatFits 150 pro výšku 70. Při přidání instance do lze metodu zadat jako pro opravu špatného měření CustomControlStackLayoutFixSizeGetDesiredSizeDelegate poskytovaného CustomControl třídou :

stackLayout.Children.Add (customControl, FixSize);

Výsledkem je správné zobrazení vlastního zobrazení bez mezery nad a pod ní, jak je znázorněno na následujícím snímku obrazovky:

iOS CustomControl with GetDesiredSize Override

Android

Následující příklad kódu ukazuje třídu CustomControl , která dědí z TextView :

public class CustomControl : TextView
{
  public CustomControl (Context context) : base (context)
  {
  }

  protected override void OnMeasure (int widthMeasureSpec, int heightMeasureSpec)
  {
    int width = MeasureSpec.GetSize (widthMeasureSpec);

    // Force the width to half of what's been requested.
    // This is deliberately wrong to demonstrate providing an override to fix it with.
    int widthSpec = MeasureSpec.MakeMeasureSpec (width / 2, MeasureSpec.GetMode (widthMeasureSpec));

    base.OnMeasure (widthSpec, heightMeasureSpec);
  }
}

Instance tohoto zobrazení je přidána do StackLayout objektu , jak je znázorněno v následujícím příkladu kódu:

var customControl = new CustomControl (MainActivity.Instance) {
  Text = "This control has incorrect sizing - it doesn't occupy the available width of the device.",
  TextSize = 14
};
stackLayout.Children.Add (customControl);

Vzhledem k tomu, že přepsání vždy vrací polovinu požadované šířky, zobrazí se zobrazení, které zabírá pouze polovinu dostupné šířky zařízení, jak je znázorněno na následujícím snímku CustomControl.OnMeasure obrazovky:

Android CustomControl with Bad OnMeasure Implementation

Řešením tohoto problému je implementace, jak je znázorněno v GetDesiredSizeDelegate následujícím příkladu kódu:

SizeRequest? FixSize (NativeViewWrapperRenderer renderer, int widthConstraint, int heightConstraint)
{
  var nativeView = renderer.Control;

  if ((widthConstraint == 0 && heightConstraint == 0) || nativeView == null) {
    return null;
  }

  int width = Android.Views.View.MeasureSpec.GetSize (widthConstraint);
  int widthSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec (
    width * 2, Android.Views.View.MeasureSpec.GetMode (widthConstraint));
  nativeView.Measure (widthSpec, heightConstraint);
  return new SizeRequest (new Size (nativeView.MeasuredWidth, nativeView.MeasuredHeight));
}

Tato metoda používá šířku poskytovanou CustomControl.OnMeasure metodou , ale vynásobí ji dvěma. Při přidání instance do lze metodu zadat jako pro opravu špatného měření CustomControlStackLayoutFixSizeGetDesiredSizeDelegate poskytovaného CustomControl třídou :

stackLayout.Children.Add (customControl, FixSize);

Výsledkem je správné zobrazení vlastního zobrazení, které zabírá šířku zařízení, jak je znázorněno na následujícím snímku obrazovky:

Android CustomControl with Custom GetDesiredSize Delegate

Univerzální platforma Windows

Následující příklad kódu ukazuje třídu CustomControl , která dědí z Panel :

public class CustomControl : Panel
{
  public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register(
      "Text", typeof(string), typeof(CustomControl), new PropertyMetadata(default(string), OnTextPropertyChanged));

  public string Text
  {
    get { return (string)GetValue(TextProperty); }
    set { SetValue(TextProperty, value.ToUpper()); }
  }

  readonly TextBlock textBlock;

  public CustomControl()
  {
    textBlock = new TextBlock
    {
      MinHeight = 0,
      MaxHeight = double.PositiveInfinity,
      MinWidth = 0,
      MaxWidth = double.PositiveInfinity,
      FontSize = 14,
      TextWrapping = TextWrapping.Wrap,
      VerticalAlignment = VerticalAlignment.Center
    };

    Children.Add(textBlock);
  }

  static void OnTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
  {
    ((CustomControl)dependencyObject).textBlock.Text = (string)args.NewValue;
  }

  protected override Size ArrangeOverride(Size finalSize)
  {
      // This is deliberately wrong to demonstrate providing an override to fix it with.
      textBlock.Arrange(new Rect(0, 0, finalSize.Width/2, finalSize.Height));
      return finalSize;
  }

  protected override Size MeasureOverride(Size availableSize)
  {
      textBlock.Measure(availableSize);
      return new Size(textBlock.DesiredSize.Width, textBlock.DesiredSize.Height);
  }
}

Instance tohoto zobrazení je přidána do StackLayout objektu , jak je znázorněno v následujícím příkladu kódu:

var brokenControl = new CustomControl {
  Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);

Vzhledem k tomu, že přepsání vždy vrátí polovinu požadované šířky, oříznutí zobrazení na polovinu dostupné šířky zařízení, jak je znázorněno na následujícím CustomControl.ArrangeOverride snímku obrazovky:

UWP CustomControl with Bad ArrangeOverride Implementation

Řešením tohoto problému je poskytnout implementaci při přidávání zobrazení do , jak je znázorněno v ArrangeOverrideDelegateStackLayout následujícím příkladu kódu:

stackLayout.Children.Add(fixedControl, arrangeOverrideDelegate: (renderer, finalSize) =>
{
    if (finalSize.Width <= 0 || double.IsInfinity(finalSize.Width))
    {
        return null;
    }
    var frameworkElement = renderer.Control;
    frameworkElement.Arrange(new Rect(0, 0, finalSize.Width * 2, finalSize.Height));
    return finalSize;
});

Tato metoda používá šířku poskytovanou CustomControl.ArrangeOverride metodou , ale vynásobí ji dvěma. Výsledkem je správné zobrazení vlastního zobrazení, které zabírá šířku zařízení, jak je znázorněno na následujícím snímku obrazovky:

UWP CustomControl with ArrangeOverride Delegate

Souhrn

Tento článek vysvětlil, jak přidat nativní zobrazení do rozložení vytvořeného pomocí jazyka C# a jak přepsat rozložení vlastních zobrazení a opravit Xamarin.Forms tak jejich využití rozhraní API měření.