Skip to content

Instantly share code, notes, and snippets.

@DaDude
Forked from Jyosua/ImageEx.cs
Created November 1, 2018 20:21
Show Gist options
  • Save DaDude/9905c393823a99dc5b477d77e3a6193d to your computer and use it in GitHub Desktop.
Save DaDude/9905c393823a99dc5b477d77e3a6193d 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.
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