Swift, Access parent properties in child class - ios

My problem is I donĀ“t jnow how to access parent properties within the child class
class imageOverlayRenderer: MKOverlayRenderer {
var bar = self.overlay
}
MKOverlayRenderer should have the property overlay
What I really want is to write a custom subclass of MKOverlayRender to render an image, the code in Objective C is:
#import <MapKit/MapKit.h>
#interface PVParkMapOverlayView : MKOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage;
#end
and
#import "PVParkMapOverlayView.h"
#interface PVParkMapOverlayView ()
#property (nonatomic, strong) UIImage *overlayImage;
#end
#implementation PVParkMapOverlayView
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage {
self = [super initWithOverlay:overlay];
if (self) {
_overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef imageReference = self.overlayImage.CGImage;
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextDrawImage(context, theRect, imageReference);
}
#end

You can't reference self in a normal property declaration - you have to declare the property lazy:
class imageOverlayRenderer: MKOverlayRenderer {
lazy var bar: MKOverlay! = self.overlay
}

Related

Fill MKOverlay with specific color and blending mode

I need to fill MKOverlay with specific color and kCGBlendModeMultiply blending mode. I've implemented MKOverlayRenderer subclass as follows:
#interface MapDimOverlayRenderer : MKOverlayRenderer
#property (nonatomic, strong) UIColor *overlayColor;
#property (nonatomic, strong) CGFloat overlayAlpha;
#end
#implementation MapDimOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay {
self = [super initWithOverlay:overlay];
if (self) {
self.overlayAlpha = 0.9;
self.overlayColor = [UIColor hx_colorWithHexString:#"2C3239" alpha:self.overlayAlpha];
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGContextSetBlendMode(context, kCGBlendModeMultiply);
CGContextSetFillColorWithColor(context, self.overlayColor.CGColor);
CGContextFillRect(context, [self rectForMapRect:MKMapRectWorld]);
}
#end
The problem is CGContextSetBlendMode doesn't affect to result. I tried to set different modes. The result is always the same as default (kCGBlendModeNormal).

How to detect touch on non-transparent parts of overlay image drawn by MKOverlayRenderer

I draw an image on my map as overlay like so (RW example code):
It has a transparent part in the middle (that should let touches through) and non-transparent sides that should catch touches (kind of like a donut :)).
Overlay.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#class PVPark;
#interface PVParkMapOverlay : NSObject <MKOverlay>
- (instancetype)initWithPark:(PVPark *)park;
#end
Overlay.m
#import "PVParkMapOverlay.h"
#import "PVPark.h"
#implementation PVParkMapOverlay
#synthesize coordinate;
#synthesize boundingMapRect;
- (instancetype)initWithPark:(PVPark *)park {
self = [super init];
if (self) {
boundingMapRect = park.overlayBoundingMapRect;
coordinate = park.midCoordinate;
}
return self;
}
#end
OverlayView.h
#import <MapKit/MapKit.h>
#interface PVParkMapOverlayView : MKOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage;
#end
OverlayView.m
#import "PVParkMapOverlayView.h"
#interface PVParkMapOverlayView ()
#property (nonatomic, strong) UIImage *overlayImage;
#end
#implementation PVParkMapOverlayView
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage {
self = [super initWithOverlay:overlay];
if (self) {
_overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef imageReference = self.overlayImage.CGImage;
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextDrawImage(context, theRect, imageReference);
}
#end
I add it to the map like so:
MainViewController
- (void) viewDidLoad
{
[super viewDidLoad];
[self addOverlay];
}
- (void)addOverlay {
PVParkMapOverlay *overlay = [[PVParkMapOverlay alloc] initWithPark:self.park];
[self.mapView addOverlay:overlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:PVParkMapOverlay.class]) {
UIImage *magicMountainImage = [UIImage imageNamed:#"overlay_park"];
PVParkMapOverlayView *overlayView = [[PVParkMapOverlayView alloc] initWithOverlay:overlay overlayImage:magicMountainImage];
return overlayView;
}
return nil;
}
How can I detect a touch on the non-transparent part of the overlayed image? I've tried using some examples using MKPolyLines but to no avail. Should I create an invisible (to the user) polyline using the cutout's location data and check for that? Seems like there should be a way to catch the overlay more efficiently, no?

mkmapview image overlay zooming Memory issue in ios

When I am adding a imageOverlay with high resolution image and map zooms image in the map gone and got memory issues.some times my app crashes. How can this be solved?
Here is my code
-(void)addOverlay
{
MapOverlay *overlay = [[MapOverlay alloc] initWithRouteOverlay:self.routeOverlayObj];
[self.mapView addOverlay:overlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if([overlay isKindOfClass:[MapOverlay class]])
{
mapOverlay = (MapOverlay *)overlay;
NSLog(#"%# %#",routeInfoObj.routeOverlay,[UIImage imageNamed:routeInfoObj.routeOverlay]);
ATTMapOverLayRender *mapOverlayRender = [[ATTMapOverLayRender alloc] initWithOverlay:mapOverlay overlayImage:[UIImage imageNamed:routeInfoObj.routeOverlay] andImageFile:[NSString stringWithFormat:#"%#.png",routeInfoObj.routeOverlay]];
return mapOverlayRender;
}
else
{
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:routePolyline];
routeRenderer.strokeColor = [UIColor redColor];
routeRenderer.fillColor = [UIColor redColor];
routeRenderer.lineWidth = 5;
return routeRenderer;
}
return nil;
}
and in "ATTMApOVerlayRender.h"
#interface ATTMapOverLayRender : MKOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage andImageFile:(NSString *)file;
#property (nonatomic, weak) UIImage *overlayImage;
#end
"ATTMApOVerlayRender.h"
#import "ATTMapOverLayRender.h"
#implementation ATTMapOverLayRender
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage andImageFile:(NSString *)file {
self = [super initWithOverlay:overlay];
if (self) {
self.overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef image = _overlayImage.CGImage;
MKMapRect overlayMapRect = [self.overlay boundingMapRect];
CGRect overlayRect = [self rectForMapRect:overlayMapRect];
// draw image
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -overlayRect.size.height);
CGContextDrawImage(context, overlayRect, image);
}
#end
I'm running into similar problems on a tile overlay project as well.
I was able to significantly improve the memory usage by maintaining a single MKMapOverlayRenderer.
Rather than allocating memory for a new MKOverlayRenderer (or MKPolylineRenderer) every time the mapView: renderForOverlay: method is called, create a class variable and rewrite to it.
So in your ViewController.h or whatever class contains your mapView that calls -(MKOverlayRenderer*)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay have,
#property (nonatomic, strong) MKOverlayRenderer *renderer;
And in the declaration of -(MKOverlayRenderer*)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay
use
self.renderer = [[MKOverlayRenderer alloc] init...

CGRect Center for Ipad

I am creating an image frame using CGRect. I want to center the rectangle that is created.
I've looked on here, as well as in the Apple documentation for the best way to do this, and found CGRectGetMidY and CGRectGetMidX which get the center coordinates.
When I try implementing this into my own code I run into problems. I get a Property size not found on object of type UIIMageView error
#import "MyViewController.h"
#interface MyViewController ()
#end
#implementation MyViewController
#synthesize mySignatureImage;
#synthesize lastContactPoint1, lastContactPoint2, currentPoint;
#synthesize imageFrame;
#synthesize fingerMoved;
#synthesize navbarHeight;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
CGRect mySignatureImageFrame = CGRectMake(
CGRectGetMidX(self.view.frame) - (mySignatureImage.size.width/ 2.0),
CGRectGetMidY(self.view.frame) - (mySignatureImage.size.height / 2.0),
image.size.width,
image.size.height);
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController <UIAlertViewDelegate>
#property (nonatomic, strong) UIImageView *mySignatureImage;
#property (nonatomic, assign) CGPoint lastContactPoint1, lastContactPoint2, currentPoint;
#property (nonatomic, assign) CGRect imageFrame;
#property (nonatomic, assign) BOOL fingerMoved;
#property (nonatomic, assign) float navbarHeight;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
Assuming image is of type UIImage then:
CGRect imageFrame = CGRectMake(
CGRectGetMidX(self.view.frame) - (image.size.width / 2.0),
CGRectGetMidY(self.view.frame) - (image.size.height / 2.0),
image.size.width,
image.size.height);
Assuming imageView is of type UIImageView then:
CGRect imageFrame = CGRectMake(
CGRectGetMidX(self.view.frame) - CGRectGetMidX(imageView.frame),
CGRectGetMidY(self.view.frame) - CGRectGetMidY(imageView.frame),
CGRectGetWidth(imageView.frame),
CGRectGetHeight(imageView.frame));
You don't need to calculate the centre point, as it's available for a view anyway:
CGRect superviewBounds = superview.bounds;
imageView.center = CGPointMake(CGRectGetMidX(superviewBounds), CGRectGetMidY(superviewBounds));
- (void)viewDidAppear:(BOOL)animated {
img.center = CGPointMake(CGRectGetMidX([self.view bounds]), CGRectGetMidY([self.view bounds]));
}
/*write code in viewDidApper */
CGPoint (^CGRectGetCenter)(CGRect) = ^(CGRect rect)
{
return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
};
example : The above answer by Mirant
let center = CGPoint(x: rect.midX, y: rect.midY)

drawRect: inside UIView category

I'm trying to do a UIView category for drawing inside drawRect: method without subclassing. To do this, I created a block to simplify this task.
Here's the code:
UIView+DrawRectBlock.h
#import <UIKit/UIKit.h>
// DrawRect block
typedef void(^DrawRectBlock)(UIView *drawRectView, CGRect rect);
#interface UIView (DrawRectBlock)
- (void)drawInside:(DrawRectBlock)block;
#end
UIView+DrawRectBlock.m
#import "UIView+DrawRectBlock.h"
#import <objc/runtime.h>
#interface UIView ()
#pragma mark - Private properties
#property DrawRectBlock drawBlock;
#end
#implementation UIView (DrawRectBlock)
- (void)drawInside:(DrawRectBlock)block {
if ((self.drawBlock = [block copy])) {
[self setNeedsDisplay];
}
}
- (void)drawRect:(CGRect)rect {
if (self.drawBlock) {
self.drawBlock(self, rect);
}
}
- (void)dealloc {
self.drawBlock = nil;
}
#pragma mark - Others
- (void)setDrawBlock:(DrawRectBlock)drawBlock {
objc_setAssociatedObject(self, #"block", drawBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (DrawRectBlock)drawBlock {
return objc_getAssociatedObject(self, #"block");
}
#end
Finally, I call block as follows:
[_testView drawInside:^(UIView *drawRectView, CGRect rect) {
NSLog(#"DrawReeeeeeect!!!!");
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, 5.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, 0.0); //start at this point
CGContextAddLineToPoint(context, 100.0, 100.0); //draw to this point
CGContextStrokePath(context);
}];
But "drawRect:" is never called.
Any idea?
Thanks!!
Finally I made a mix of subclass and category and works great!
https://github.com/mhergon/SimpleBlockDrawing

Resources