Freigeben über


Native Ansichten in C#

Native Ansichten aus iOS, Android und UWP können direkt von Xamarin.Forms Seiten verwiesen werden, die mit C# erstellt wurden. In diesem Artikel wird veranschaulicht, wie Sie einem Xamarin.Forms layout, das mit C# erstellt wurde, systemeigene Ansichten hinzufügen und das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.

Übersicht

Jedes Xamarin.Forms Steuerelement, das das Festlegen oder eine Children Sammlung ermöglichtContent, kann plattformspezifische Ansichten hinzufügen. Beispielsweise kann ein iOS UILabel direkt der ContentView.Content Eigenschaft oder der StackLayout.Children Auflistung hinzugefügt werden. Beachten Sie jedoch, dass diese Funktionalität die Verwendung von #if Definierten in Xamarin.Forms Freigegebenen Projektlösungen erfordert und nicht über Xamarin.Forms .NET Standard-Bibliothekslösungen verfügbar ist.

Die folgenden Screenshots veranschaulichen plattformspezifische Ansichten, die zu einer Xamarin.FormsStackLayouthinzugefügt wurden:

StackLayout mit plattformspezifischen Ansichten

Die Möglichkeit, plattformspezifische Ansichten zu einem Xamarin.Forms Layout hinzuzufügen, wird durch zwei Erweiterungsmethoden auf jeder Plattform aktiviert:

  • Add – fügt der Children Sammlung eines Layouts eine plattformspezifische Ansicht hinzu.
  • ToView – verwendet eine plattformspezifische Ansicht und umschließt sie als Xamarin.FormsView Content Eigenschaft eines Steuerelements.

Wenn Sie diese Methoden in einem Xamarin.Forms freigegebenen Projekt verwenden, müssen Sie den entsprechenden plattformspezifischen Xamarin.Forms Namespace importieren:

  • iOS: Xamarin.Forms.Platform.iOS
  • Android: Xamarin.Forms.Platform.Android
  • Universelle Windows-Plattform (UWP): Xamarin.Forms.Platform.UWP

Hinzufügen plattformspezifischer Ansichten auf jeder Plattform

In den folgenden Abschnitten wird veranschaulicht, wie Plattformspezifische Ansichten zu einem Xamarin.Forms Layout auf jeder Plattform hinzugefügt werden.

iOS

Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem UILabel StackLayout und einem :ContentView

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

Im Beispiel wird davon ausgegangen, dass die stackLayout Instanzen und contentView Instanzen zuvor in XAML oder C# erstellt wurden.

Android

Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem TextView StackLayout und einem :ContentView

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

Im Beispiel wird davon ausgegangen, dass die stackLayout Instanzen und contentView Instanzen zuvor in XAML oder C# erstellt wurden.

Universelle Windows-Plattform

Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem TextBlock StackLayout und einem :ContentView

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

Im Beispiel wird davon ausgegangen, dass die stackLayout Instanzen und contentView Instanzen zuvor in XAML oder C# erstellt wurden.

Überschreiben von Plattformmaßen für benutzerdefinierte Ansichten

Benutzerdefinierte Ansichten auf jeder Plattform implementieren häufig nur die richtige Messung für das Layoutszenario, für das sie entworfen wurden. Beispielsweise wurde möglicherweise eine benutzerdefinierte Ansicht so konzipiert, dass nur die Hälfte der verfügbaren Breite des Geräts belegt wird. Nach der Freigabe für andere Benutzer muss die benutzerdefinierte Ansicht jedoch möglicherweise die volle verfügbare Breite des Geräts belegen. Daher kann es erforderlich sein, eine benutzerdefinierte Ansichtsmessimplementierung außer Kraft zu setzen, wenn sie in einem Xamarin.Forms Layout wiederverwendet wird. Aus diesem Grund stellen die Add Methoden und ToView Erweiterungsmethoden Außerkraftsetzungen bereit, mit denen Maßdelegatten angegeben werden können, die das benutzerdefinierte Ansichtslayout überschreiben können, wenn es einem Xamarin.Forms Layout hinzugefügt wird.

In den folgenden Abschnitten wird veranschaulicht, wie sie das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.

