Hello,
I`m trying to take a photo from library and then send it to a crop view.
To take the photo from library I use a custom renderer and it is working fine, here is the code:
using System;
using Xamarin.Forms;
namespace App
{
public class CropperPage : ContentPage
{
public CropperPage ()
{
#if __IOS__
MessagingCenter.Subscribe<App.iOS.CropperPageRenderer, UIKit.UIImage >(this, "cropiOS", async (sender, arg) =>
{
await Navigation.PopAsync();
var pag = new CropperPageiOS(arg);
await Navigation.PushAsync(pag);
});
#endif
}
protected override void OnDisappearing()
{
base.OnDisappearing();
#if __IOS__
MessagingCenter.Unsubscribe<App.iOS.CropperPageRenderer, UIKit.UIImage >(this, "cropiOS");
#endif
}
}
}
custom renderer:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using UIKit;
[assembly:ExportRenderer(typeof(App.CropperPage), typeof(App.iOS.CropperPageRenderer))]
namespace App.iOS
{
public class CropperPageRenderer : PageRenderer
{
UIImagePickerController imagePicker;
UIWindow window;
UIViewController viewController;
public CropperPageRenderer ()
{
Console.WriteLine("*****iOS Crop Page*****");
}
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
}
public override async void ViewDidLoad ()
{
base.ViewDidLoad ();
// create a new picker controller
imagePicker = new UIImagePickerController ();
// set our source to the photo library
imagePicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
// set what media types
imagePicker.MediaTypes = new string[]{"public.image"};
imagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
imagePicker.Canceled += Handle_Canceled;
// show the picker
window = UIApplication.SharedApplication.KeyWindow;
viewController = window.RootViewController;
if (viewController == null) {
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
await viewController.PresentViewControllerAsync(imagePicker, true);
}
else
await viewController.PresentViewControllerAsync(imagePicker, true);
}
// Do something when cancelled
void Handle_Canceled (object sender, EventArgs e) {
Console.WriteLine ("picker cancelled");
imagePicker.DismissModalViewController(true);
}
// This is a sample method that handles the FinishedPickingMediaEvent
protected async void Handle_FinishedPickingMedia (object sender, UIImagePickerMediaPickedEventArgs e)
{
await imagePicker.DismissViewControllerAsync (true);
// get the original image
UIImage originalImage = e.Info[UIImagePickerController.OriginalImage] as UIImage;
if(originalImage != null) {
//send a message to pop the CropperPage and send the image
Xamarin.Forms.MessagingCenter.Send<CropperPageRenderer, UIImage>(this, "cropiOS", originalImage);
// do something with the image
Console.WriteLine ("got the original image");
}
}
}
}
After the Image is picked the Handle_FinishedPickingMedia is triggered and send a message to pop the CropperPage from forms and Push another Page
that is also a custom renderer. And here is my problem!
in the CropperPage we have this Message from MessageCenter:
#if __IOS__
MessagingCenter.Subscribe<App.iOS.CropperPageRenderer, UIKit.UIImage >(this, "cropiOS", async (sender, arg) =>
{
await Navigation.PopAsync();
var pag = new CropperPageiOS(arg);
await Navigation.PushAsync(pag);
});
#endif
The CropperPage is popped... but the CropperPageiOS is not pushed.
This page is based in the code from this post
I tried to adapt it but could not test because the custom renderer is not working.
Here is the code:
using System;
using Xamarin.Forms;
namespace App
{
public class CropperPageiOS : ContentPage
{
public CropperPageiOS (UIKit.UIImage photo)
{
}
}
}
And the custom renderer:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using UIKit;
using System.Drawing;
using CoreGraphics;
[assembly: ExportRenderer(typeof(App.CropperPageiOS), typeof(App.iOS.CropperPageiOSRenderer))]
namespace App.iOS
{
public class CropperPageiOSRenderer : PageRenderer
{
UIImageView imageView;
CropperView cropperView;
UIPanGestureRecognizer pan;
UIPinchGestureRecognizer pinch;
UITapGestureRecognizer doubleTap;
UIImage photo;
UIWindow window;
UIViewController viewController;
//public static void Init() { }
public CropperPageiOSRenderer (UIImage originalImage)
{
photo = originalImage;
}
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
var page = e.NewElement as CropperPageiOS;
var view = NativeView;
}
public override async void ViewDidLoad ()
{
base.ViewDidLoad ();
using (photo) {
imageView = new UIImageView (new CGRect (0, 0, photo.Size.Width, photo.Size.Height));
imageView.Image = photo;
}
cropperView = new CropperView { Frame = View.Frame };
View.AddSubviews (imageView, cropperView);
float dx = 0;
float dy = 0;
pan = new UIPanGestureRecognizer (() => {
if ((pan.State == UIGestureRecognizerState.Began || pan.State == UIGestureRecognizerState.Changed) && (pan.NumberOfTouches == 1)) {
var p0 = pan.LocationInView (View);
if (dx == 0)
dx = (float)p0.X - cropperView.Origin.X;
if (dy == 0)
dy = (float)p0.Y - cropperView.Origin.Y;
var p1 = new PointF ((float)p0.X - dx, (float)p0.Y - dy);
cropperView.Origin = p1;
} else if (pan.State == UIGestureRecognizerState.Ended) {
dx = 0;
dy = 0;
}
});
float s0 = 1;
pinch = new UIPinchGestureRecognizer ( () => {
float s = (float)pinch.Scale;
float ds = Math.Abs (s - s0);
float sf = 0;
const float rate = 0.5f;
if (s >= s0) {
sf = 1 + ds * rate;
} else if (s < s0) {
sf = 1 - ds * rate;
}
s0 = s;
cropperView.CropSize = new SizeF (cropperView.CropSize.Width * sf, cropperView.CropSize.Height * sf);
if (pinch.State == UIGestureRecognizerState.Ended) {
s0 = 1;
}
});
doubleTap = new UITapGestureRecognizer ((gesture) => {
Crop();
}) {
NumberOfTapsRequired = 2, NumberOfTouchesRequired = 1
};
cropperView.AddGestureRecognizer (pan);
cropperView.AddGestureRecognizer (pinch);
cropperView.AddGestureRecognizer (doubleTap);
}
async void Crop()
{
var inputCGImage = photo.CGImage;
var image = inputCGImage.WithImageInRect (cropperView.CropRect);
using (var croppedImage = UIImage.FromImage (image)) {
imageView.Image = croppedImage;
imageView.Frame = cropperView.CropRect;
imageView.Center = View.Center;
cropperView.Origin = new PointF ((float)imageView.Frame.Left, (float)imageView.Frame.Top);
cropperView.Hidden = true;
}
await viewController.DismissViewControllerAsync (true);
}
}
}
Am I doing anything wrong??
Or there are any way to "navigate" between the iOS PageRenderes directly without have to use a new custom renderer?
The CropperPageiOSRenderer is never getting called! But the CropperPageiOS constructor is hit!