glidex icon indicating copy to clipboard operation
glidex copied to clipboard

Xamarin.Forms.Image Does Not Appear

Open brminnick opened this issue 5 years ago • 16 comments

The Image does not appear when HorizontalOptions = LayoutOptions.CenterAndExpand

Reproduction Sample: https://github.com/brminnick/GlideX_HorizontalOptions_Repro

brminnick avatar Oct 24 '18 23:10 brminnick

Repro Video: https://1drv.ms/u/s!AnmXwEzpaYLslzhIQmucWNj7U98O

brminnick avatar Oct 24 '18 23:10 brminnick

So this brings up a valid concern:

  • Xamarin.Forms layouts tend to let the size of image content "push" layouts around. In other words, the size of the image impacts the layout.
  • Glide, however, is implemented in reverse. It will scale/transforms/thumbnail images as they are loaded! Hence, an image set to Center will not grow when the image is loaded. It will load an image the size of the control...

These two ways of doing things are at odds...

I am uncertain what to do here yet. I tried doing something like what was mentioned here:

//NOTE: SIZE_ORIGINAL is Java.Lang.Integer.MinValue
//https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/request/target/Target.java#L28
builder.Apply(RequestOptions.OverrideOf (SIZE_ORIGINAL));

But it did not adjust the layout in Xamarin.Forms.

jonathanpeppers avatar Oct 25 '18 16:10 jonathanpeppers

Image in StackLayout Doesn't Appear

Here's another example where the image doesn't appear; this time when it's inside of a StackLayout

public class StackLayoutPage : ContentPage
{
    const string _xamarinImageUrl = "https://raw.githubusercontent.com/github/explore/06da849e137507b144448ac2b28bc19d3b909cab/topics/xamarin/xamarin.png";

    public StackLayoutPage()
    {
        var imageLabel = new Label { Text = "This image is broken" };
        var brokenImage = new Image { Source = _xamarinImageUrl };

        var stackLayout = new StackLayout
        {
            Children = {
                imageLabel,
                brokenImage
            }
        };

        Content = stackLayout;
    }
}

screenshot_1541018150

Workaround

Specifying a value for HeightRequest will allow the image to appear

public class StackLayoutPage : ContentPage
{
    const string _xamarinImageUrl = "https://raw.githubusercontent.com/github/explore/06da849e137507b144448ac2b28bc19d3b909cab/topics/xamarin/xamarin.png";

    public StackLayoutPage()
    {
        var imageLabel = new Label { Text = "This image is not broken" };
        var brokenImage = new Image
        {
            HeightRequest = 100,
            Source = _xamarinImageUrl
        };

        var stackLayout = new StackLayout
        {
            Children = {
                imageLabel,
                brokenImage
            }
        };

        Content = stackLayout;
    }
}

screenshot_1541018732

brminnick avatar Oct 31 '18 20:10 brminnick

I'm hitting sort of the same issue: my Image only appears after the source has been changed (for animations between images) or a full layout cycle has been done. I have toggle to show/hide the navigation bar and when I toggle that the images appear, not before.

rogihee avatar Jan 13 '19 12:01 rogihee

@rogihee your case sounds different: using an animation + inside navigation bar.

Could you file a new issue with a code example?

jonathanpeppers avatar Jan 14 '19 13:01 jonathanpeppers

hi Jonathan, I meant that that toggling the nav bar on/off was showing it in the page. I'll see if I can reproduce the case, it is quite standard usage of Image, but somewhere in nested layout.

rogihee avatar Jan 14 '19 18:01 rogihee

I had the same issue. I realized if the HorizontalOptions don't be set to Fill or FillAndExpand, the image don't shows (widht == 0).

But if you update the layout, showing and hide an activity indicator g.ex. the image shows up (width != 0).

I made an example for this.

pictos avatar Feb 18 '19 23:02 pictos

Same issue here. I just noticed that every time I toggle the IsVisible property, I always see this log from the console output:

[glidex] IImageViewHandler of type `Android.Glide.ImageViewHandler`, `LoadImageAsync` called.

Here's a snippet with comments from our code. Hope it would help you figure out what's causing the issue.

<Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>


    <!-- This button gets distorted/disappears when you click it enough times -->
    <ImageButton
        Grid.ColumnSpan="3"
        Margin="0,20,10,10"
        VerticalOptions="Start"
        HorizontalOptions="End"
        WidthRequest="44"
        HeightRequest="44"
        BackgroundColor="Transparent"
        IsVisible="False"
        Source="{x:Static res:Images.IcSomeImage}"
        Command="{Binding SomeCommand}">
        <ImageButton.Behaviors>
            <behaviors:FadingVisibilityBehavior
                BindingContext="{Binding BindingContext, Source={x:Reference Page}}"
                IsVisible="{Binding ShowControls}" />
        </ImageButton.Behaviors>
    </ImageButton>

    <!-- This button have almost the same property as above but it has no issue -->
    <ImageButton
        Grid.ColumnSpan="3"
        VerticalOptions="Start"
        HorizontalOptions="Start"
        WidthRequest="44"
        HeightRequest="44"
        Margin="10,20"
        BackgroundColor="Transparent"
        Source="{x:Static res:Images.IcSomeOtherImage}"
        Command="{Binding SomeOtherCommand}">
        <ImageButton.Behaviors>
            <behaviors:FadingVisibilityBehavior
                BindingContext="{Binding BindingContext, Source={x:Reference Page}}"
                IsVisible="{Binding ShowControls}" />
        </ImageButton.Behaviors>
    </ImageButton>

    <!-- Other more controls are omitted -->

</Grid>

mr5z avatar Oct 24 '19 04:10 mr5z

I suspect it has something to do with the Forms layout engine and size calculation. Either incorrect sizing by Forms or the incorrect size as seen by Glide. I noticed the VerticalOptions and HorizontalOptions did have an effect on whether Glide showed the picture or not, but could not create a simple reproduction.

rogihee avatar Oct 24 '19 08:10 rogihee

In some layouts you should try setting HeightRequest or WidthRequest.

The problem is a conflict in how Glide and Xamarin.Forms work: https://github.com/jonathanpeppers/glidex/issues/10#issuecomment-433109852

jonathanpeppers avatar Oct 24 '19 13:10 jonathanpeppers

I am trying to create a staggered layout but while using glidex I cannot get the image size. I need to provide height request and width request manually. What should I do to get correct sizes ?

AswinPG avatar Oct 29 '20 09:10 AswinPG

I am trying to create a staggered layout but while using glidex I cannot get the image size. I need to provide height request and width request manually. What should I do to get correct sizes ?

UX wise, you should always specify the sizes in ImageView controls on its @1x equivalent.

mr5z avatar Oct 30 '20 14:10 mr5z

But

I am trying to create a staggered layout but while using glidex I cannot get the image size. I need to provide height request and width request manually. What should I do to get correct sizes ?

UX wise, you should always specify the sizes in ImageView controls on its @1x equivalent.

But in a staggered layout, the image size is dynamic

AswinPG avatar Oct 30 '20 14:10 AswinPG

Is there any way to ignore/skip glidex on a per image basis?

Same situation as this - I have one image thats not appearing because of no WidthRequest (has HeightRequest, but image sizes are unknown), but this particular page isn't in a list, it's a single image on a page so the performance boost from glidex isn't as important.

thewoodknight avatar May 31 '21 23:05 thewoodknight

@thewoodknight you might implement your own IGlideHandler to do this, see: https://github.com/jonathanpeppers/glidex/issues/89#issuecomment-790635408

jonathanpeppers avatar Jun 01 '21 14:06 jonathanpeppers

I faced this issue too.

Implementing IGlideHandler solved this problem. However, performance may be degraded.

my workaround:

public class CustomGlideHandler: IGlideHandler
{
    public bool Build(ImageView imageView, ImageSource source, RequestBuilder builder, CancellationToken token)
    {
        // if not using glidex, the file name is attached "_nc".
        if (source is FileImageSource imageSource && imageSource.File.EndsWith("_nc"))
        {
            builder.Dispose();
            builder = null;                

            // call default handler
            var defaultHandler = new FileImageSourceHandler();
            Task.Run(() =>
            {
                defaultHandler.LoadImageAsync(imageSource, imageView, token);
            });

            return true;
        }

        return false;
    }        
}

muak avatar Mar 07 '22 03:03 muak