Xamarin Android - Custom Map Image Async - xamarin.android

I'm following this example:
CustomMap
In the example the image is informed directly(On here):
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/xamarin" />
I changed it to:
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:id="#+id/InfoWindowFoto"/>
and:
var infoFoto = view.FindViewById<ImageView>(Resource.Id.InfoWindowFoto);
if (infoFoto != null) GetImageBitmapFromUrl(infoFoto, customPin.local.Url_Imagem);
and:
private void GetImageBitmapFromUrl(ImageView img, string url)
{
using (var webClient = new WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
var bitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
img.SetImageBitmap(bitmap);
}
}
}
if the image is synchronous, it works with delay :(
If I change to asynchronous the image is not show:
var infoFoto = view.FindViewById<ImageView>(Resource.Id.InfoWindowFoto);
if (infoFoto != null) GetImageBitmapFromUrl(infoFoto, customPin.local.Url_Imagem);
private async void GetImageBitmapFromUrl(ImageView img, string url)
{
using (var webClient = new WebClient())
{
var imageBytes = await webClient.DownloadDataTaskAsync(url);
if (imageBytes != null && imageBytes.Length > 0)
{
var bitmap = await BitmapFactory.DecodeByteArrayAsync(imageBytes, 0, imageBytes.Length);
img.SetImageBitmap(bitmap);
}
}
}
I don't know how to update a view to show an image after downloading it. I also tried Picasso with the same result:
var infoFoto = view.FindViewById<ImageView>(Resource.Id.InfoWindowFoto);
Picasso.Get().Load(customPin.local.Url_Imagem).Into(infoFoto);
Can you help me fix this please
EDIT:
also tried with FFImageloading:
if (infoFoto != null) ImageService.Instance.LoadUrl(customPin.local.Url_Imagem).Into(infoFoto);
When I click on the pin the image does not appear. But if I click off the pin and the view closes, and I click on the pin again for the view to open the image appears quickly!
I need to know if it is possible to update the view inside the map after the image is downloaded...
My sample: Sample Project

The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map.
To update the info window later (for example, after an image has loaded), call showInfoWindow().
You could try the below codes:
private Bitmap bitmap;
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Local não localizado");
}
if (customPin.local.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
if (infoTitle != null) infoTitle.Text = marker.Title;
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoSubtitle != null) infoSubtitle.Text = marker.Snippet;
var infoNote = view.FindViewById<TextView>(Resource.Id.InfoNote);
if(infoNote != null) infoNote.Text = customPin.local.Note;
var infoFoto = view.FindViewById<ImageView>(Resource.Id.InfoWindowFoto);
if (infoFoto != null && bitmap == null)
{
GetImageBitmapFromUrlAsync(infoFoto, customPin.local.Url_Imagem, marker);
}
else
{
infoFoto.SetImageBitmap(bitmap);
}
return view;
}
return null;
}
private async void GetImageBitmapFromUrlAsync(ImageView img, string url, Marker marker)
{
using (var webClient = new WebClient())
{
var imageBytes = await webClient.DownloadDataTaskAsync(url);
if (imageBytes != null && imageBytes.Length > 0)
{
bitmap = await BitmapFactory.DecodeByteArrayAsync(imageBytes, 0, imageBytes.Length);
marker.ShowInfoWindow();
}
}
}
if your image_urls are not the same,you could use Dictionary to store the bitmap,use the url as the key,the bitmap as the value.

Related

Xamarin iOS camera and photos

