Runde Bilder sind grade der große Trend im mobilen App-Design und mit dieser einfachen Technik können Sie Ihre mobilen Apps schnell und einfach aufpolieren. Xamarin hat diese in den mobilen Apps auf Xamarin Evolve verwendet und mit ein bisschen Code und einem speziellen Renderer können auch Sie Standardbilder in Xamarin.Forms in elegante, runde Bilder transformieren..

Xamarin Monkey Circle Images

Bildquelle: Xamarin

Custom Image

Nachdem Sie ein Xamarin.Forms Projekt angelegt haben müssen Sie zunächst ein Bedienelement erstellen, das von Image erbt. Im Folgenden wird dieser ImageCircle genannt. Dieser wird auf jeder Plattform implementiert.

1
2
3
4
public class ImageCircle : Image
{
  //Optional custom properties could go here
}

Custom Renderer

Jetzt müssen Sie Xamarin.Forms noch sagen, wie er ImageCircle auf den unterschiedlichen Plattformen rendern soll. Dazu nutzen Sie
Custom Renderer

Legen Sie für alle drei Projekte einen ImageCircleRenderer an, der von ImageRenderer erbt und implementieren dann das eigentliche Zuschneiden.

1
2
3
4
public class ImageCircleRenderer : ImageRenderer
{
  //...Implementation
}

iOS Renderer

In iOS können Sie direkt mit dem CALayer  vom UIImageView interagieren um einen Eckenradius zu bestimmen und die Umrandungsfarbe festzulegen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void CreateCircle()
{
  try
  {
    double min = Math.Min(Element.Width, Element.Height);
    Control.Layer.CornerRadius = (float)(min / 2.0);
    Control.Layer.MasksToBounds = false;
    Control.Layer.BorderColor = Color.White.ToCGColor();
    Control.Layer.BorderWidth = 3;
    Control.ClipsToBounds = true;
  }
  catch(Exception ex)
  {
    Debug.WriteLine("Unable to create circle image: " + ex)
  }
}

Diese Methode muss im initialen OnElementChanged und bei jeder Änderung von Höhe und Breite aufgerufen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected override void OnElementChanged(ElementChangedEventArgs e)
{
  base.OnElementChanged(e);
  if (e.OldElement != null || Element == null)
    return;
  CreateCircle();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
  base.OnElementPropertyChanged(sender, e);
  if (e.PropertyName == VisualElement.HeightProperty.PropertyName ||
      e.PropertyName == VisualElement.WidthProperty.PropertyName)
  {
    CreateCircle();
  }
}

Und Sie müssen den Renderer natürlich mit einem Assembly-Export exportieren.

1
2
3
4
5
[assembly: ExportRenderer(typeof(ImageCircle), typeof(ImageCircleRenderer))]
namespace CircleImage.iOS
{
 //...
}

Android Renderer

Android ist eine einzigartige Plattform; Sie haben keine physische Ebene, mit der Sie interagieren könnten. Dafür können Sie bestimmen, wie Xamarin.Forms das Child erzeugt und entlang des Kreispfades ausschneidet.

Diese Methode ist etwas komplexere Mathematik, berechnet aber den Pfad, an dem entlanggeschnitten werden muss und fügt einen runden Rand um das Child hinzu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected override bool DrawChild(Canvas canvas, global::Android.Views.View child, long drawingTime)
{
  try
  {
    var radius = Math.Min(Width, Height) / 2;
    var strokeWidth = 10;
    radius -= strokeWidth / 2;
    //Create path to clip
    var path = new Path();
    path.AddCircle(Width / 2, Height / 2, radius, Path.Direction.Ccw);
    canvas.Save();
    canvas.ClipPath(path);
    var result = base.DrawChild(canvas, child, drawingTime);
    canvas.Restore();
    // Create path for circle border
    path = new Path();
    path.AddCircle(Width / 2, Height / 2, radius, Path.Direction.Ccw);
    var paint = new Paint();
    paint.AntiAlias = true;
    paint.StrokeWidth = 5;
    paint.SetStyle(Paint.Style.Stroke);
    paint.Color = global::Android.Graphics.Color.White;
    canvas.DrawPath(path, paint);
    //Properly dispose
    paint.Dispose();
    path.Dispose();
    return result;
  }
  catch (Exception ex)
  {
    Debug.WriteLine("Unable to create circle image: " + ex);
  }
  return base.DrawChild(canvas, child, drawingTime);
}

Ein komplexerer Bestandteil bei der Entwicklung ist die je nach Version unterschiedliche Art und Weise, in der der Android Pfad kürzt.
Hardwarebeschleunigung wurde für diese Methode in API 18 eingeführt, also müssen Sie Android sagen, dass es bei älteren Geräten
Software-Rendering benutzen muss. Sie können den Typ des Layers in der OnElementChanged-Methode setzen.

1
2
3
4
5
6
7
8
9
protected override void OnElementChanged(ElementChangedEventArgs e)
{
  base.OnElementChanged(e);
  if (e.OldElement == null)
  {
    if ((int)Android.OS.Build.VERSION.SdkInt < 18)
      SetLayerType(LayerType.Software, null);
  }
}

Und natürlich müssen Sie den Renderer mit einem Assembly-Export exportieren.

1
2
3
4
5
[assembly: ExportRenderer(typeof(ImageCircle), typeof(ImageCircleRenderer))]
namespace CircleImage.Droid
{
 //...
}

Windows Phone Renderer

WindowsPhone hat eine Clip-Eigenschaft, die man verwenden kann um EllipseGeometry zu erzeugen und damit den Kreis aus dem Bild auszuschneiden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
  base.OnElementPropertyChanged(sender, e);
  if (Control != null && Control.Clip == null)
  {
    var min = Math.Min(Element.Width, Element.Height) / 2.0f;
    if (min <= 0)
      return;
    Control.Clip = new EllipseGeometry
    {
      Center = new System.Windows.Point(min, min),
      RadiusX = min,
      RadiusY = min
    };
  }
}

Und wieder müssen Sie den Renderer mit einem Assembly-Export exportieren.

1
2
3
4
5
[assembly: ExportRenderer(typeof(ImageCircle), typeof(ImageCircleRenderer))]
namespace CircleImage.WinPhone
{
 //...
}

ViewCells für ImageCircle

Wenn Sie alle Custom Renderer fertig haben, können Sie ImageCircle überall verwenden, auch in eigenen ViewCells für Ihre ListViews. Stellen Sie sicher, dass Sie für
Ihr Bild die gleiche Höhe und Breite festlegen und den Aspect auf AspectFill setzen, um den Kreis aus einem perfekten Quadrat zu schneiden.

1
2
3
4
5
6
7
8
9
int photoSize = Device.OnPlatform(50, 50, 80);
var photo = new ImageCircle
{
  WidthRequest = photoSize,
  HeightRequest = photoSize,
  Aspect = Aspect.AspectFill,
  HorizontalOptions = LayoutOptions.Center
};
photo.SetBinding(Image.SourceProperty, s => s.Image);
Xamarin Circle Image

Bildquelle: Xamarin

Den Code live erleben

Der Sourcecode steht Ihnen auf GitHub zur Verfügung.
Außerdem haben James Montemagno und Steven Yi bei der Xamarin Evolve ein Video davon gemacht, wie sie CircleImages in den Xamarin Evolve mobile apps
implementiert haben.itialen OnElementChanged und bei jeder Änderung von Höhe und Breite aufgerufen werden.


Es handelt sich bei diesem Artikel um eine Übersetzung aus dem Blogbeitrag von Xamarin

SHARE ONShare on FacebookTweet about this on TwitterGoogle+