Ffimageloading: When scrolling listview, images are recycled

Created on 28 Apr 2017  路  9Comments  路  Source: luberda-molinet/FFImageLoading

I saw you clarification here:

https://github.com/luberda-molinet/FFImageLoading/wiki/FAQ#when-fling-or-scrolling-listview-images-are-recycled-user-can-see-the-old-image-before-the-new-one-loads-about-05-2-seconds-causing-flicker-and-unpleasant-artifacts-for-the-user-how-to-avoid-it

When fling or scrolling listview, images are recycled, user can see the old image before the new one loads (about 0.5 ~2 seconds), causing flicker and unpleasant artifacts for the user. How to avoid it?

But how I do that on binding? I've just bound image source to the URL, how would I set it to NULL while user is scrolling??

Xamarin.Forms question

Most helpful comment

For the next guy, that like me uses XAML everywhere, here is a solution:

public class MyViewCell : ViewCell
{
    private CachedImage _cachedImage = null;

    protected override void OnBindingContextChanged()
    {
        if (_cachedImage == null)
        {
            foreach (var child in ((StackLayout)((Frame)View).Content).Children)
            {
                if (child is CachedImage)
                {
                    _cachedImage = (CachedImage)child;
                    break;
                }
            }
        }

        _cachedImage.Source = null; // prevent showing old images occasionally

        var item = BindingContext as Feed;

        if (item == null)
            return;

        _cachedImage.HeightRequest = item.UrlSource.HasValue() ? 200 : 0;

        _cachedImage.Source = item.UrlSource;

        base.OnBindingContextChanged();
    }
}

Fix the Frame/Stack to match your UI, and if you are getting like me, weird row heights, the manual height helped me a lot.

For those interested, here is my view cell XAML:

<ListView.ItemTemplate>
    <DataTemplate>
        <design:iXingViewCell>
            <Frame
                Margin="10,10,10,0"
                CornerRadius="5"
                Padding="10"
                HasShadow="false"
                BackgroundColor="White">
                <StackLayout
                    Spacing="0"
                    Margin="3,3,3,15">
                    <StackLayout
                        Orientation="Horizontal"
                        HorizontalOptions="FillAndExpand">
                        <Label
                            Text="{Binding Text}"
                            HorizontalOptions="StartAndExpand"
                            LineBreakMode="TailTruncation"
                            FontSize="16" />
                        <Label
                            Text="{Binding TimeAgo}"
                            HorizontalOptions="End"
                            LineBreakMode="NoWrap"
                            FontSize="13" />
                    </StackLayout>
                    <ffimageloading:CachedImage
                        Margin="5"
                        Aspect="AspectFill"
                        HorizontalOptions="Start" />
                    <Label
                        Text="{Binding PostedBy}"
                        Margin="0,0,0,5"
                        LineBreakMode="WordWrap"
                        FontSize="13" />
                </StackLayout>
            </Frame>
        </design:iXingViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

Hope this can help someone in the future.

All 9 comments

I think you are looking for this

@EmmanVazz +1 for your solution, also it's much more performant to use list views with a lot of items without bindings (it's noticeable) :) I am thinking of adding a new property which will define behaviour if the image should be cleared before assigning a new one, but it's not implemented yet.

For the next guy, that like me uses XAML everywhere, here is a solution:

public class MyViewCell : ViewCell
{
    private CachedImage _cachedImage = null;

    protected override void OnBindingContextChanged()
    {
        if (_cachedImage == null)
        {
            foreach (var child in ((StackLayout)((Frame)View).Content).Children)
            {
                if (child is CachedImage)
                {
                    _cachedImage = (CachedImage)child;
                    break;
                }
            }
        }

        _cachedImage.Source = null; // prevent showing old images occasionally

        var item = BindingContext as Feed;

        if (item == null)
            return;

        _cachedImage.HeightRequest = item.UrlSource.HasValue() ? 200 : 0;

        _cachedImage.Source = item.UrlSource;

        base.OnBindingContextChanged();
    }
}

Fix the Frame/Stack to match your UI, and if you are getting like me, weird row heights, the manual height helped me a lot.

For those interested, here is my view cell XAML:

<ListView.ItemTemplate>
    <DataTemplate>
        <design:iXingViewCell>
            <Frame
                Margin="10,10,10,0"
                CornerRadius="5"
                Padding="10"
                HasShadow="false"
                BackgroundColor="White">
                <StackLayout
                    Spacing="0"
                    Margin="3,3,3,15">
                    <StackLayout
                        Orientation="Horizontal"
                        HorizontalOptions="FillAndExpand">
                        <Label
                            Text="{Binding Text}"
                            HorizontalOptions="StartAndExpand"
                            LineBreakMode="TailTruncation"
                            FontSize="16" />
                        <Label
                            Text="{Binding TimeAgo}"
                            HorizontalOptions="End"
                            LineBreakMode="NoWrap"
                            FontSize="13" />
                    </StackLayout>
                    <ffimageloading:CachedImage
                        Margin="5"
                        Aspect="AspectFill"
                        HorizontalOptions="Start" />
                    <Label
                        Text="{Binding PostedBy}"
                        Margin="0,0,0,5"
                        LineBreakMode="WordWrap"
                        FontSize="13" />
                </StackLayout>
            </Frame>
        </design:iXingViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

Hope this can help someone in the future.

As @EmmanVazz wrote, it's also described here: https://github.com/luberda-molinet/FFImageLoading/wiki/Xamarin.Forms-Advanced#usage-in-listview-with-listviewcachingstrategyrecycleelement-enabled

:)

@NightOwlCoder @daniel-luberda I dont understand there "old image" story. why you guys are talking about old image. are you not caching it? it should get it from the cache and display it, I thought. my image in my datatemplate looks like as below, I expect this to cache image to the disk for the first time and later usage should grab it from the cache within 120 days. So it is always 1 image for me, No old or new image. I believe my problem occurs because of LoadingPlaceholder, as i see loading.png for 0.5sec-1sec till actual image is loaded. when I scroll fast, it freezes my UI. How can I resolve it? are we talking about same problem?

    <ffimageloading:CachedImage  RetryCount="1 TransparencyEnabled = "false" 
  CacheDuration = "120"   LoadingPlaceholder="loading.png"   FadeAnimationEnabled="True"   
CacheType="Disk"  InputTransparent="True"     ErrorPlaceholder="error.png" />

Yes that was my issue.. the listview locks up ONLY when I use a place holder... However using the above code to null out the image has fixed the lock ups...

As to the problems we were having.. Yes we cache our images too... You will see the issue if you remove your placeholder... you will then see the previous image displaying before the new one (which looks bad).. Using a place holder hides this though... but causes lock ups when scrolling quickly...

@EmilAlipiev No, we're not caching anything additionally. It's how bindings in Xamarin.Forms in a ListView like scenarios, where cells are reused, binding have some kind of lag which can be resolved by this: https://github.com/luberda-molinet/FFImageLoading/wiki/Xamarin.Forms-Advanced#usage-in-listview-with-listviewcachingstrategyrecycleelement-enabled

It's even mentioned in official docs: https://developer.xamarin.com/guides/xamarin-forms/user-interface/listview/performance/#RecycleElement

@gviddy "However using the above code to null out the image has fixed the lock ups..." - what do you mean by that? can I give me example if you have done it using mvvm and xaml?
PS, even though still nice to know how you did this, it looks like 2.2.10 and above versions solves this problem. I havent had any lock up after updating

Hello @daniel-luberda

I change my binding concept and used your concept.

```
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>


protected override void OnBindingContextChanged()
{
imge1.Source = null;
var item = BindingContext as ProductModel;

        if (item == null)
        {
            return;
        }
        imge1.Source = item.ProductImage;
        base.OnBindingContextChanged();
    }

```

image Flicking problem has gone but now image hide then show when ListView Scrolled.

Any solution for this problem

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LeoJHarris picture LeoJHarris  路  22Comments

stopiccot picture stopiccot  路  17Comments

SemyonL picture SemyonL  路  20Comments

stesvis picture stesvis  路  144Comments

vlkam picture vlkam  路  21Comments