I am taking a picture with the iOS camera and trying to extract metadata from the image. This is my code:-
partial void BtnCamera_TouchUpInside(UIButton sender)
{
UIImagePickerController imagePicker = new UIImagePickerController();
imagePicker.PrefersStatusBarHidden();
imagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
// handle saving picture and extracting meta-data from picture //
imagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
// present //
PresentViewController(imagePicker, true, () => { });
}
protected void Handle_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
try
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info[UIImagePickerController.MediaType].ToString())
{
case "public.image":
isImage = true;
break;
}
// get common info
NSUrl referenceURL = e.Info[new NSString("UIImagePickerControllerReferenceURL")] as NSUrl;
if (referenceURL != null)
Console.WriteLine("Url:" + referenceURL.ToString());
I am able to initiate the camera, take the picture and then however when I click 'use photo'... The referenceURL comes back as NULL... How can I get the url, such that to extract GPS coordinates of the photo and such other attributes ?
I had a tremendous amount of trouble with the URL. It can be a file, it can be a web url and it acts different on every device. My app crashed and burned so many times with my test group. I finally found a way to get the Metadata from the data. There are multiple ways to get the DateTaken, Width and Height as well as GPS Coordinates. In addition, I needed the Camera MFG and the Model.
string dateTaken = string.Empty;
string lat = string.Empty;
string lon = string.Empty;
string width = string.Empty;
string height = string.Empty;
string mfg = string.Empty;
string model = string.Empty;
PHImageManager.DefaultManager.RequestImageData(asset, options, (data, dataUti, orientation, info) => {
dateTaken = asset.CreationDate.ToString();
// GPS Coordinates
var coord = asset.Location?.Coordinate;
if (coord != null)
{
lat = asset.Location?.Coordinate.Latitude.ToString();
lon = asset.Location?.Coordinate.Longitude.ToString();
}
UIImage img = UIImage.LoadFromData(data);
if (img.CGImage != null)
{
width = img.CGImage?.Width.ToString();
height = img.CGImage?.Height.ToString();
}
using (CGImageSource imageSource = CGImageSource.FromData(data, null))
{
if (imageSource != null)
{
var ns = new NSDictionary();
var imageProperties = imageSource.CopyProperties(ns, 0);
if (imageProperties != null)
{
width = ReturnStringIfNull(imageProperties[CGImageProperties.PixelWidth]);
height = ReturnStringIfNull(imageProperties[CGImageProperties.PixelHeight]);
var tiff = imageProperties.ObjectForKey(CGImageProperties.TIFFDictionary) as NSDictionary;
if (tiff != null)
{
mfg = ReturnStringIfNull(tiff[CGImageProperties.TIFFMake]);
model = ReturnStringIfNull(tiff[CGImageProperties.TIFFModel]);
//dateTaken = ReturnStringIfNull(tiff[CGImageProperties.TIFFDateTime]);
}
}
}
}
}
}
The little helper function
private string ReturnStringIfNull(NSObject inObj)
{
if (inObj == null) return String.Empty;
return inObj.ToString();
}
You can request a PHAsset from the reference Url and that will contain some metadata. You can request the image data to obtain more.
Note: If you need full EXIF, you need to check to ensure the image on on the device (could be iCloud-based), download it if needed, and then load the image data with the ImageIO framework (lots of SO postings cover this).
public void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
void ImageData(PHAsset asset)
{
if (asset == null) throw new Exception("PHAsset is null");
PHImageManager.DefaultManager.RequestImageData(asset, null, (data, dataUti, orientation, info) =>
{
Console.WriteLine(data);
Console.WriteLine(info);
});
}
PHAsset phAsset;
if (e.ReferenceUrl == null)
{
e.OriginalImage?.SaveToPhotosAlbum((image, error) =>
{
if (error == null)
{
var options = new PHFetchOptions
{
FetchLimit = 1,
SortDescriptors = new[] { new NSSortDescriptor("creationDate", true) }
};
phAsset = PHAsset.FetchAssets(options).FirstOrDefault() as PHAsset;
ImageData(phAsset);
}
});
}
else
{
phAsset = PHAsset.FetchAssets(new[] { e.ReferenceUrl }, null).FirstOrDefault() as PHAsset;
ImageData(phAsset);
}
}
Note: Make sure you have request runtime photo library authorization PHPhotoLibrary.RequestAuthorization) and have set the Privacy - Photo Library Usage Description string in your info.plist to avoid a nasty privacy crash

