Skip to content

Instantly share code, notes, and snippets.

@Jyosua
Forked from andreinitescu/gist:c907c2951a719ed3ac34
Last active November 27, 2019 01:44
Show Gist options
  • Save Jyosua/6ba677c03c69f0c0fe964e65087728a5 to your computer and use it in GitHub Desktop.
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.
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