Native Ansichten in C#
Native Ansichten von iOS, Android und UWP können direkt von Xamarin.Forms Seiten referenziert werden, die mit C# erstellt wurden. In diesem Artikel wird veranschaulicht, wie Sie einem Xamarin.Forms mit C# erstellten Layout native Ansichten hinzufügen und das Layout benutzerdefinierter Ansichten überschreiben, um die Verwendung der Mess-API zu korrigieren.
Übersicht
Jedes Xamarin.Forms Steuerelement, das festgelegt werden kann Content
oder über eine Children
Sammlung verfügt, kann plattformspezifische Ansichten hinzufügen. Beispielsweise kann der -Eigenschaft oder der ContentView.Content
StackLayout.Children
Auflistung ein iOS-Element UILabel
direkt hinzugefügt werden. Beachten Sie jedoch, dass diese Funktionalität die Verwendung von #if
defines in Xamarin.Forms Shared Project-Lösungen erfordert und nicht in Xamarin.Forms .NET Standard-Bibliothekslösungen verfügbar ist.
Die folgenden Screenshots veranschaulichen plattformspezifische Ansichten, die einem Xamarin.FormsStackLayout
hinzugefügt wurden:
Die Möglichkeit, einem Xamarin.Forms Layout plattformspezifische Ansichten hinzuzufügen, wird durch zwei Erweiterungsmethoden auf jeder Plattform ermöglicht:
Add
– fügt derChildren
Auflistung eines Layouts eine plattformspezifische Ansicht hinzu.ToView
– übernimmt eine plattformspezifische Ansicht und umschließt sie als eine Xamarin.FormsView
, dieContent
als Eigenschaft eines Steuerelements festgelegt werden kann.
Wenn Sie diese Methoden in einem freigegebenen Xamarin.Forms 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 Platform-Specific Ansichten auf jeder Plattform
In den folgenden Abschnitten wird veranschaulicht, wie sie einem Xamarin.Forms Layout auf jeder Plattform plattformspezifische Ansichten hinzufügen.
iOS
Im folgenden Codebeispiel wird veranschaulicht, wie ein UILabel
und ein StackLayout
ContentView
hinzugefügt wird:
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
zuvor in XAML oder C# erstellt wurden.
Android
Im folgenden Codebeispiel wird veranschaulicht, wie ein TextView
und ein StackLayout
ContentView
hinzugefügt wird:
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
zuvor in XAML oder C# erstellt wurden.
Universelle Windows-Plattform
Im folgenden Codebeispiel wird veranschaulicht, wie ein TextBlock
und ein StackLayout
ContentView
hinzugefügt wird:
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
zuvor in XAML oder C# erstellt wurden.
Überschreiben von Plattformmessungen für benutzerdefinierte Ansichten
Benutzerdefinierte Ansichten auf jeder Plattform implementieren die Messung häufig nur ordnungsgemäß für das Layoutszenario, für das sie entworfen wurden. Beispielsweise kann eine benutzerdefinierte Ansicht so konzipiert worden sein, dass sie nur die Hälfte der verfügbaren Breite des Geräts belegt. Nach der Freigabe für andere Benutzer ist die benutzerdefinierte Ansicht jedoch möglicherweise erforderlich, um die volle verfügbare Breite des Geräts zu belegen. Daher kann es erforderlich sein, eine Implementierung für die Messung benutzerdefinierter Ansichten zu überschreiben, wenn sie in einem Xamarin.Forms Layout wiederverwendet wird. Aus diesem Grund stellen die Add
Erweiterungsmethoden und ToView
Außerkraftsetzungen bereit, mit denen Messdelegaten angegeben werden können, die das Layout der benutzerdefinierten Ansicht überschreiben können, wenn es einem Xamarin.Forms Layout hinzugefügt wird.
In den folgenden Abschnitten wird veranschaulicht, wie Das Layout benutzerdefinierter Ansichten überschrieben wird, um die Verwendung der Mess-API zu korrigieren.
iOS
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von UILabel
erbt:
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);
}
}
Wie im folgenden Codebeispiel veranschaulicht, wird eine StackLayout
instance dieser Ansicht 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
Überschreibung jedoch immer eine Höhe von 150 zurückgibt, wird die Ansicht mit leerer Fläche darüber und darunter angezeigt, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate
Implementierung bereitzustellen, wie im folgenden Codebeispiel veranschaulicht:
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 durch eine Höhe von 70. Wenn der CustomControl
instance hinzugefügt StackLayout
wird, kann die FixSize
-Methode als die angegeben werden, um die GetDesiredSizeDelegate
fehlerhafte Messung zu beheben, die von der CustomControl
-Klasse bereitgestellt wird:
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:
Android
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von TextView
erbt:
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);
}
}
Wie im folgenden Codebeispiel veranschaulicht, wird eine StackLayout
instance dieser Ansicht 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
Überschreibung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht nur mit der Hälfte der verfügbaren Breite des Geräts angezeigt, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate
Implementierung bereitzustellen, wie im folgenden Codebeispiel veranschaulicht:
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 der CustomControl
instance hinzugefügt StackLayout
wird, kann die FixSize
-Methode als die angegeben werden, um die GetDesiredSizeDelegate
fehlerhafte Messung zu beheben, die von der CustomControl
-Klasse bereitgestellt wird:
stackLayout.Children.Add (customControl, FixSize);
Dies führt dazu, dass die benutzerdefinierte Ansicht ordnungsgemäß angezeigt wird und die Breite des Geräts belegt, wie im folgenden Screenshot gezeigt:
Universelle Windows-Plattform
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von Panel
erbt:
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);
}
}
Wie im folgenden Codebeispiel veranschaulicht, wird eine StackLayout
instance dieser Ansicht 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
Überschreibung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht auf die Hälfte der verfügbaren Breite des Geräts gekappt, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht in der Bereitstellung einer ArrangeOverrideDelegate
Implementierung beim Hinzufügen der Ansicht zu StackLayout
, wie im folgenden Codebeispiel veranschaulicht:
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 ordnungsgemäß angezeigt wird und die Breite des Geräts belegt, wie im folgenden Screenshot gezeigt:
Zusammenfassung
In diesem Artikel wurde erläutert, wie Sie einem Xamarin.Forms mit C# erstellten Layout native Ansichten hinzufügen und das Layout benutzerdefinierter Ansichten überschreiben, um die Verwendung der Mess-API zu korrigieren.