37

Here is xaml (an image in stacklayout). Everything is logical: I set Aspect to AspectFit and HorizontalOptions to FillAndExpand. Width of image must fill the width of stacklayout. Height must be calculated in order to image Aspect.

<Image BackgroundColor="Fuchsia"
       Aspect="AspectFit"
       Source="{Binding GroupLogo}"
       HorizontalOptions="FillAndExpand"
       VerticalOptions="FillAndExpand"/>

It fill the width but It doesn't want to draw image full width. Why?

enter image description here

Vorotnyak_Nazar
  • 894
  • 1
  • 10
  • 22

13 Answers13

40

AspectFit does what it says on the tin, it will fit the whole image into the View, which may leave parts of the view empty. Straight from Xamarin's documentation:

Scale the image to fit the view. Some parts may be left empty (letter boxing).

What you're looking for is AspectFill, which will scale the image to fit:

Scale the image to fill the view. Some parts may be clipped in order to fill the view.

If you are trying to get the image view to be the height of the image, I'd suggest adding a HeightRequest to the height of the image. Image controls don't seem to automatically scale in Xamarin, in my experience, as the native controls don't appear to support that by default either.

Reference

Rudi Visser
  • 21,350
  • 5
  • 71
  • 97
  • 2
    What you're looking for is AspectFill ( c ) no, I don't want to cut image. I want it to fill width and have height that it needs in order to save aspect of an image. How can I do that? Height request isn't an option. I don't know what Image I will receive – Vorotnyak_Nazar Dec 30 '16 at 11:51
  • As I said, the native controls don't scale so doing this in XF XAML without a custom renderered implementation (this is possible using some core changes on iOS / Android) won't be easy to accomplish. I'd suggest wherever you get your image from you could also provide another bindable property that gets the height of the image. At some point you have access to load the image and thus get its properties. – Rudi Visser Dec 30 '16 at 15:11
  • 1
    This is sort of a problem with xamarin forms here. I set it to be AspectFill, then it gets clipped vertically. What exactly should I set HeightRequest to that would make sense? It could be on a thousand different devices with a thousand different widths, and therefore different heights. This is something that really should be addressed in xamarin forms. – computrius Jul 31 '18 at 21:25
  • 2
    Rudi's suggestion worked for me: If you are resizing for the purpose of thumbnails I found this site which was helpful: https://forums.xamarin.com/discussion/58342/best-way-to-create-thumbnails-of-images – Chris Nov 12 '19 at 14:58
  • 5
    @computrius Addressed? This should have been basic object positioning 101. To this day, there is no XAML solution to the problem, only manually calculating correct widths and heights in code, which turns to be difficult when source image dimensions are not known beforehead. In CSS this can be accomplished in two lines of code: `width:100%; height:auto;` This is a huge embarrassment for Xamarin in my opinion. – astralmaster Mar 13 '20 at 14:44
17

I had a similar problem. I wanted to fill the width and the height of a StackLayout when possible but without cropping the actual image. The answers here have helped me find the correct way. Here is what has worked for me:

            <Grid 
                HorizontalOptions="FillAndExpand"
                VerticalOptions="FillAndExpand"
                 >
                <Image
                   x:Name="photo"                         
                   Aspect="AspectFit"                    
                />
            </Grid>

Maybe it will be of use for someone.

Clarification:

HorizontalOptions and VerticalOptions are with the value FillAndExpand, so the height and the width of the Grid are adjusted to fill the parent, in this case that is the Stacklayout. The image is a child of the Grid, so it transforms according to the parent (we haven't given any additional options to the image).

The aspect of the image is set to AspectFit, so that the image will fit the view (in this case the Grid) and also preserve its ratios.

In this way, if the image is in portrait mode but too narrow, it will fill the Grid's (StackLayout's) height but won't fill the width in order to preserve its ratios and to not be cropped from above or under.

If the image is in landscape mode, it will fill the Grid's (StackLayout's) width but won't fill the height in order to preserve its ratios and to not be cropped from left or right.

Sonia
  • 362
  • 3
  • 6
9

As I've found no working example. This works perfectly for me:

<Grid VerticalOptions="FillAndExpand">
      <Image Source="{Binding MyImageSrc}" Aspect="AspectFill" />
</Grid>
gyosifov
  • 3,193
  • 4
  • 25
  • 41
samuelru
  • 119
  • 1
  • 5
5

Up until now, the only solution I've found is to set Aspect="AspectFill" and set HeightRequest.

You can bind HeightRequest to a property and calculate the height based on the page width.

In my case the images are always the same proportion, so I do:

HeightRequest = (int)Math.Truncate(Xamarin.Forms.Application.Current.MainPage.Width / 1.41);

Daniel Genezini
  • 694
  • 9
  • 12
2

