C# İçindeki Yerel Görünümler

iOS, Android ve UWP'den yerel görünümlere C# kullanılarak oluşturulan sayfalardan Xamarin.Forms doğrudan başvurulabilir. Bu makalede, C# kullanılarak oluşturulan bir Xamarin.Forms düzene yerel görünümlerin nasıl ekleneceği ve bunların ölçüm API'si kullanımını düzeltmek için özel görünümlerin düzeninin nasıl geçersiz kılınacakları gösterilmektedir.

Genel bakış

Ayarlanmasına izin veren Content veya koleksiyonu olan Children tüm Xamarin.Forms denetimler platforma özgü görünümler ekleyebilir. Örneğin, bir iOS UILabel doğrudan özelliğine ContentView.Content veya koleksiyona StackLayout.Children eklenebilir. Ancak, bu işlevin Paylaşılan Proje çözümlerinde Xamarin.Forms tanımların #if kullanılmasını gerektirdiğini ve .NET Standart kitaplık çözümlerinde Xamarin.Forms kullanılamadığını unutmayın.

Aşağıdaki ekran görüntüleri, bir Xamarin.FormsStackLayoutöğesine eklenen platforma özgü görünümleri gösterir:

Platforma Özgü Görünümler İçeren StackLayout

Düzene platforma özgü görünümler Xamarin.Forms ekleme özelliği her platformda iki uzantı yöntemiyle etkinleştirilir:

  • Add – bir düzen koleksiyonuna platforma Children özgü bir görünüm ekler.
  • ToView – platforma özgü bir görünüm alır ve denetimin Xamarin.FormsView özelliği olarak ayarlanabilen Content bir görünüm olarak sarmalar.

Paylaşılan projede Xamarin.Forms bu yöntemlerin kullanılması için platforma özgü Xamarin.Forms uygun ad alanının içeri aktarılması gerekir:

  • iOS – Xamarin.Forms. Platform.iOS
  • Android – Xamarin.Forms. Platform.Android
  • Evrensel Windows Platformu (UWP) – Xamarin.Forms. Platform.UWP

Her Platforma Platforma Özgü Görünümler Ekleme

Aşağıdaki bölümlerde, her platformdaki bir Xamarin.Forms düzene platforma özgü görünümlerin nasıl ekleneceği gösterilmektedir.

iOS

Aşağıdaki kod örneğinde ve 'ye StackLayout nasıl ekleneceği UILabel gösterilmektedirContentView:

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

Örnekte ve contentView örneklerinin stackLayout daha önce XAML veya C# içinde oluşturulduğu varsayılır.

Android

Aşağıdaki kod örneğinde ve 'ye StackLayout nasıl ekleneceği TextView gösterilmektedirContentView:

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

Örnekte ve contentView örneklerinin stackLayout daha önce XAML veya C# içinde oluşturulduğu varsayılır.

Evrensel Windows Platformu

Aşağıdaki kod örneğinde ve 'ye StackLayout nasıl ekleneceği TextBlock gösterilmektedirContentView:

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

Örnekte ve contentView örneklerinin stackLayout daha önce XAML veya C# içinde oluşturulduğu varsayılır.

Özel Görünümler için Platform Ölçümlerini Geçersiz Kılma

Her platformdaki özel görünümler genellikle yalnızca tasarlandığı düzen senaryosu için ölçüleri doğru şekilde uygular. Örneğin, özel bir görünüm, cihazın kullanılabilir genişliğinin yalnızca yarısını kaplar şekilde tasarlanmış olabilir. Ancak, diğer kullanıcılarla paylaşıldıktan sonra, cihazın tüm kullanılabilir genişliğini kaplarken özel görünüm gerekebilir. Bu nedenle, bir düzende Xamarin.Forms yeniden kullanılırken özel görünümler ölçüm uygulamasını geçersiz kılmak gerekebilir. Bu nedenle ve ToView uzantısı yöntemleri, Add ölçüm temsilcilerinin belirtilmesine izin veren geçersiz kılmalar sağlar ve bu da bir Xamarin.Forms düzene eklendiğinde özel görünüm düzenini geçersiz kılabilir.

Aşağıdaki bölümlerde, ölçüm API'sinin kullanımını düzeltmek için özel görünümlerin düzeninin nasıl geçersiz kılınacakları gösterilmektedir.

iOS

Aşağıdaki kod örneği, öğesinden UILabeldevralan sınıfını gösterirCustomControl:

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

