I posted couple other questions in regards to Zxing please DONT mark it duplicate just because they are about Zxing..
So, in my Xamarin iOS app, I am using Zxing to detect the barcode. I am using https://github.com/Redth/ZXing.Net.Mobile/tree/master/Samples/iOS as example.
I am using a subview to scan for barcodes. The custom overlay n everything works fine but it is unable to detect the barcode when I'm trying to scan.
Can anyone please help me out where I'm doing wrong or missing something.
CODE
public UIView camView;
AVCaptureScannerView scannerView;
UIActivityIndicatorView loadingView;
UIView loadingBg;
UIView topBg;
UIView bottomBg;
MobileBarcodeScanner scanner;
public event Action<ZXing.Result> OnScannedResult;
public MobileBarcodeScanningOptions ScanningOptions { get; set; }
public override void ViewDidLoad()
{
camView = new UIView(new CGRect(0, 0, this.View.Frame.Width, this.View.Frame.Height / 3)) { BackgroundColor = UIColor.Clear };
scanner = new MobileBarcodeScanner();
Root = new RootElement("ZXingDwatNet.Mobile") {
new Section {
camView
}
};
scannerView = new AVCaptureScannerView(camView.Frame);
camView = scannerView;
loadingBg = camView;// new UIView(this.View.Frame) { BackgroundColor = UIColor.Purple, AutoresizingMask = UIViewAutoresizing.FlexibleDimensions };
loadingView = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.White)
{
AutoresizingMask = UIViewAutoresizing.FlexibleMargins
};
loadingView.Frame = new CGRect((this.View.Frame.Width - loadingView.Frame.Width) / 4,
(this.View.Frame.Height - loadingView.Frame.Height) / 4,
loadingView.Frame.Width / 4,
loadingView.Frame.Height / 4);
loadingBg.AddSubview(loadingView);
View.AddSubview(loadingBg);
loadingView.StartAnimating();
this.View.InsertSubviewBelow(scannerView, loadingView);
this.View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
}
void HandleScanResult(ZXing.Result result)
{
string msg = "";
if (result != null && !string.IsNullOrEmpty(result.Text))
msg = "Found Barcode: " + result.Text;
else
msg = "Scanning Canceled!";
this.InvokeOnMainThread(() =>
{
var av = new UIAlertView("Barcode Result", msg, null, "OK", null);
av.Show();
});
}
public override void ViewDidAppear(bool animated)
{
//scannerView.OnScannerSetupComplete += HandleOnScannerSetupComplete;
//camView = scannerView;
var options = new MobileBarcodeScanningOptions
{
AutoRotate = false,
UseFrontCameraIfAvailable = false,
TryHarder = true
};
ScanningOptions = options;
if (UIDevice.CurrentDevice.CheckSystemVersion(7, 0))
{
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.Default;
SetNeedsStatusBarAppearanceUpdate();
}
else
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.BlackTranslucent, false);
Console.WriteLine("Starting to scan...");
Task.Factory.StartNew(() =>
{
BeginInvokeOnMainThread(() => scannerView.StartScanning(result =>
{
//if (!ContinuousScanning)
//{
// Console.WriteLine("Stopping scan...");
// scannerView.StopScanning();
//}
var evt = this.OnScannedResult;
if (evt != null)
evt(result);
}, this.ScanningOptions));
});
}
void HandleOnScannerSetupComplete()
{
BeginInvokeOnMainThread(() =>
{
if (loadingView != null && loadingBg != null && loadingView.IsAnimating)
{
loadingView.StopAnimating();
UIView.BeginAnimations("zoomout");
UIView.SetAnimationDuration(2.0f);
UIView.SetAnimationCurve(UIViewAnimationCurve.EaseOut);
loadingBg.Transform = CGAffineTransform.MakeScale(2.0f, 2.0f);
loadingBg.Alpha = 0.0f;
UIView.CommitAnimations();
loadingBg.RemoveFromSuperview();
}
});
}
Related
In my xamarin.forms app, I created a custom camera by using Camera view and custom renders. Everything works fine. In android after the photo capture I can check whether the taken photo contains a face or not.It is done by using Camera.IFaceDetectionListener. My question is how can I achieve this in iOS? I know there is vision API. But I don't want the live face tracking. I just simply want to check whether the taken photo contains face. Any help is appreciated.
My iOS CameraPreview
public class UICameraPreview : UIView, IAVCaptureMetadataOutputObjectsDelegate
{
AVCaptureVideoPreviewLayer previewLayer;
public AVCaptureDevice[] videoDevices;
CameraOptions cameraOptions;
public AVCaptureStillImageOutput stillImageOutput;
public AVCaptureDeviceInput captureDeviceInput;
public AVCaptureDevice device;
public event EventHandler<EventArgs> Tapped;
public AVCaptureSession CaptureSession { get; set; }
public bool IsPreviewing { get; set; }
public AVCaptureStillImageOutput CaptureOutput { get; set; }
public UICameraPreview(CameraOptions options)
{
cameraOptions = options;
IsPreviewing = false;
Initialize();
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
if (previewLayer != null)
previewLayer.Frame = Bounds;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
OnTapped();
}
protected virtual void OnTapped()
{
var eventHandler = Tapped;
if (eventHandler != null)
{
eventHandler(this, new EventArgs());
}
}
void Initialize()
{
CaptureSession = new AVCaptureSession();
previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession)
{
Frame = Bounds,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill
};
videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);
if (device == null)
{
return;
}
NSError error;
captureDeviceInput = new AVCaptureDeviceInput(device, out error);
CaptureSession.AddInput(captureDeviceInput);
var dictionary = new NSMutableDictionary();
dictionary[AVVideo.CodecKey] = new NSNumber((int)AVVideoCodec.JPEG);
stillImageOutput = new AVCaptureStillImageOutput()
{
OutputSettings = new NSDictionary()
};
CaptureSession.AddOutput(stillImageOutput);
Layer.AddSublayer(previewLayer);
CaptureSession.StartRunning();
IsPreviewing = true;
}
// Photo Capturing
public async Task CapturePhoto()
{
try
{
var videoConnection = stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);
var jpegData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
var photo = new UIImage(jpegData);
var rotatedPhoto = RotateImage(photo, 180f);
var img = rotatedPhoto;
CALayer layer = new CALayer
{
ContentsScale = 1.0f,
Frame = Bounds,
Contents = rotatedPhoto.CGImage //Contents = photo.CGImage,
};
CaptureSession.StopRunning();
photo.SaveToPhotosAlbum((image, error) =>
{
if (!string.IsNullOrEmpty(error?.LocalizedDescription))
{
Console.Error.WriteLine($"\t\t\tError: {error.LocalizedDescription}");
}
});
}
catch (Exception ex)
{
}
//MainPage.UpdateSource(UIImageFromLayer(layer).AsJPEG().AsStream());
//MainPage.UpdateImage(UIImageFromLayer(layer).AsJPEG().AsStream());
}
}
My CameraPreviewRenderer
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>, IAVCaptureMetadataOutputObjectsDelegate
{
UICameraPreview uiCameraPreview;
AVCaptureSession captureSession;
AVCaptureDeviceInput captureDeviceInput;
AVCaptureStillImageOutput stillImageOutput;
protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null)
{
if (Control == null)
{
uiCameraPreview = new UICameraPreview(e.NewElement.Camera);
SetNativeControl(uiCameraPreview);
MessagingCenter.Subscribe<Camera_Popup>(this, "CaptureClick", async (sender) =>
{
try
{
// Using messeging center to take photo when clicking button from shared code
var data = new AVCaptureMetadataOutputObjectsDelegate();
await uiCameraPreview.CapturePhoto();
}
catch (Exception ex)
{
return;
}
});
}
MessagingCenter.Subscribe<Camera_Popup>(this, "RetryClick", (sender) =>
{
Device.BeginInvokeOnMainThread(() =>
{
uiCameraPreview.CaptureSession.StartRunning();
uiCameraPreview.IsPreviewing = true;
});
});
MessagingCenter.Subscribe<Camera_Popup>(this, "FlipClick", (sender) =>
{
try
{
var devicePosition = uiCameraPreview.captureDeviceInput.Device.Position;
if (devicePosition == AVCaptureDevicePosition.Front)
{
devicePosition = AVCaptureDevicePosition.Back;
}
else
{
devicePosition = AVCaptureDevicePosition.Front;
}
uiCameraPreview.device = uiCameraPreview.videoDevices.FirstOrDefault(d => d.Position == devicePosition);
uiCameraPreview.CaptureSession.BeginConfiguration();
uiCameraPreview.CaptureSession.RemoveInput(uiCameraPreview.captureDeviceInput);
uiCameraPreview.captureDeviceInput = AVCaptureDeviceInput.FromDevice(uiCameraPreview.device);
uiCameraPreview.CaptureSession.AddInput(uiCameraPreview.captureDeviceInput);
uiCameraPreview.CaptureSession.CommitConfiguration();
}
catch (Exception ex)
{
var abc = ex.InnerException.Message;
}
});
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
void OnCameraPreviewTapped(object sender, EventArgs e)
{
if (uiCameraPreview.IsPreviewing)
{
uiCameraPreview.CaptureSession.StopRunning();
uiCameraPreview.IsPreviewing = false;
}
else
{
uiCameraPreview.CaptureSession.StartRunning();
uiCameraPreview.IsPreviewing = true;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.CaptureSession.Dispose();
Control.Dispose();
}
base.Dispose(disposing);
}
}
The CoreImage framework has CIDetector that provides image detectors for faces, QR codes, text, .... in which you pass in an image and you get a specific "feature set" back.
Example from Xamarin docs:
var imageFile = "photoFace2.jpg";
var image = new UIImage(imageFile);
var context = new CIContext ();
var detector = CIDetector.CreateFaceDetector (context, true);
var ciImage = CIImage.FromCGImage (image.CGImage);
var features = detector.GetFeatures (ciImage);
Console.WriteLine ("Found " + features.Length + " faces");
re: https://learn.microsoft.com/en-us/dotnet/api/CoreImage.CIDetector?view=xamarin-ios-sdk-12
When I try to run my Xamarin.forms maps application I get the following error: Event registration is overwriting existing delegate. Either just use events or your own delegate: MyApp.iOS.CustomRenderer.MapDelegate MapKit.MKMapView+_MKMapViewDelegate
I attached my CustomMapRender file to this question
... C#
using ICCHMapClusterControllerDelegate = MapClustering.ICCHMapClusterControllerDelegate;
using ICCHMapClusterer = MapClustering.ICCHMapClusterer;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MyApp.iOS.CustomRenderer
{
public class CustomMapRenderer : MapRenderer, ICCHMapClusterControllerDelegate//IMKMapViewDelegate
{
MKMapView mapView;
CustomMap customMap;
CCHMapClusterController mapClusterController;
ICCHMapClusterer mapClusterer;
List<MKPointAnnotation> annotations;
CLLocationManager LocationManager;
protected override void Dispose(bool disposing)
{
mapView.ShowsUserLocation = false;
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
mapView = Control as MKMapView;
customMap = e.NewElement as CustomMap;
customMap.LocationsLoaded += customMap_LocationsLoaded;
customMap.CenterToMyLocationButtonClicked += CenterToMyLocation;
customMap.OpenCallout += OpenCallout;
LocationManager = new CLLocationManager();
LocationManager.AuthorizationChanged += (object locationmanager, CLAuthorizationChangedEventArgs eventargs) =>
{
if (eventargs.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
{
mapView.ShowsUserLocation = true;
}
else
{
mapView.ShowsUserLocation = false;
}
};
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
mapView.ShowsUserLocation = true;
}
WMSTileOverlay WMSOverlay = new WMSTileOverlay(NetworkConstants.WmsOvermaasLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSProvincieTileOverlay ProvinceOverLay = new WMSProvincieTileOverlay
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay2 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "2")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay3 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "3")
{
CanReplaceMapContent = false
};
WMSTileOverlay WPMOverlay4 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "4")
{
CanReplaceMapContent = false
};
mapView.AddOverlay(WMSOverlay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(ProvinceOverLay, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay2, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay3, MKOverlayLevel.AboveLabels);
mapView.AddOverlay(WPMOverlay4, MKOverlayLevel.AboveLabels);
Debug.WriteLine("TESTING");
mapClusterController = new CCHMapClusterController(mapView);
mapClusterController.Delegate = new CCHMapClusterControllerDelegate();
mapClusterController.WeakDelegate = this;
// /new CCHMapDelegate();//new CCHMapDelegate();
//new CCHMapClusterControllerDelegate(); //new CCHMapDelegate ();
}
}
private void customMap_LocationsLoaded(object sender, List<Location> locations)
{
RemoveAnnotations();
if (locations == null || locations.Count == 0)
{
return;
}
annotations = new List<MKPointAnnotation>();
foreach (Location location in locations)
{
MKPointAnnotation anno = new MKPointAnnotation();
CLLocationCoordinate2D coord = new CLLocationCoordinate2D(location.Latitude, location.Longitude);
anno.Coordinate = coord;
anno.Title = location.WaterName;
anno.Subtitle = location.City + " " + location.ExternalReference;
annotations.Add(anno);
}
mapClusterController.AddAnnotations(annotations.ToArray(), null);
mapView.Delegate = new MapDelegate(locations, customMap);
mapClusterController.ReuseExistingClusterAnnotations = false;
}
private void RemoveAnnotations()
{
if (annotations != null && annotations.Count != 0)
{
mapClusterController.RemoveAnnotations(annotations.ToArray(), () =>
{
});
}
}
private void CenterToMyLocation(object sender, string e)
{
if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
|| CLLocationManager.Status == CLAuthorizationStatus.Authorized)
{
MKCoordinateRegion mapRegion;
mapRegion.Center.Latitude = mapView.UserLocation.Coordinate.Latitude;
mapRegion.Center.Longitude = mapView.UserLocation.Coordinate.Longitude;
mapRegion.Span.LatitudeDelta = 0.2;
mapRegion.Span.LongitudeDelta = 0.2;
mapView.SetRegion(mapRegion, true);
}
if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
//check if ios 7/8 this is ios 8
UIAlertController alertController = UIAlertController.Create(title: "Locatie", message: "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. " +
"dit kunt u in het instellingen menu geven.", preferredStyle: UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create(title: "Annuleren", style: UIAlertActionStyle.Cancel, handler: null));
alertController.AddAction(UIAlertAction.Create(title: "Instellingen", style: UIAlertActionStyle.Default, handler =>
{
NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
mapView.ShowsUserLocation = true;
UIApplication.SharedApplication.OpenUrl(settingsurl);
}));
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null);
//Old Obsolete
//UIAlertView alert = new UIAlertView("Locatie", "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. " +
// "dit kunt u in het instellingen menu geven.", null, "Annuleren", "Instellingen");
//alert.Clicked += (object alertsender, UIButtonEventArgs eventargs) => {
// if (eventargs.ButtonIndex != 0)
// {
// NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
// mapView.ShowsUserLocation = true;
// UIApplication.SharedApplication.OpenUrl(settingsurl);
// }
//};
//alert.Show();
}
if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
{
LocationManager.RequestWhenInUseAuthorization();
}
}
private void OpenCallout(object sender, Location e)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // delay execution for 1 s
Device.BeginInvokeOnMainThread(() =>
{
var anno = this.annotations.Where(a => a.Coordinate.Latitude == e.Latitude && a.Coordinate.Longitude == e.Longitude).FirstOrDefault();
if (anno != null)
{
this.mapClusterController.SelectAnnotation(anno, e.Latitude, e.Longitude);
}
});
});
}
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
}
internal class MapDelegate : MKMapViewDelegate
{
public MapDelegate(List<Location> locations, CustomMap CustomMap)
: base()
{
Locations = locations;
customMap = CustomMap;
conv = new LevelStatusToColorValueConverter();
defaultColor = Color.FromHex(ColorConstants.WaterLevelBadgeGreen).ToUIColor();
}
static NSObject Invoker = new NSObject();
List<Location> Locations;
string clusterPinId = "cluster";
string nonClusterPinId = "nonCluster";
CustomMap customMap;
LevelStatusToColorValueConverter conv;
UIColor defaultColor;
public override void RegionChanged(MKMapView mapView, bool animated)
{
if (mapView.UserLocationVisible)
{
customMap.ChangeStatusOfLocationImageOnMap(true);
}
else
{
customMap.ChangeStatusOfLocationImageOnMap(false);
}
}
public override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation anno)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(anno.Handle) as CCHMapClusterAnnotation; // this is required to get the underlying annotation object
string useId = nonClusterPinId;
if (anno is MKUserLocation)
return null;
if (annotation == null)
{
return null;
}
string imageName = "";
string imageURL = string.Empty;
string value = string.Empty;
UIColor color = defaultColor;
if (annotation.IsCluster)
{
useId = clusterPinId;
if (Locations != null)
{
List<Location> locations = new List<Location>();
foreach (MKPointAnnotation clusterAnno in annotation.Annotations)
{
string title = clusterAnno.Subtitle;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == title).ToList();
if (location != null && location.Count != 0)
{
locations.Add(location.First());
}
}
if (locations.Any())
{
imageName = MapUtil.GetCorrectImageNameForLocations(locations);
}
}
}
else
{
if (Locations != null)
{
string title = annotation.Subtitle;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == title).ToList();
if (location != null && location.Count != 0)
{
var currentLocation = location.First();
value = currentLocation.CurrentValueAsString;
var xColor = (Color)conv.Convert(currentLocation.WaterlevelStatus, null, null, null);
color = xColor.ToUIColor();
imageName = MapUtil.GetCorrectImageNameForLocation(currentLocation);
if (currentLocation.HasImage)
{
imageURL = currentLocation.SmallImageURL();
}
else
{
imageURL = NetworkConstants.NoImageSmall;
}
}
}
}
MKAnnotationView pinView = (MKAnnotationView)mapView.DequeueReusableAnnotation(useId);
if (pinView == null)
pinView = new MKAnnotationView(annotation, useId);
if (!annotation.IsCluster)
{
pinView.CanShowCallout = true;
double testWidth = value.Length < 11 ? 65 : 90;
var button = new UIButton(new CGRect(testWidth, 5, 10, 20));
button.SetImage(UIImage.FromBundle("disclosure"), UIControlState.Normal);
JSBadgeView badge = new JSBadgeView(button, JSBadgeView.Alignment.CenterLeft)
{
BadgeBackgroundColor = color,
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = Color.FromHex(ColorConstants.DarkGreyDetailText).ToUIColor(),
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.CenterLeft,
BadgeText = value
};
UIView view = new UIView(new CGRect(0, 0, testWidth + 10, 30));
view.ClipsToBounds = false;
view.AddSubview(button);
pinView.RightCalloutAccessoryView = view;
if (string.IsNullOrEmpty(imageURL))
{
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = UIImage.FromBundle("notavailable");
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
pinView.LeftCalloutAccessoryView = imageView;
}
else
{
FromUrl(imageURL, pinView);
}
}
pinView.Image = UIImage.FromBundle((string.IsNullOrEmpty(imageName)) ? "flowgreenpin" : imageName);
if (annotation.IsCluster)
{
pinView.CanShowCallout = false;
JSBadgeView badge = new JSBadgeView(pinView, JSBadgeView.Alignment.TopCenter)
{
BadgeBackgroundColor = UIColor.FromRGB(0.451f, 0.847f, 0.988f),
BadgeStrokeColor = UIColor.Red,
BadgeTextColor = UIColor.White,
BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
BadgeAlignment = JSBadgeView.Alignment.TopCenter,
BadgeText = annotation.Annotations.Count.ToString()
};
}
return pinView;
}
public static void InvokedOnMainThread(Action Action)
{
if (NSThread.Current.IsMainThread)
Action();
else
Invoker.BeginInvokeOnMainThread(() => Action());
}
static async Task FromUrl(string uri, MKAnnotationView pinView)
{
using (var httpClient = new HttpClient())
{
Task<byte[]> contentsTask = httpClient.GetByteArrayAsync(uri);
// await! control returns to the caller and the task continues to run on another thread
var contents = await contentsTask;
// load from bytes
var image = UIImage.LoadFromData(NSData.FromArray(contents));
var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
imageView.Image = image;
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
InvokedOnMainThread(delegate
{
pinView.LeftCalloutAccessoryView = imageView;
});
}
}
public override void DidSelectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
var annotation = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
if (annotation != null)
{
if (!annotation.IsCluster)
{
UITapGestureRecognizer tap = new UITapGestureRecognizer(OnTap);
view.AddGestureRecognizer(tap);
return;
}
MKMapRect mapRect = annotation.MapRect;
UIEdgeInsets edgeInsets = new UIEdgeInsets(20, 20, 20, 20);
mapView.SetVisibleMapRect(mapRect, edgeInsets, true);
}
mapView.DeselectAnnotation(view.Annotation, true);
}
public override void DidDeselectAnnotationView(MKMapView mapView, MKAnnotationView view)
{
view.GestureRecognizers = null;
}
public override void CalloutAccessoryControlTapped(MKMapView mapView, MKAnnotationView view, UIControl control)
{
if (view != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null && location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
private void OnTap(UIGestureRecognizer gesture)
{
var pinView = gesture.View as MKAnnotationView;
if (pinView != null)
{
var clusterPin = ObjCRuntime.Runtime.GetNSObject(pinView.Annotation.Handle) as CCHMapClusterAnnotation;
var location = Locations.Where(l => (l.City + " " + l.ExternalReference) == clusterPin.Subtitle).ToList();
if (location != null && location.Count != 0)
{
customMap.ClickedCallout(location.First());
}
}
}
public override MKOverlayRenderer OverlayRenderer(MKMapView mapView, IMKOverlay overlay)
{
var osmOverlay = overlay as WMSTileOverlay;
if (osmOverlay != null)
{
return new MKTileOverlayRenderer(new WMSTileOverlay(osmOverlay.BaseUrl, osmOverlay.Layer) { CanReplaceMapContent = false });
}
return new MKTileOverlayRenderer(new WMSProvincieTileOverlay() { CanReplaceMapContent = false });
}
}
internal class CCHMapDelegate : UIViewController, ICCHMapClusterControllerDelegate//CCHMapClusterControllerDelegate
{
[Export("mapClusterController:titleForMapClusterAnnotation:")]
public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
var annotationsCount = mapClusterAnnotation.Annotations.Count;
if (annotationsCount != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Title;
}
//public override string MapClusterTitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Title;
// }
// return "";
//}
[Export("mapClusterController:subtitleForMapClusterAnnotation:")]
public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
if (mapClusterAnnotation.Annotations.Count != 1) return "";
MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
return annot.Subtitle;
}
//public override string MapClusterSubtitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
// if (mapClusterAnnotation.Annotations.Count == 1) {
// MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
// return annot.Subtitle;
// }
// return "";
//}
[Export("mapClusterController:willReuseMapClusterAnnotation:")]
public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
{
}
//public override void MapClusterWillReuseAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
//{
//}
}
}
...
I am trying to get the above look on my tabbed bar in xamarin forms, i tried customizing the tabbed bar using renderer and still was not able to get the expected output
output i am getting
till now this is what i have tried
[assembly: ExportRenderer(typeof(BottomNavTabPage), typeof(BottomNavTabPageRenderer))]
namespace HealthMobile.Droid.Renderers
{
public class BottomNavTabPageRenderer : TabbedPageRenderer
{
private bool _isShiftModeSet;
public BottomNavTabPageRenderer(Context context)
: base(context)
{
}
protected override void OnVisibilityChanged(Android.Views.View changedView, [GeneratedEnum] ViewStates visibility)
{
base.OnVisibilityChanged(changedView, visibility);
var tabs = changedView.FindViewById<TabLayout>(Resource.Id.sliding_tabs);
if (tabs != null)
{
ViewGroup vg = (ViewGroup)tabs.GetChildAt(0);
int tabsCount = vg.ChildCount;
}
}
//protected override void DispatchDraw (global::Android.Graphics.Canvas canvas)
// {
// base.DispatchDraw (canvas);
// SetTabIcons();
// // var tabLayout = (TabLayout)GetChildAt(1);
// }
// private void SetTabIcons()
// {
// var element = this.Element;
// if (null == element)
// {
// return;
// }
// Activity activity = this.Context as Activity;
// if ((null != activity) && (null != activity.ActionBar) && (activity.ActionBar.TabCount > 0))
// {
// for (int i = 0; i < element.Children.Count; i += 1)
// {
// var tab = activity.ActionBar.GetTabAt(i);
// var page = element.Children[i];
// if ((null != tab) && (null != page) && (null != page.Icon)
// && (tab.CustomView == null))
// {
// var resourceId = activity.Resources.GetIdentifier(page.Icon.File.ToLowerInvariant(), "drawable", this.Context.PackageName);
// LinearLayout tabHeader
// = new LinearLayout(activity) { Orientation = Orientation.Vertical };
// ImageView tabImg = new ImageView(activity);
// TextView tabTitle = new TextView(activity);
// tabImg.SetImageResource(resourceId);
// tabTitle.Text = page.Title;
// tabTitle.SetTextColor(Android.Graphics.Color.White);
// tabHeader.AddView(tabTitle);
// tabHeader.AddView(tabImg);
// tab.SetCustomView(tabHeader);
// }
// }
// }
// }
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
var childViews = GetAllChildViews(ViewGroup);
//tab.SetIcon(Resource.Drawable.icon);
var scale = Resources.DisplayMetrics.Density;
var paddingDp = 0;
var dpAsPixels = (int)(paddingDp * scale + 0.5f);
foreach (var childView in childViews)
{
if (childView is BottomNavigationItemView tab)
{
//tab.SetPadding(-50, -100, -50, -100);
}
else if (childView is TextView textView)
{
textView.SetTextColor(Android.Graphics.Color.Transparent);
}
}
}
protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
{
base.SetTabIcon(tab, icon);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
try
{
if (!_isShiftModeSet)
{
var children = GetAllChildViews(ViewGroup);
if (children.SingleOrDefault(x => x is BottomNavigationView) is BottomNavigationView bottomNav)
{
bottomNav.SetShiftMode(false, false);
_isShiftModeSet = true;
}
}
}
catch (Exception e)
{
Console.WriteLine($"Error setting ShiftMode: {e}");
}
}
private List<View> GetAllChildViews(View view)
{
if (!(view is ViewGroup group))
{
return new List<View> {view };
}
var result = new List<View>();
for (int i = 0; i < group.ChildCount; i++)
{
var child = group.GetChildAt(i);
var childList = new List<View> {child};
childList.AddRange(GetAllChildViews(child));
result.AddRange(childList);
}
return result.Distinct().ToList();
}
}
}
i am trying to make this look like this somewhat
output expecting
also i tried setting up the icons but SetTabIcons method never get triggered
I am using FlowListView To set gallery view in my xamarin forms application, with following code..
public class Page1 : ContentPage
{
public Page1()
{
ObservableCollection<ItemModel> List = new ObservableCollection<ItemModel>();
string[] images = {
"https://farm9.staticflickr.com/8625/15806486058_7005d77438.jpg",
"https://farm5.staticflickr.com/4011/4308181244_5ac3f8239b.jpg",
"https://farm8.staticflickr.com/7423/8729135907_79599de8d8.jpg",
"https://farm3.staticflickr.com/2475/4058009019_ecf305f546.jpg",
"https://farm6.staticflickr.com/5117/14045101350_113edbe20b.jpg",
"https://farm2.staticflickr.com/1227/1116750115_b66dc3830e.jpg",
"https://farm8.staticflickr.com/7351/16355627795_204bf423e9.jpg",
"https://farm1.staticflickr.com/44/117598011_250aa8ffb1.jpg",
"https://farm8.staticflickr.com/7524/15620725287_3357e9db03.jpg",
"https://farm9.staticflickr.com/8351/8299022203_de0cb894b0.jpg",
};
int number = 0;
for (int n = 0; n < 20; n++)
{
for (int i = 0; i < images.Length; i++)
{
number++;
var item = new ItemModel()
{
ImageUrl = images[i],
FileName = string.Format("image_{0}.jpg", number),
};
List.Add(item);
}
}
FlowListView listView = new FlowListView()
{
FlowColumnTemplate = new DataTemplate(typeof(ListCell)),
SeparatorVisibility = SeparatorVisibility.None,
HasUnevenRows = true,
FlowColumnMinWidth = 110,
FlowItemsSource = List,
};
listView.FlowItemTapped += (s, e) =>
{
var item = (ItemModel)e.Item;
if (item != null)
{
App.Current.MainPage.DisplayAlert("Alert", "Tapped {0} =" + item.FileName, "Cancel");
}
};
Content = new StackLayout
{
Children = {
listView
}
};
}
}
public class ItemModel
{
public string ImageUrl { get; set; }
public string FileName { get; set; }
}
public class ListCell : View
{
public ListCell()
{
CachedImage IconImage = new CachedImage
{
HeightRequest = 100,
Aspect = Aspect.Fill,
DownsampleHeight = 100,
DownsampleUseDipUnits = false,
LoadingPlaceholder = "image_loading.png",
ErrorPlaceholder = "image_error.png"
};
IconImage.SetBinding(CachedImage.SourceProperty, "ImageUrl");
Label NameLabel = new Label
{
Opacity = 0.5,
HorizontalOptions = LayoutOptions.Fill,
HorizontalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.End,
};
NameLabel.SetBinding(Label.TextProperty, "FileName");
Grid grd = new Grid
{
Padding = 3,
ColumnDefinitions = {
new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) },
},
RowDefinitions = {
new RowDefinition { Height=GridLength.Star},
},
};
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
}
}
i added all the dependency of FlowListView, FFImage etc,
This above code just showing blank screen, Not displaying any data...
You're ListCell has nothing to show.
Append the existing lines to set the content to the grid in your custom ViewCell.
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
Content = grd; <--- add this line
Also have you done the following as per advice from the author? i.e. You've added the nuget library to the platforms in addition to the PCL and added the corresponding initialisation code for the library?
You must add this line to your platform specific project (AppDelegate.cs, MainActivity.cs, etc) before you use FFImageLoading:
CachedImageRenderer.Init();
This is what I got in my IOS:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
FFImageLoading.Forms.Touch.CachedImageRenderer.Init(); <---- this line
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
In a Forms project, is it possible to place a SearchBar such that it appears in the top/navigation bar of the app? What I want to achieve is something along the lines of the Android Youtube app, just cross-platform:
To do this, you should write a renderer for your Page
There is my implementation for iOS (with custom 'searchField')
using CoreGraphics;
using Foundation;
using MyControls;
using MyRenderer;
using UIKit;
using Xamarin.Forms;
[assembly: ExportRenderer(typeof(MySearchContentPage), typeof(MySearchContentPageRenderer))]
namespace IOS.Renderer
{
using Xamarin.Forms.Platform.iOS;
public class MySearchContentPageRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
SetSearchToolbar();
}
public override void WillMoveToParentViewController(UIKit.UIViewController parent)
{
base.WillMoveToParentViewController(parent);
if (parent != null)
{
parent.NavigationItem.RightBarButtonItem = NavigationItem.RightBarButtonItem;
parent.NavigationItem.TitleView = NavigationItem.TitleView;
}
}
private void SetSearchToolbar()
{
var element = Element as MySearchContentPage;
if (element == null)
{
return;
}
var width = NavigationController.NavigationBar.Frame.Width;
var height = NavigationController.NavigationBar.Frame.Height;
var searchBar = new UIStackView(new CGRect(0, 0, width * 0.85, height));
searchBar.Alignment = UIStackViewAlignment.Center;
searchBar.Axis = UILayoutConstraintAxis.Horizontal;
searchBar.Spacing = 3;
var searchTextField = new MyUITextField();
searchTextField.BackgroundColor = UIColor.FromRGB(239, 239, 239);
NSAttributedString strAttr = new NSAttributedString("Search", foregroundColor: UIColor.FromRGB(146, 146, 146));
searchTextField.AttributedPlaceholder = strAttr;
searchTextField.SizeToFit();
// Delete button
UIButton textDeleteButton = new UIButton(new CGRect(0, 0, searchTextField.Frame.Size.Height + 5, searchTextField.Frame.Height));
textDeleteButton.Font = UIFont.FromName("FontAwesome", 18f);
textDeleteButton.BackgroundColor = UIColor.Clear;
textDeleteButton.SetTitleColor(UIColor.FromRGB(146, 146, 146), UIControlState.Normal);
textDeleteButton.SetTitle("\uf057", UIControlState.Normal);
textDeleteButton.TouchUpInside += (sender, e) =>
{
searchTextField.Text = string.Empty;
};
searchTextField.RightView = textDeleteButton;
searchTextField.RightViewMode = UITextFieldViewMode.Always;
// Border
searchTextField.BorderStyle = UITextBorderStyle.RoundedRect;
searchTextField.Layer.BorderColor = UIColor.FromRGB(239, 239, 239).CGColor;
searchTextField.Layer.BorderWidth = 1;
searchTextField.Layer.CornerRadius = 5;
searchTextField.EditingChanged += (sender, e) =>
{
element.SetValue(MySearchContentPage.SearchTextProperty, searchTextField.Text);
};
searchBar.AddArrangedSubview(searchTextField);
var searchbarButtonItem = new UIBarButtonItem(searchBar);
NavigationItem.SetRightBarButtonItem(searchbarButtonItem, true);
NavigationItem.TitleView = new UIView();
if (ParentViewController != null)
{
ParentViewController.NavigationItem.RightBarButtonItem = NavigationItem.RightBarButtonItem;
ParentViewController.NavigationItem.TitleView = NavigationItem.TitleView;
}
}
}
}
Also, there is some discussion:How to include view in NavigationBar of Xamarin Forms?
I hope, you understood the main idea.