How to share files to another app using Xamarin iOS?

I am using the below code to share the files to other apps using xamarin iOS. but i didnt get any response. Is there any other option to share files to other apps using Xamarin iOS?
Ref: http://xamarinhelp.com/share-dialog-xamarin-forms/
public async Task Show(string title, string message, string filePath)
{
var items = new NSObject[] { NSObject.FromObject(title), NSUrl.FromFilename(filePath) };
var activityController = new UIActivityViewController(items, null);
var vc = GetVisibleViewController();
NSString[] excludedActivityTypes = null;
if (excludedActivityTypes != null && excludedActivityTypes.Length > 0)
activityController.ExcludedActivityTypes = excludedActivityTypes;
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
if (activityController.PopoverPresentationController != null)
{
activityController.PopoverPresentationController.SourceView = vc.View;
}
}
await vc.PresentViewControllerAsync(activityController, true);
}
UIViewController GetVisibleViewController()
{
var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;
if (rootController.PresentedViewController == null)
return rootController;
if (rootController.PresentedViewController is UINavigationController)
{
return ((UINavigationController)rootController.PresentedViewController).TopViewController;
}
if (rootController.PresentedViewController is UITabBarController)
{
return ((UITabBarController)rootController.PresentedViewController).SelectedViewController;
}
return rootController.PresentedViewController;
}

UIImagePickerController crashesdue to memory issues in ios 10