Try using CachedImage from FFImageLoading NuGet package

MyPage.xaml

<StackLayout HorizontalOptions="FillAndExpand"
             VerticalOptions="FillAndExpand"
             Padding="0">
    <ff:CachedImage Source="{Binding GroupLogo}"
                    HorizontalOptions="Fill"
                    VerticalOptions="Fill"
                    Aspect="Fill"
                    DownsampleToViewSize="True"/>
</StackLayout>

This will results image trying to horizontally fill the container and to automatically generate the width while maintaining its aspect.

Add this line of code to MainActivity.xaml after global::Xamarin.Forms.Forms.Init(this, bundle);

CachedImageRenderer.Init(true);

Example can be found here

Michael Yuwono
  • 2,452
  • 1
  • 14
  • 32
2

Aspect="AspectFit" use to fit your image inside the layout it can left space if images are small. Aspect="AspectFill" used to fit your image inside the layout and it will strech your image to take full space and it will not left space either your image is small with respect of your parent layout space. So You have to use AspectFill in place of AspectFit.

rwp
  • 1,786
  • 2
  • 17
  • 28
Naveen Tiwari
  • 301
  • 2
  • 12
2

I think this works. The trick is to wrap the image in a frame and bind the frame height to the image. In this example I am fitting the image to one side of a grid. hope it helps

 <Label Text="one lable" FontSize="Large"></Label>
                    <Grid  HorizontalOptions="Center"  BackgroundColor="Yellow" Margin="0"  >
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Frame Padding="0" Margin="0"  HeightRequest="{Binding Source={x:Reference image}, Path=Height}" HasShadow="False"   Grid.Row="0" Grid.Column="0" VerticalOptions="Start" >
                            <Image x:Name="image"   Source="roth9_2.bmp" Aspect="AspectFit" ></Image>
                        </Frame>
                    </Grid>

                    <Label Text="another label" FontSize="Large"></Label>
SandiaDeDia
  • 291
  • 2
  • 9
1

Try inclosing image inside of a grid like:

<grid>
    <image></image>
</grid>

Sometimes when I have an image that is not resizing properly, inclosing it inside a grid solves the problem.

Bjt1776
  • 189
  • 3
  • 15
1

This requires custom rendering for both platforms. Create a FillScreenImageRenderer that inherits from ImageRenderer.

<local:FillScreenImage Source="{ImageSource}"></local:FillScreenImage>

The code below stretch to fit the entire screen. You can tweak the view bounds to fit anything you want, like, in your case, is the parent view.

iOS:

    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);
        UIGraphics.BeginImageContext(UIScreen.MainScreen.Bounds.Size);
        Control.Image.Draw(UIScreen.MainScreen.Bounds);
        var dest = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        Control.Image = dest;
    }

Android:

    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);
        var display = ((Activity)Context).WindowManager.DefaultDisplay;
        var b = ((BitmapDrawable)Control.Drawable).Bitmap;
        Bitmap bitmapResized = Bitmap.CreateScaledBitmap(b, display.Width, display.Height, false);
        Control.SetImageDrawable(new BitmapDrawable(Resources, bitmapResized));
    }
Ramon Chan
  • 21
  • 2
1

It work with me

<Grid HorizontalOptions="FillAndExpand"
  VerticalOptions="FillAndExpand">
  <Image
         Aspect="AspectFill" 
         HeightRequest="255"
         WidthRequest="255">
         Source="https://pbs.twimg.com/media/DzZdI3AWkAYxH13.jpg" />
</Grid>
1

I think you are out of luck, on Android at least, HeightRequest MUST be set. Just make sure that all upper layouts have an auto height adjustment.

innom
  • 770
  • 4
  • 19
0

heightrequest of stacklayout must be either StartAndExpand or FillAndExpand or EndAndExpand in order to automatically adjust height

Jay Patel
  • 528
  • 8
  • 26
  • Still the same result – Vorotnyak_Nazar Dec 30 '16 at 13:41
  • Make heightsrequest of stack layout to StartAndExpand or FillAndExpand or EndAndExpand not the height request of image – Jay Patel Dec 31 '16 at 05:47
  • I have try all theses solutions, what I wish is to Keep the aspect ratio, fill the image horizontally, and the height must be adapted automatically (Height = Width). Is it possible ? Does someone have another idea ? – ClubberLang Aug 08 '18 at 16:32
-4

You can achieve this with the use of some CSS. Note: the css parsing a little finicky in forms right now, you can't have a semi-colon at the end of the line and need to place the width call at the end of the class def...

<Image BackgroundColor="Fuchsia"
   Source="{Binding GroupLogo}"
   class="ImageFill"/>

And your related css...

.ImageFill {
    ...
    width: 100%
}
Shadesz
  • 33
  • 4