-
Notifications
You must be signed in to change notification settings - Fork 376
Xamarin.Forms Advanced
You can now easily use FFImageLoading with standard views like Xamarin.Forms.Image. Just call this after Xamarin.Forms.Init
call:
-
CachedImageRenderer.InitImageViewHandler()
on Android -
CachedImageRenderer.InitImageSourceHandler()
on iOS / Mac and others
Initial idea here: https://github.com/roubachof/Xamarin.Forms.ImageSourceHandlers (thanks to @roubachof)
Usage in ListView with a lot of elements and ListViewCachingStrategy.RecycleElement enabled (default)
// EDIT Since XF 3.0 you could also use BindingMode.OneTime
to have similar effect.
If you use CachedImage
views inside ViewCells used by ListViews with ListViewCachingStrategy.RecycleElement
enabled, don't rely on bindings for setting the Source
property (they are so slow!) - please use ViewCell's OnBindingContextChanged
override of a ViewCell implementation to update it, avoiding loading images to wrong views. Example:
public class MyCustomCell : ViewCell
{
readonly CachedImage cachedImage = null;
public MyCustomCell()
{
cachedImage = new CachedImage();
View = cachedImage;
}
protected override void OnBindingContextChanged()
{
// you can also put cachedImage.Source = null; here to prevent showing old images occasionally
cachedImage.Source = null;
var item = BindingContext as Item;
if (item == null)
{
return;
}
cachedImage.Source = item.ImageUrl;
base.OnBindingContextChanged();
}
}
More info here: https://developer.xamarin.com/guides/xamarin-forms/user-interface/listview/performance/#RecycleElement
- Use custom cache key factory + custom
StreamImageSource
subclass which has aKey
property. This will allow FFImageLoading to use memory cache properly, without it, no images would be reused. - If your source is a byte array, reuse the same array:
ImageSource.FromStream(async (token) => new MemoryStream(byteArrayWhichIsReusedMultipleTimes))
Here's the sample of using custom cache key factory + custom StreamImageSource
subclass which has a Key
property sample1 sample2. This will allow FFImageLoading to use memory cache properly, without it, no images would be reused.
It's better to use EmbeddedResourceImageSource
which has a better performance and lets you to avoid a lot of issues.
If you use ImageSource.FromResource("ProjectName.Resources.image.png");
PLEASE also set a custom cache key. See this: https://github.com/luberda-molinet/FFImageLoading/issues/696
You can override CachedImage
global defaults by calling ImageService.Instance.Initialize
method in platform specific project. You can globally enable transparency channel, disable fade animation, specify own logger, timeouts and a lot more. Read more details here: link
Read more details here: link
Preferred way to implement custom transformations for PCL Xamarin.Forms projects is to use PCL Bait&switch technique (http://log.paulbetts.org/the-bait-and-switch-pcl-trick/).
- Transformations should be implemented in a separate projects
-
Separate transformations project for Android - reference it in Android platform specific project
-
Separate transformations project for iOS - reference it in iOS platform specific project
-
Separate transformations project for Windows - reference it in Windows platform specific project
-
Separate transformations project for Shared Project - reference it in a Xamarin.Forms specific project (where the Page definitions are). If you don't use PCL project (but shared) you don't need it
-
- All projects must have the same:
- Assembly names - (Xamarin Studio: Project Options -> Main Settings -> Default Namespace)
- Namespaces - (Xamarin Studio: Project Options -> Output -> Assembly Name)
- Versions - Add eg.
[assembly: AssemblyVersion("1.0.0")]
to each projectAssemblyInfo.cs
file
- All implemented transformations must have the same:
- Constructors
- Namespaces
For platform a specific guide see this: Custom Transformations Guide
You can force FFImageLoading to use custom keys for cache. For that you need to make your own ICacheKeyFactory implementation and set CachedImage.CacheKeyFactory
property to it.
class CustomCacheKeyFactory : ICacheKeyFactory
{
public string GetKey(ImageSource imageSource, object bindingContext)
{
if (imageSource == null)
return null;
string itemSuffix = string.Empty;
var bindingItem = bindingContext as ListExampleItem;
if (bindingItem != null)
itemSuffix = bindingItem.FileName;
// UriImageSource
var uriImageSource = imageSource as UriImageSource;
if (uriImageSource != null)
return string.Format("{0}+myCustomUriSuffix+{1}", uriImageSource.Uri, itemSuffix);
// FileImageSource
var fileImageSource = imageSource as FileImageSource;
if (fileImageSource != null)
return string.Format("{0}+myCustomFileSuffix+{1}", fileImageSource.File, itemSuffix);
// StreamImageSource
var streamImageSource = imageSource as StreamImageSource;
if (streamImageSource != null)
return string.Format("{0}+myCustomStreamSuffix+{1}", streamImageSource.Stream.GetHashCode(), itemSuffix);
throw new NotImplementedException("ImageSource type not supported");
}
}
var cachedImage = new CachedImage() {
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 300,
HeightRequest = 300,
CacheDuration = TimeSpan.FromDays(30),
DownsampleToViewSize = true,
RetryCount = 0,
RetryDelay = 250,
TransparencyEnabled = false,
Source = "http://loremflickr.com/600/600/nature?filename=simple.jpg",
CacheKeyFactory = new CustomCacheKeyFactory(),
};
<ffimageloading:CachedImage HorizontalOptions="Center" VerticalOptions="Center"
WidthRequest="300" HeightRequest="300"
DownsampleToViewSize="true"
Source = "http://loremflickr.com/600/600/nature?filename=simple.jpg">
<ffimageloading:CachedImage.CacheKeyFactory>
<local:CustomCacheKeyFactory/>
</ffimageloading:CachedImage.CacheKeyFactory>
</ffimageloading:CachedImage>