MkMapView cancel loading google tiles - ios

I have a case where I need to import an overlay map in top of MkMapView.
The overlay totally covers the google tiles below so there is no need loading, plus it adds overhead to the app.
Is there a way to tell mkMapView to stop loading tiles?

Actually there are 2 ways to implement the real "Hide Google tiles" method (johndope solution only puts an overlay on top of it but doesn't prevent the tiles from loading).
Beware that option one described below might get your application rejected while option 2 will not but is a bit more complex.
Common Part: Retrieve the MKMapTileView object
Inside each MKMapView lies an undocumented class of type: MKMapTileView. Retrieving it is NOT a reason for rejection. In this code the MKMapView instance will be called mapView
UIView* scrollview = [[[[mapView subviews] objectAtIndex:0] subviews] objectAtIndex:0];
UIView* mkTiles = [[scrollview subviews] objectAtIndex:0]; // <- MKMapTileView instance
Option 1: Undocumented Method (!! can be a reason for rejection !! )
if ( [mkTiles respondsToSelector:#selector(setDrawingEnabled:)])
[mkTiles performSelector:#selector(setDrawingEnabled:) withObject:(id)NO];
This will prevent the undocumented method setDrawingEnabled to be called on the MKMapTileView instance.
Option 2: Method Swizzling
Outside of your controller implementation you will write someting like:
// Import runtime.h to unleash the power of objective C
#import <objc/runtime.h>
// this will hold the old drawLayer:inContext: implementation
static void (*_origDrawLayerInContext)(id, SEL, CALayer*, CGContextRef);
// this will override the drawLayer:inContext: method
static void OverrideDrawLayerInContext(UIView *self, SEL _cmd, CALayer *layer, CGContextRef context)
{
// uncommenting this next line will still perform the old behavior
//_origDrawLayerInContext(self, _cmd, layer, context);
// change colors if needed so that you don't have a black background
layer.backgroundColor = RGB(35, 160, 211).CGColor;
CGContextSetRGBFillColor(context, 35/255.0f, 160/255.0f, 211/255.0f, 1.0f);
CGContextFillRect(context, layer.bounds);
}
And somewhere in your code (once your map view is loaded!) :
// Retrieve original method object
Method origMethod = class_getInstanceMethod([mkTiles class],
#selector(drawLayer:inContext:));
// from this method, retrieve its implementation (actual work done)
_origDrawLayerInContext = (void *)method_getImplementation(origMethod);
// override this method with the one you created
if(!class_addMethod([mkTiles class],
#selector(drawLayer:inContext:),
(IMP)OverrideDrawLayerInContext,
method_getTypeEncoding(origMethod)))
{
method_setImplementation(origMethod, (IMP)OverrideDrawLayerInContext);
}
Hope this helps anyone, this code was originally described in this blog post.

As far as I know you can't prevent MKMapView from loading Google Maps tiles, and there's a chance your app will be rejected if it covers up the Google logo while displaying an MKMapView – you may want to consider writing a custom UIScrollView to display your map instead.

I encountered a related problem but in my case my overlay didn't cover all the google tiles.
If anyone has this problem, and is trying to stop loading the google tiles, I managed to superimpose one gray tile(256x256) overlay over the google map tiles.
To do this, the top level tile must be
/FakeTiles/1/1/0.png and add this directory to resources to project.
(N.B. don't drag this into project > Add files > Folders > Create folder references for any folders)
//hack to overlay grey tiles
NSString *fakeTileDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"FakeTiles"];
TileOverlay *greyOverlay = [[TileOverlay alloc] initWithTileDirectory:fakeTileDirectory];
[mapView addOverlay:greyOverlay];
[greyOverlay release];
then add your custom tile overlay.
Then you need this code to scale the grey tile
Calculating tiles to display in a MapRect when "over-zoomed" beyond the overlay tile set

Related

Cropping/zooming not working while setting iOS Wallpaper using PhotoLibrary private framework

I have managed (with the help of this post) to open up a PLStaticWallpaperImageViewController from the PhotoLibrary private framework, which allows the direct setting of the wallpaper and lock screen (using same UI as the Photos app). Unfortunately, the image cropping/zooming features don't seem to work, as touches to the image view itself don't seem to be coming through (the main view is also not dismissed properly after the cancel/set buttons are touched, but this isn't so important).
I have an Xcode project demonstrating the wallpaper setting (can be run in simulator as well as a non-jailbroken device):
https://github.com/newenglander/WallpaperTest/
The code is quite basic, and involves a ViewController inheriting from PLStaticWallpaperImageViewController and implementing an init method similar to the following:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [self initWithUIImage:[UIImage imageWithContentsOfFile:#"/System/Library/WidgetResources /ibutton/white_i#2x.png"]];
self.allowsEditing = YES;
self.saveWallpaperData = YES;
return self;
}
(It will be necessary to allow access to the photo library after the first launch, and for some reason the popup for this comes up behind the app, rather than on top.)
Perhaps someone has insight as to why the cropping/zooming isn't working, or can give me an alternative way to set the wallpaper in an app (destined for Cydia rather than the App Store of course)?
Use this sample project, working very well.
Have inside camera control and custom layout, crop image when taken or after chose from your library, i used for my project and in very simple to customize.
https://github.com/yuvirajsinh/YCameraView
//---------- Answer improved----------//
I take a look on your project and i see 2 problem:
here you have 3 warning of semantic issue:
- (id)initWithUIImage:(id)arg1 cropRect:(struct CGRect { struct CGPoint { float x_1_1_1; float x_1_1_2; } x1; struct CGSize { float x_2_1_1; float x_2_1_2; } x2; })arg2;
in your ViewController.m you setting to get the image from where?
- (id)initWithCoder:(NSCoder *)aDecoder
{
// black_i
//what directory is this?
self = [self initWithUIImage:[UIImage imageWithContentsOfFile:#"/System/Library/WidgetResources/ibutton/white_i#2x.png"]];
//--------------------
self.allowsEditing = YES;
self.saveWallpaperData = YES;
return self;
}
i try to remove your
- (id)initWithUIImage:(id)arg1 cropRect:(struct CGRect { struct CGPoint { float x_1_1_1; float x_1_1_2; } x1; struct CGSize { float x_2_1_1; float x_2_1_2; } x2; })arg2;
change IMG directory in to:
self = [self initWithUIImage:[UIImage imageNamed:#"myImage.png"]];
and all working well but can't crop image, with my git hub YCameraView you have first understand how it work CROPPING function if you want to use crop or more simple, you have to create a fullScreen UICameraPicker allow user to get from camera or from library and allow the editing in cameraPicker then you can load a new picture in your View like this
self = [self initWithUIImage:[UIImage imageNamed:imageSelected.image]];
for a dismiss view, you can't because is a full app allow user to setUp background wallpaper and you can't terminate the app to see a SpringBoard, you have to create first view > picker > detail view with settings for a Home and LockScreen > then dismiss and come back to a first view.
PS: I think in your project to enable editing direct in a view you have to improve your code with a pinch and pan gesture on the UIView
Hope this help you!

Any method to get layer's parent view?

Yes, you read it right "layer's parent view". I'm not sure if its the right term to use but what I mean is, I have a layer added as sublayer of a view. I wanted to know if there is any way to get the view from the layer.
This question is quite old, but accessing CALayer's parent view is easy as:
layer.delegate
If you look into a debugger, you'll see that the delegate property is populated with the UIView containing the Layer, and if not, you can recursively check until you get the main CALayer directly hosted in the view.
Source: https://developer.apple.com/documentation/quartzcore/calayer/1410984-delegate
You can perform this using KVC.
UIView *View1=[UIView new];
View1.tag=1;
[View1.layer setValue:View1 forKey:#"LayerObject"];
UIView *View2=[UIView new];
View2.tag=2;
[View2.layer setValue:View2 forKey:#"LayerObject"];
NSLog(#"Your Layers superView = %#",[View2.layer.superlayer valueForKey:#"LayerObject"]);
This will return your layer's parent View.
OK, so if you have a commonly-used CALayer-subclass and you need to "call into the view" then it looks to me like that view will need to conform to a protocol in order for this to work correctly.
In that case you will need to store a reference to the view within the layer using KVC:
[layer setValue:view forKey:MyViewKey];
Where MyViewKey can be declared as part of the CALayer-subclass code:
extern NSString * const MyViewKey;
and will be defined something like:
NSString * const MyViewKey = #"Hello Mum";

iOS creating PDF from UIViews

I am currently creating PDF documents from a UIView in iOS by using CALayer and the renderInContext method.
The problem I am facing is the sharpness of labels. I have created a UILabel subclass that overrides drawLayer like so:
/** Overriding this CALayer delegate method is the magic that allows us to draw a vector version of the label into the layer instead of the default unscalable ugly bitmap */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
BOOL isPDF = !CGRectIsEmpty(UIGraphicsGetPDFContextBounds());
if (!layer.shouldRasterize && isPDF)
[self drawRect:self.bounds]; // draw unrasterized
else
[super drawLayer:layer inContext:ctx];
}
This method lets me draw nice crisp text, however, the problem is with other views that I don't have control over. Is there any method that would allow me to do something similar for labels embedded in UITableView or UIButton. I guess I'm looking for a way to iterate through the view stack and do something to let me draw sharper text.
Here is an example:
This text renders nicely (my custom UILabel subclass)
The text in a standard segmented control isn't as sharp:
Edit: I am getting the context to draw into my PDF as follows:
UIGraphicsBeginPDFContextToData(self.pdfData, CGRectZero, nil);
pdfContext = UIGraphicsGetCurrentContext();
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
[view.layer renderInContext:pdfContext];
I ended up traversing the view hierarchy and setting every UILabel to my custom subclass that overrides drawLayer.
Here is how I traverse the views:
+(void) dumpView:(UIView*) aView indent:(NSString*) indent {
if (aView) {
NSLog(#"%#%#", indent, aView); // dump this view
if ([aView isKindOfClass:[UILabel class]])
[AFGPDFDocument setClassForLabel:aView];
if (aView.subviews.count > 0) {
NSString* subIndent = [[NSString alloc] initWithFormat:#"%#%#",
indent, ([indent length]/2)%2==0 ? #"| " : #": "];
for (UIView* aSubview in aView.subviews)
[AFGPDFDocument dumpView:aSubview indent:subIndent];
}
}
}
And how I change the class:
+(void) setClassForLabel: (UIView*) label {
static Class myFancyObjectClass;
myFancyObjectClass = objc_getClass("UIPDFLabel");
object_setClass(label, myFancyObjectClass);
}
The comparison:
Old:
New:
Not sure if there is a better way to do this, but it seems to work for my purposes.
EDIT: Found a more generic way to do this that doesn't involve changing the class or traversing through the whole view hierarchy. I am using method swizzling. This method also lets you do cool things like surrounding every view with a border if you want. First I created a category UIView+PDF with my custom implementation of the drawLayer method, then in the load method I use the following:
// The "+ load" method is called once, very early in the application life-cycle.
// It's called even before the "main" function is called. Beware: there's no
// autorelease pool at this point, so avoid Objective-C calls.
Method original, swizzle;
// Get the "- (void) drawLayer:inContext:" method.
original = class_getInstanceMethod(self, #selector(drawLayer:inContext:));
// Get the "- (void)swizzled_drawLayer:inContext:" method.
swizzle = class_getInstanceMethod(self, #selector(swizzled_drawLayer:inContext:));
// Swap their implementations.
method_exchangeImplementations(original, swizzle);
Worked from the example here: http://darkdust.net/writings/objective-c/method-swizzling

new created UIImageViews do not show up when added as subview

upon a tap, I want to let a few UIImageView objects appear on an underlaying UIView.
So I created the following action:
- (IBAction)startStars: (id) sender
{
UIView* that = (UIView*) sender; // an UIButton, invisible, but reacting to Touch Down events
int tag = that.tag;
UIView* page = [self getViewByTag:mPages index:tag]; // getting a page currently being viewed
if ( page != nil )
{
int i;
UIImage* image = [UIImage imageNamed:#"some.png"];
for ( i = 0 ; i < 10 ; ++i )
{
// create a new UIImageView at the position of the tapped UIView
UIImageView* zap = [[UIImageView alloc] initWithFrame:that.frame];
// assigning the UIImage
zap.image = image;
// make a modification to the position so we can see all instances
CGPoint start = that.layer.frame.origin;
start.x += i*20;
zap.layer.position = start;
[page addSubview:zap]; // add to the UIView
[zap setNeedsDisplay]; // please please redraw
[zap release]; // release, since page will retain zap
}
[image release];
}
}
Unfortunately, nothing shows up. The code gets called, the objects created, the image is loaded, even the properties are as expected.
Page itself is a real basic UIView, created with interface builder to contain other views and controls.
Still, nothing of this can be seen....
Has anyone an idea what I am doing wrong? Do I need to set the alpha property (or others)?
Thanks
Zuppa
A couple of things I would check:
Logging to make sure this section of code is actually being called.
Use the designated initializer for UIImageView:
[[UIImageView alloc] initWithImage:image];
This will ensure that your new view has the correct size for the image - what are the relative sizes of zap and your image? It could be out of the frame.
Ensure that the image actually exists and is created
Try not adjusting the layer properties, but setting the center of the image view instead. In fact, in the first instance don't adjust it at all and just see if you can see anything. I'm not sure but I think position might be moving the layer within the view so could be moving your image out of sight. Try:
CGPoint newCenter = that.frame.origin;
newCenter.y += zap.bounds.size.height/2;
newCenter.x += i*20;
zap.center = origin;
setNeedsDisplay is not required. Obviously from your comments it was an act of desparation!
Is your UIImage nil?
You don't need to have the .png extension for imageNamed: to work. It might not even work correctly if you put it in, I'm not sure. You're also overreleasing your image. imageNamed: returns an autoreleased image so there is no reason to call release on the image unless you're also calling retain on it somewhere.
I see a potential error: on second invocation you will re-add another copy, so take care about removing subviews before adding anew copy. Yu can alternatively move a previous view.
99% of my cases about non-visible views with images are wrong names, so as suggested, load using a temp var:
UIImage img = [UIImage imageNamed..];
and test img.

core-plot adding UITable

i am still very new to objective c and in fact this is my first attempt to build an app so please bear with me...
I am trying to add an UITable beside core-plot graph, i have taken CPTestApp example and stated to work off that, i was able to get the graph part working ok but i am having trouble with UITable. Below is the screenshot of how it look at the moment.UITable is upside down and the text is all mirrored..
below is rotation part, can someone point me with an example for UITable rotation together with graph...UITable is populated with an array of values and that is working ok too..
i probably need some guidance to figure out the correct way to add UItable to the coreplothosting view layer
Thanks
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(fromInterfaceOrientation))
{
// Move the plots into place for portrait
scatterPlotView.frame = CGRectMake(20.0f, 55.0f, 728.0f, 556.0f);
tblSimpleTable.frame = CGRectMake(20.0f, 644.0f, 728.0f, 340.0f);
[tblSimpleTable reloadData];
}
else
{
// Move the plots into place for landscape
scatterPlotView.frame = CGRectMake(20.0f, 55.0f, 858.0f, 677.0f);
tblSimpleTable.frame = CGRectMake(878.0f, 51.0f, 220.0f, 677.0f);
[tblSimpleTable reloadData];
}
}
Core Plot applies a flip transform to all of its Core Animation layers so that the drawing code can be shared between iOS and MacOS. This is what you're seeing.
Make sure your UITable and graph hosting view are siblings (i.e., have a common parent view) and one is not a subview of the other.

Resources