Bu görünümün bir örneği, aşağıdaki kod örneğinde gösterildiği gibi öğesine StackLayouteklenir:

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

Ancak, CustomControl.SizeThatFits geçersiz kılma her zaman 150 yüksekliği döndürdüğünden, görünüm aşağıdaki ekran görüntüsünde gösterildiği gibi üzerinde ve altında boş alanla görüntülenir:

Hatalı Boyuta Sahip iOS CustomControlThatFits Uygulaması

Bu sorunun çözümü, aşağıdaki kod örneğinde gösterildiği gibi bir GetDesiredSizeDelegate uygulama sağlamaktır:

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

Bu yöntem, yöntemi tarafından CustomControl.SizeThatFits sağlanan genişliği kullanır, ancak 150'nin yüksekliğini 70'lik bir yükseklikle değiştirmektedir. CustomControl örneği öğesine FixSize StackLayouteklendiğinde, sınıfı tarafından CustomControl sağlanan hatalı ölçümü düzeltmek için yöntemi olarak belirtilebilirGetDesiredSizeDelegate:

stackLayout.Children.Add (customControl, FixSize);

Bu, aşağıdaki ekran görüntüsünde gösterildiği gibi, özel görünümün üzerinde ve altında boş alan olmadan doğru şekilde görüntülenmesine neden olur:

GetDesiredSize Override ile iOS CustomControl

Android

Aşağıdaki kod örneği, öğesinden TextViewdevralan sınıfını gösterirCustomControl:

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

Bu görünümün bir örneği, aşağıdaki kod örneğinde gösterildiği gibi öğesine StackLayouteklenir:

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

Ancak, CustomControl.OnMeasure geçersiz kılma her zaman istenen genişliğin yarısını döndürdüğünden, görünüm aşağıdaki ekran görüntüsünde gösterildiği gibi cihazın kullanılabilir genişliğinin yalnızca yarısını kaplayarak görüntülenir:

Hatalı OnMeasure Uygulaması ile Android CustomControl

Bu sorunun çözümü, aşağıdaki kod örneğinde gösterildiği gibi bir GetDesiredSizeDelegate uygulama sağlamaktır:

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

Bu yöntem, yöntemi tarafından CustomControl.OnMeasure sağlanan genişliği kullanır, ancak iki ile çarpar. CustomControl örneği öğesine FixSize StackLayouteklendiğinde, sınıfı tarafından CustomControl sağlanan hatalı ölçümü düzeltmek için yöntemi olarak belirtilebilirGetDesiredSizeDelegate:

stackLayout.Children.Add (customControl, FixSize);

Bu, aşağıdaki ekran görüntüsünde gösterildiği gibi özel görünümün doğru şekilde görüntülenmesine ve cihazın genişliğinin kaplanmasıyla sonuçlanır:

Özel GetDesiredSize Temsilcisi ile Android CustomControl

Evrensel Windows Platformu

Aşağıdaki kod örneği, öğesinden Paneldevralan sınıfını gösterirCustomControl:

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

Bu görünümün bir örneği, aşağıdaki kod örneğinde gösterildiği gibi öğesine StackLayouteklenir:

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

Ancak, CustomControl.ArrangeOverride geçersiz kılma her zaman istenen genişliğin yarısını döndürdüğünden, görünüm aşağıdaki ekran görüntüsünde gösterildiği gibi cihazın kullanılabilir genişliğinin yarısına kırpılır:

Hatalı ArrangeOverride Uygulaması ile UWP CustomControl

Bu sorunun çözümü, aşağıdaki kod örneğinde gösterildiği gibi görünümü öğesine StackLayouteklerken bir ArrangeOverrideDelegate uygulama sağlamaktır:

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

Bu yöntem, yöntemi tarafından CustomControl.ArrangeOverride sağlanan genişliği kullanır, ancak iki ile çarpar. Bu, aşağıdaki ekran görüntüsünde gösterildiği gibi özel görünümün doğru şekilde görüntülenmesine ve cihazın genişliğinin kaplanmasıyla sonuçlanır:

ArrangeOverride Temsilcisi ile UWP CustomControl

Özet

Bu makalede, C# kullanılarak oluşturulan bir Xamarin.Forms düzene yerel görünümlerin nasıl ekleneceği ve bunların ölçüm API'si kullanımını düzeltmek için özel görünümlerin düzeninin nasıl geçersiz kılınacakları açıklanmıştır.