iOS

Das folgende Codebeispiel zeigt die CustomControl Klasse, die von 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);
  }
}

Eine Instanz dieser Ansicht wird einem StackLayout, wie im folgenden Codebeispiel gezeigt, hinzugefügt:

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);

Da die CustomControl.SizeThatFits Außerkraftsetzung jedoch immer eine Höhe von 150 zurückgibt, wird die Ansicht mit leerem Platz darüber und darunter angezeigt, wie im folgenden Screenshot gezeigt:

iOS CustomControl mit bad SizeThatFits-Implementierung

Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate Implementierung bereitzustellen, wie im folgenden Codebeispiel gezeigt:

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));
}

Diese Methode verwendet die von der CustomControl.SizeThatFits Methode bereitgestellte Breite, ersetzt jedoch die Höhe von 150 für eine Höhe von 70. Wenn die CustomControl Instanz der StackLayoutKlasse hinzugefügt wird, kann die FixSize Methode angegeben GetDesiredSizeDelegate werden, um die von der CustomControl Klasse bereitgestellte schlechte Messung zu beheben:

stackLayout.Children.Add (customControl, FixSize);

Dies führt dazu, dass die benutzerdefinierte Ansicht ordnungsgemäß angezeigt wird, ohne leerer Platz darüber und darunter, wie im folgenden Screenshot gezeigt:

iOS CustomControl mit GetDesiredSize Override

Android

Das folgende Codebeispiel zeigt die CustomControl Klasse, die von 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);
  }
}

Eine Instanz dieser Ansicht wird einem StackLayout, wie im folgenden Codebeispiel gezeigt, hinzugefügt:

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);

Da die CustomControl.OnMeasure Außerkraftsetzung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht nur die Hälfte der verfügbaren Breite des Geräts angezeigt, wie im folgenden Screenshot gezeigt:

Android CustomControl mit bad OnMeasure-Implementierung

Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate Implementierung bereitzustellen, wie im folgenden Codebeispiel gezeigt:

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));
}

Diese Methode verwendet die von der CustomControl.OnMeasure Methode bereitgestellte Breite, multipliziert sie jedoch mit zwei. Wenn die CustomControl Instanz der StackLayoutKlasse hinzugefügt wird, kann die FixSize Methode angegeben GetDesiredSizeDelegate werden, um die von der CustomControl Klasse bereitgestellte schlechte Messung zu beheben:

stackLayout.Children.Add (customControl, FixSize);

Dies führt dazu, dass die benutzerdefinierte Ansicht richtig angezeigt wird, wobei die Breite des Geräts belegt wird, wie im folgenden Screenshot gezeigt:

Android CustomControl mit benutzerdefiniertem GetDesiredSize-Delegaten

Universelle Windows-Plattform

Das folgende Codebeispiel zeigt die CustomControl Klasse, die von 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);
  }
}

Eine Instanz dieser Ansicht wird einem StackLayout, wie im folgenden Codebeispiel gezeigt, hinzugefügt:

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

Da die CustomControl.ArrangeOverride Außerkraftsetzung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht auf die Hälfte der verfügbaren Breite des Geräts zugeschnitten, wie im folgenden Screenshot gezeigt:

UWP CustomControl mit Bad ArrangeOverride-Implementierung

Eine Lösung für dieses Problem besteht darin, eine ArrangeOverrideDelegate Implementierung bereitzustellen, wenn sie der Ansicht StackLayouthinzugefügt wird, wie im folgenden Codebeispiel gezeigt:

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;
});

Diese Methode verwendet die von der CustomControl.ArrangeOverride Methode bereitgestellte Breite, multipliziert sie jedoch mit zwei. Dies führt dazu, dass die benutzerdefinierte Ansicht richtig angezeigt wird, wobei die Breite des Geräts belegt wird, wie im folgenden Screenshot gezeigt:

UWP CustomControl mit ArrangeOverride Delegate

Zusammenfassung

In diesem Artikel wird erläutert, wie Sie einem Xamarin.Forms layout, das mit C# erstellt wurde, systemeigene Ansichten hinzufügen und das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.