I get random memory crashes with no memory warning. I have updated my ios to 10.0.2, my Xamarin to 6.2. I added camera usage description and photo library usage description, as suggested.
I have the following code in my FinishedPickingMedia callback
public async override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info)
{
try
{
// determine what was selected, video or image
bool isImage = false;
switch (info[UIImagePickerController.MediaType].ToString())
{
case "public.image":
isImage = true;
break;
case "public.video":
break;
}
if (isImage)
{
UIImage originalImage = info[UIImagePickerController.OriginalImage] as UIImage;
if (originalImage != null)
{
UIImageOrientation OrIn = originalImage.Orientation;
Debug.WriteLine("scaling image");
var originalImage1 = await Task.Run(() => ScaleAndRotateImage.ScaleAndRotateImageView(originalImage, OrIn));
if (originalImage1 != null)
{
var Data = originalImage1.AsJPEG(0.0f);
if (Data != null)
{
UIImage resizedImage = UIImage.LoadFromData(Data);
if (originalImage != null)
{
originalImage.Dispose();
originalImage = null;
}
originalImage1.Dispose();
originalImage1 = null;
Data.Dispose();
Data = null;
GC.Collect();
#if DEBUG
var Process1 = Process.GetCurrentProcess();
if (Process1 != null)
{
Debug.WriteLine(string.Format("memory allocated by FinishedPickingMedia = {0}", Process1.WorkingSet64));
}
#endif
camController.ShowPhoto(resizedImage);
}
if (info != null)
{
info.Dispose();
info = null;
}
GC.Collect();
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine("Exception Occured in FinishedPickingMedia method due to " + ex.Message);
}
finally
{
// dismiss the picker
picker.DismissModalViewController(true);
picker.Dispose();
picker = null;
GC.Collect();
}
}
This seams to happen randomly, my application needs to capture more than 200 photos (archive) I researched on the internet and this seams to be an issue with iOS 10 and this control

Xamarin IOS: Change tint color in share window

I am using this code for sharing in Xamarin IOS:
public void Share(string title, string content)
{
if (UIApplication.SharedApplication.KeyWindow == null || UIApplication.SharedApplication.KeyWindow.RootViewController == null)
return;
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(content))
return;
var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;
var imageToShare = UIImage.FromBundle("icon_120.png");
var itemsToShare = new NSObject[] { new NSString(content), imageToShare };
var shareStatusController = new UIActivityViewController(itemsToShare, null)
{
Title = title
};
//shareStatusController.NavigationController.NavigationBar.TintColor = UIColor.Black;
//rootController.NavigationController.NavigationBar.TintColor = UIColor.Black;
//shareStatusController.NavigationBar.TintColor = UIColor.FromRGB(0, 122, 255);
rootController.PresentViewController(shareStatusController, true, null);
Mvx.Resolve<IAnalyticsService>().LogEvent("Share button clicked.");
}
When i choose mail and i am redirected here http://take.ms/3KE4F. But color of cancel and send buttons is white (in NavigationBar). How can i change color of text of this button?
I found article
Cannot set text color of Send and Cancel buttons in the mail composer when presented from the UIActivityViewController in iOS7. But dont know howto apply this using Xamarin.
Thanks for any help.
Try this out:
public void Share(string title, string content)
{
if (UIApplication.SharedApplication.KeyWindow == null || UIApplication.SharedApplication.KeyWindow.RootViewController == null)
return;
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(content))
return;
//Share Barbutton tint
UIBarButtonItem.AppearanceWhenContainedIn (new [] {typeof(UINavigationBar)}).TintColor = UIColor.Cyan;
var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;
var imageToShare = UIImage.FromBundle("icon_120.png");
var itemsToShare = new NSObject[] { new NSString(content), imageToShare };
var shareStatusController = new UIActivityViewController(itemsToShare, null)
{
Title = title
};
shareStatusController.CompletionHandler += (NSString arg1, bool arg2) => {
// Set it back to old theme theme
UIBarButtonItem.AppearanceWhenContainedIn (new [] {typeof(UINavigationBar)}).TintColor = UIColor.White;
};
rootController.PresentViewController(shareStatusController, true, null);
Mvx.Resolve<IAnalyticsService>().LogEvent("Share button clicked.");
}
You basically set the the button tint before you present the controller then set it back in completion handler.

share image Xamarin Ios

I'm using Xamarin forms, and in my application has a button to share the problem that is being in my android application I got doing with Intent but in my application ios'm not knowing how to do, someone could help me?
using android
public async Task<bool> Share(ImageSource image)
{
Intent shareIntent = new Intent(Intent.ActionSend);
bitmapToShare = await GetBitmap (image);
if (bitmapToShare != null) {
CreateDirectoryForPictures("Xpto");
var filePath = System.IO.Path.Combine (dir.AbsolutePath, string.Format("xpto_{0}.png",Guid.NewGuid()));
var stream = new FileStream (filePath, FileMode.Create);
bitmapToShare.Compress (Bitmap.CompressFormat.Png, 100, stream);
stream.Close ();
Java.IO.File file = new Java.IO.File (filePath);
shareIntent.SetType ("image/*");
shareIntent.PutExtra (Intent.ExtraStream, Android.Net.Uri.FromFile (file));
shareIntent.AddFlags (ActivityFlags.GrantReadUriPermission);
Forms.Context.StartActivity (Intent.CreateChooser (shareIntent, "Compartilhar"));
}
return true;
}
private static async Task ShareImageAsyc(ImageSource image, string message, string url = null)
{
var handler = image.GetHandler();
if (handler == null) return;
var uiImage = await handler.LoadImageAsync(image);
var items = new List<NSObject> { new NSString(message ?? string.Empty) };
if (!url.IsNullOrEmpty())
items.Add(new NSString(url));
items.Add(uiImage);
var controller = new UIActivityViewController(items.ToArray(), null);
UIApplication.SharedApplication.KeyWindow.RootViewController.GetTopViewController()
.PresentViewController(controller, true, null);
}
From: https://github.com/jimbobbennett/JimLib.Xamarin/blob/master/JimLib.Xamarin.ios/Sharing/Share.cs

Resources