-
-
Save Jyosua/6ba677c03c69f0c0fe964e65087728a5 to your computer and use it in GitHub Desktop.
Xamarin.Forms Image subclass that finds the aspect needed to fill the view in one axis, and then dynamically expands the view in the other axis to fit the image without scaling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ImageEx : Image | |
{ | |
public static readonly BindableProperty TrueAspectProperty = | |
BindableProperty.Create( | |
propertyName: nameof(TrueAspect), | |
returnType: typeof(AspectEx), | |
declaringType: typeof(AspectEx), | |
defaultValue: AspectEx.AspectFit, | |
defaultBindingMode: BindingMode.OneWay, | |
propertyChanged: OnAspectExPropertyChanged); | |
private static void OnAspectExPropertyChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var aspectEx = (AspectEx)newValue; | |
Aspect aspect; | |
if (Enum.TryParse(aspectEx.ToString(), out aspect)) | |
{ | |
(bindable as ImageEx).Aspect = aspect; | |
} | |
} | |
public AspectEx TrueAspect | |
{ | |
get { return (AspectEx)base.GetValue(TrueAspectProperty); } | |
set { base.SetValue(TrueAspectProperty, value); } | |
} | |
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) | |
{ | |
// the returned sizeRequest contains the dimensions of the image | |
SizeRequest sizeRequest = base.OnMeasure(double.PositiveInfinity, double.PositiveInfinity); | |
switch (TrueAspect) | |
{ | |
case AspectEx.Uniform: | |
var innerAspectRatio = sizeRequest.Request.Width / sizeRequest.Request.Height; | |
if (double.IsInfinity(heightConstraint)) | |
{ | |
if (double.IsInfinity(widthConstraint)) | |
{ | |
// both destination constraints are infinity | |
// use the view's size request dimensions | |
widthConstraint = sizeRequest.Request.Width; | |
heightConstraint = sizeRequest.Request.Height; | |
} | |
else | |
{ | |
// destination height constraint is infinity | |
heightConstraint = widthConstraint * sizeRequest.Request.Height / sizeRequest.Request.Width; | |
} | |
} | |
else if (double.IsInfinity(widthConstraint)) | |
{ | |
// destination width constraint is infity | |
widthConstraint = heightConstraint * sizeRequest.Request.Width / sizeRequest.Request.Height; | |
} | |
else | |
{ | |
// both of the destination width and height constraints are non-infinity | |
var outerAspectRatio = widthConstraint / heightConstraint; | |
var resizeFactor = (innerAspectRatio >= outerAspectRatio) ? | |
(widthConstraint / sizeRequest.Request.Width) : | |
(heightConstraint / sizeRequest.Request.Height); | |
widthConstraint = sizeRequest.Request.Width * resizeFactor; | |
heightConstraint = sizeRequest.Request.Height * resizeFactor; | |
} | |
sizeRequest = new SizeRequest(new Size(widthConstraint, heightConstraint)); | |
break; | |
case AspectEx.None: | |
sizeRequest = new SizeRequest(new Size(sizeRequest.Request.Width / 2, sizeRequest.Request.Height / 2)); | |
break; | |
} | |
return sizeRequest; | |
} | |
} | |
public enum AspectEx | |
{ | |
/// <summary>Scale the image to fit the view. Some parts may be left empty (letter boxing).</summary> | |
AspectFit, | |
/// <summary>Scale the image to fill the view. Some parts may be clipped in order to fill the view.</summary> | |
/// <remarks /> | |
AspectFill, | |
/// <summary>Scale the image so it exactly fill the view. Scaling may not be uniform in X and Y.</summary> | |
Fill, | |
/// <summary>Scale the image to fill the view while it preserves its native aspect ratio.</summary> | |
Uniform, | |
/// <summary>The image preserves its original size.</summary> | |
None | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment