This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 43569 - ToolbarItem Icon from local file
Summary: ToolbarItem Icon from local file
Status: VERIFIED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms (show other bugs)
Version: unspecified
Hardware: PC Windows
: Low normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-08-21 11:15 UTC by Slava Chernikoff
Modified: 2016-12-02 16:30 UTC (History)
8 users (show)

See Also:
Tags: ac
Is this bug a regression?: ---
Last known good build:


Attachments
Source code of a small project reproducing the bug. (308.88 KB, application/zip)
2016-09-13 12:38 UTC, Emanuele Sabetta
Details

Description Slava Chernikoff 2016-08-21 11:15:28 UTC
We have to make a cart icon with badge count in Toolbar. Currently there are 2 ugly ways to do it:
1. Place PNGs for each basket with badge (100 files for each density!!!!)
2. Draw image in app and place it to cache folder and manually manipulate NATIVE UIBarButtonItem or MenuItem to set UIImage/Drawable from generated file.

First way is simple but ugly (many hundreds of PNGs). Second is buggy (not so easy to find the right time for replacing default empty cart with new image).

For Android the issue is in https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs

Drawable iconBitmap = context.Resources.GetDrawable(icon);
That's it. No way to use path to cached image (local file system). It can be simply upgraded to get Drawable from a file.

The same stuff is for iOS:
https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.iOS/Extensions/ToolbarItemExtensions.cs

var image = UIImage.FromBundle(_item.Icon);

So my question is about working with custom toolbaritem images. It's final limitation to working with images only from Resources/Bundle?

It will be great to make cart icon (there are many requests on Forum) in XF.
Comment 1 Slava Chernikoff 2016-08-21 11:43:32 UTC
You can add simply check for icon path. If it starts from "file://" you can load it from local file system not from resource.
Comment 2 Rui Marinho 2016-08-22 17:49:04 UTC
Hi thanks, it shouldn't be a limitation, we can look at extending this. 
Having said that, if you can send a PR with your suggestion we can look at get this feedback integrated quicker.

Thanks
Comment 3 Gagik Kyurkchyan 2016-09-13 11:55:09 UTC
I also have exactly same issue exactly for the same case - badges! 

I render the icon with the badge, save it to local file system. Then, I assumed that if the ToolbarItem's Icon property is FileImageSource it should load image from local file system. And this is true for iOS, it works almost fine, except iOS applies tint to the icon and the color is gone and I couldn't find a way to fix this. And this doesn't work at all for android. After hours of trials I decided to have a look at Xamarin source code, and it was evident that FileImageSource handler for android only checks for file presence inside only local resources. To summarize there are 2 issues.

1. For ios there should be a way to make the iOS not tint the icon. This is usually specified in UIImage

 UIImage *image = [UIImage imageNamed:@"myImage.png"];
 image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

So, I believe there should be a special property for this in ToolbarItem

2. For Android, FileImageSource handled correctly. Specifically in Xamarin.Forms code NavigationPageRenderer in following lines

FileImageSource icon = item.Icon;
if (!string.IsNullOrEmpty(icon))
{
	Drawable iconBitmap = context.Resources.GetDrawable(icon);
	if (iconBitmap != null)
		menuItem.SetIcon(iconBitmap);
}

It's evident that file is loaded only from Resources.
Comment 4 Slava Chernikoff 2016-09-13 12:24:11 UTC
I created thread on forums and will promote this ticket:
https://forums.xamarin.com/discussion/77099/toolbaritem-icon-with-badges-could-be-possible-and-with-custom-icon-too/p1?new=1
Comment 5 Emanuele Sabetta 2016-09-13 12:38:55 UTC
Created attachment 17439 [details]
Source code of a small project reproducing the bug.

I've attached the zip archive with the source code of a small project reproducing the bug.

All you need to do to reproduce it is the following:

1 - compile the iOS version
2 - run and verify that the icons are displayed on the toolbar. They are. That is the expected result on iOS.
3 - exit and compile the Android version instead.
4 - run and verify that the icons are or are not displayed on the toolbar. Due to this bug, the icons are NOT displayed on the toolbar as expected.

You can see the exact line of code that gives the problem in the attached project:

Project:   ToolbarBadgeSample  
File:         ToolbarItemEx.cs 
Line:        331

At that line of code I assign the path to the Icon Property (it accepts objects of type Xamarin.Forms.FileImageSource or strings).
I also tried to cast explicitly, but there is no difference. Both works fine on iOS, but the file is not found on Android.

POSSIBLE CAUSE: Looking at the Xamarin.Forms source code the issue appears to be inside how Xamarin.Forms.Android handle ImageSource for action bar. ImageSource can be Uri, File and so on. On iOS ALL of these cases are handled. On Android the image is searched ONLY inside bundle. This is the most probable cause of the issue. To fix the bug you need to handle the missing cases on Android, like you already handle them in iOS.
Comment 6 Emanuele Sabetta 2016-09-14 06:48:33 UTC
Can somebody do a PR? It's a one liner.

We just need to edit this file:

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs

The only change would be to replace this line:

```
Drawable iconBitmap = context.Resources.GetDrawable(icon);
```

With this line:

```
Drawable iconBitmap = context.Resources.GetDrawable(new BitmapDrawable(context.Resources, Android.Graphics.BitmapFactory.DecodeFile(icon)));
```
Comment 7 Slava Chernikoff 2016-09-14 08:42:33 UTC
What about this?

Android
(https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs Line 698):

Drawable iconBitmap = icon.StartsWith("/") ? Drawable.CreateFromPath(icon) : context.Resources.GetDrawable(icon);

iOS
(https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.iOS/Extensions/ToolbarItemExtensions.cs Line 86):
var image = _item.Icon.StartsWith("/") ? UIImage.FromFile(_item.Icon) : UIImage.FromBundle(_item.Icon);
Comment 8 adrianknight89 2016-10-10 16:02:18 UTC
@Slava, I don't see anything wrong with iOS' loading of images from `FromBundle`. Emanuele's sample seems to be working with iOS. Can you provide a working sample?
Comment 9 adrianknight89 2016-10-10 16:09:35 UTC
Similarly, I'd like to see a repro for the tint issue.
Comment 10 Slava Chernikoff 2016-10-10 16:20:17 UTC
I just want to inform you that UIImage.FromBundle (https://developer.xamarin.com/guides/ios/user_interface/controls/part_5_-_images/) seek for image inside App Bundle (pre-installed with app) and UIImage.FromFile seek on local disk path.
Comment 11 Slava Chernikoff 2016-10-10 16:23:03 UTC
If UIImage.FromBundle  can also load image from local file system outside app bundle so it is undocumented feature and should be ignored I guess.
Comment 12 adrianknight89 2016-10-10 16:31:30 UTC
UIImage.FromBundle and UIImage.FromFile should be the same things except that the first one caches the image for frequent access. I'm not sure if there is any change required on iOS, but I'd still like to see a repro for the tint issue mentioned.
Comment 13 Slava Chernikoff 2016-10-10 16:37:03 UTC
Official documentation say other way:
https://developer.xamarin.com/api/type/MonoTouch.UIKit.UIImage/

FromBundle(String) : UIImage
Loads an image relative to the application bundle, and caches its result.

FromFile(String) : UIImage
Create an image object from the specified file.

If FromBundle works undocumented way with local files it's not good :)
Comment 14 adrianknight89 2016-10-10 17:26:03 UTC
See here: http://www.dracotorre.com/blog/image-loading-ios/

I think FromBundle will act like FromFile if the file can't be found in cache. I won't make any changes to iOS unless one of you can submit a repro.
Comment 15 adrianknight89 2016-10-10 17:26:59 UTC
See https://github.com/xamarin/Xamarin.Forms/pull/437 for Android.
Comment 16 Slava Chernikoff 2016-10-10 17:59:55 UTC
I think that we should rely on official documentation :)
Comment 17 Emanuele Sabetta 2016-10-20 18:01:35 UTC
The pull request is done and waiting for approval. Please approve it for the next Xamarin.Forms release.

https://github.com/xamarin/Xamarin.Forms/pull/437
Comment 18 Samantha Houts 2016-11-03 18:42:12 UTC
Should be fixed in 2.3.4-pre1. Thank you!
Comment 19 Parmendra Kumar 2016-12-02 16:30:15 UTC
I have checked this issue with xamarin.forms 2.3.4-pre1 and this issue has been fixed.


Hence closing this issue.

Note You need to log in before you can comment on or make changes to this bug.