7

I have the following simple XAML page:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.UserGuides.VPN">
    <ContentPage.Content>
        <ScrollView>
            <StackLayout HorizontalOptions="Center" VerticalOptions="Center" Margin="10,10,10,10">
                <Label Margin="10,10,10,10" Text="How to connect to VPN." HorizontalOptions="Center" />
                <Label Margin="10,10,10,10" Text="If you have a corporate notebook, look for the Cisco AnyConnect application. Either in your start menu, on your desktop, or in your taskbar." />
                <Image x:Name="imgVPN1" Margin="10,10,10,10" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
                <Label Margin="10,10,10,10" Text="Select your region and press the Connect button." />
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>
</ContentPage>

In the constructor, I call a method to load the images:

private void LoadImages()
{
    imgVPN1.Aspect = Aspect.AspectFit;
    ImageSource imagesrc = ImageSource.FromResource("Test.Files.CiscoAnyConnect.PNG");
    imgVPN1.Source = imagesrc;
}

The result looks like this on my (rather large, high DPI) phone:

imgur link 1

Of course, I want the image to automatically expand so it takes up the entire width of the screen. While maintaining the aspect ratio. But how can I achieve this? I've already tried putting the Aspect to "AspectFill", and added

imgVPN1.WidthRequest = Application.Current.MainPage.Width;

To the LoadImages method, but that makes the end result look like this:

imgur link 2

I've been toying around with various HorizontalOptions, VerticalOptions, Aspects, GridView, StackLayouts,... The end result is always either the first or the second screenshot. So how can I achieve what I want here?

Matthias
  • 12,704
  • 13
  • 35
  • 56
  • what is your image size to experiment? – Yuri S Jul 18 '17 at 20:59
  • @YuriS The dimension of the CiscoAnyConnect.PNG image is 411x 191. If I could get those values it would be easy to set the HeightRequest to the aspect ratio, but it seems to be near impossible to do that with Xamarin.Forms from my research the past hours. – Matthias Jul 18 '17 at 21:05
  • can you post it somewhere so I don't need to rectreate similar? – Yuri S Jul 18 '17 at 21:20
  • Sure thing: http://imgur.com/Z487WqB – Matthias Jul 18 '17 at 21:23
  • There are 2 bugs created. One for grid and one for StackLayout. Bugs confirmed but not fixed. I would try to use relative layout if you need to scale a picture. Sorry https://bugzilla.xamarin.com/show_bug.cgi?id=27729 and https://bugzilla.xamarin.com/show_bug.cgi?id=55294 – Yuri S Jul 18 '17 at 21:56
  • There are 2 options. You can get image like this https://www.dropbox.com/s/qbh520ngp7dm3b3/ImageInStackLayout.png?dl=0 or use relative layout – Yuri S Jul 18 '17 at 22:04
  • @YuriS and how did you achieve that? Looks like huge margins or Heightrequest? – Matthias Jul 19 '17 at 04:13
  • that's the bug. the image scales but keeps original height. Is that acceptable? I am working on relative layout. It is tricky with the bug but doable. But I am having problems with scrolling which I am trying to solve – Yuri S Jul 19 '17 at 06:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/149630/discussion-between-yuri-s-and-matthias). – Yuri S Jul 19 '17 at 15:56
  • Only solution I've found up until now: https://stackoverflow.com/a/62171219/4058784 – Daniel Genezini Jun 03 '20 at 11:20

2 Answers2

11

Here is what can be done. XML almost didn't change, I just removed image Layout Options

<ContentPage.Content>
        <ScrollView>
            <StackLayout HorizontalOptions="Center" VerticalOptions="Center" Margin="10,10,10,10">
                <Label Margin="10,10,10,10" Text="How to connect to VPN." HorizontalOptions="Center" />
                <Label Margin="10,10,10,10" Text="If you have a corporate notebook, look for the Cisco AnyConnect application. Either in your start menu, on your desktop, or in your taskbar." />
                <Image x:Name="imgVPN1" Margin="10,10,10,10" />
                <Label Margin="10,10,10,10" Text="Select your region and press the Connect button." />
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>

After implementing everything in relative layout which also was not simple (I have the code if anybody needs it let me know) I found easier way. The key point is that image doesn't scale correctly and occupies too much space in height. But we know the size ratio of this image so we can use it. In the code we need to override OnSizeAllocated because in constructor the width is unknown yet. Then it's easy

protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height);
    imgVPN1.WidthRequest = width;
    imgVPN1.HeightRequest = width / 2.152; //given that image is 411 x 191
}

You could use other width than page with if you want. For example you could use stack layout width to consider margins for more accuracy but this is already tuning. Or you actually could use the image width itself like that

 protected override void OnSizeAllocated(double width, double height)
 {
     base.OnSizeAllocated(width, height);
     double needHeight=imgVPN1.Width / 2.152;
     if (imgVPN1.Height != needHeight)
         imgVPN1.HeightRequest = needHeight;
 }

enter image description here

Yuri S
  • 5,355
  • 1
  • 15
  • 23
  • Hi Yuri S. Thank you for this. Indeed I also managed to semi-fix/workaround the problem by manually specifying the HeightRequest. However for that to work you either need to know the dimensions of the image or the aspect ratio. And since you can't seem to get them programatically, you would need to hardcode this for every image. Anyway, I appreciate your help. And I think this will be the only way to do it for now. I will test your solution in my project. – Matthias Jul 20 '17 at 06:56
  • Where are your images? If they are in resources you know the the ratio in advance. if they downloaded you can probably find out the ratio. – Yuri S Jul 20 '17 at 15:19
  • Thank you! I nearly spent an entire day trying to figure this out! – primehalo Jun 02 '18 at 01:40
  • @primehalo glad it helped – Yuri S Jun 02 '18 at 06:19
  • In my opinion it's a huge embarrassment for Xamarin Forms that this has to be done via code in such a hacky way. Not to mention that this only works when image size is known. – astralmaster Mar 11 '20 at 11:44
  • Solution works! One side note, you can't compare two doubles this way: `if (imgVPN1.Height != needHeight)` you always get `true` – Arvis Aug 05 '20 at 15:17
-1

Here is what you need.

<ContentPage.Content>
    <ScrollView>
        <StackLayout Margin="20" Spacing="10">
            <Label Text="How to connect to VPN." HorizontalOptions="Center" />
            <Label Text="If you have a corporate notebook, look for the Cisco AnyConnect application. Either in your start menu, on your desktop, or in your taskbar." />
            <Image Source="yourimage.jpg" HorizontalOptions="Fill" />
            <Label Text="Select your region and press the Connect button." />
        </StackLayout>
    </ScrollView>
</ContentPage.Content>
Bright Lee
  • 2,306
  • 2
  • 27
  • 55