Changing Color/Alpha/Filter to MKMapView iOS 6 - iphone

Is there a way to apply CI Filters to MKMapViews? Or something similar? I'm trying to not have my map based app looks so beige. Is there way to apply RGBA filters?
Any help/tutorials direction appreciated. I see nothing in the native documentation that talks about changing look for MKMapView.

I don't think you can change the imagery before it is rendered to the screen. However, you can use an MKOverlayView over the entire world that achieves the same effect. The following should work, but treat it like pseudocode just to get you started.
#interface MapTileOverlay : NSObject <MKOverlay>
#end
#implementation MapTileOverlay
-(id)init {
self = [super init];
if(self) {
boundingMapRect = MKMapRectWorld;
coordinate = MKCoordinateForMapPoint(MKMapPointMake(boundingMapRect.origin.x + boundingMapRect.size.width/2, boundingMapRect.origin.y + boundingMapRect.size.height/2));
}
return self;
}
#end
#interface MapTileOverlayView : MKOverlayView
#end
#implementation MapTileOverlayView
-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGContextSetBlendMode(context, kCGBlendModeMultiply); //check docs for other blend modes
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5); //use whatever color to mute the beige
CGContextFillRect(context, [self rectForMapRect:mapRect]);
}
#end
You need to have some class that implements the MKMapViewDelegate protocol to create the view...
#interface MapViewDelegate : NSObject<MKMapViewDelegate>
#end
#implementation MapViewDelegate
-(MKOverlayView*)mapView:(MKMapView*)mapView viewForOverlay:(id<MKOverlay>)overlay {
if([overlay isKindOfClass:[MapTileOverlay class]]) {
return [[MapTileOverlayView alloc] initWithOverlay:overlay];
}
return nil;
}
Finally, after you initialize your map, you need to set the delegate on the map and add the overlay...you must set the delegate before you add the overlay...
MapViewDelegate* delegate = [[MapViewDelegate alloc] init]; //you need to make this an iVar somewhere
[map setDelegate:delegate];
[map addOverlay:[[MapTileOverlay alloc] init]];

You could add a view on top of the map view,
nearly transparent with a slight color (e.g blueish to compensate that brown.)

Related

Quartz 2D MVC Drawing

all. I'm trying to follow a tutorial on making a ball bounce around the screen of an iPhone. The tutorial constructs the application in a MVC scheme. I'm having trouble wrapping my head around this concept when it comes to the drawRect method in the View implementation.
This is my Model header file:
#import <Foundation/Foundation.h>
#import "TestView.h"
#define BALL_SIZE 20.0
#define VIEW_WIDTH 320.0
#define VIEW_HEIGHT 460.0
#interface TestModel : NSObject
{
TestView* ball;
CGPoint ballVelocity;
CGFloat lastTime;
CGFloat timeDelta;
}
- (void) updateModelWithTime:(CFTimeInterval) timestamp;
- (void) checkCollisionWithScreenEdges;
#property (readonly) TestView* ball;
#end
The tutorial instructs me the user to override the init method of NSObject. I've also included the methods for controlling the "animation" logic:
- (id) init {
self = [super init];
if (self) {
ball = [[TestView alloc] initWithFrame: CGRectMake(0.0, 0.0, BALL_SIZE, BALL_SIZE)];
// Set the initial velocity for the ball
ballVelocity = CGPointMake(200.0, -200.0);
// Initialize the last time
lastTime = 0.0;
}
return self;
}
- (void) checkCollisionWithScreenEdges {
// Left Edge
if (ball.frame.origin.x <= 0) {
ballVelocity.x = abs(ballVelocity.x);
}
// Right Edge
if (ball.frame.origin.x >= VIEW_WIDTH - BALL_SIZE) {
ballVelocity.x = -1 * abs(ballVelocity.x);
}
// Top Edge
if (ball.frame.origin.y <= 0) {
ballVelocity.y = abs(ballVelocity.y);
}
// Bottom Edge
if (ball.frame.origin.y >= VIEW_HEIGHT - BALL_SIZE) {
ballVelocity.y = -1 * abs(ballVelocity.y);
}
}
- (void) updateModelWithTime:(CFTimeInterval) timestamp {
if (lastTime == 0.0) {
// initialize lastTime if first time through
lastTime = timestamp;
} else {
// Calculate time elapsed since last call
timeDelta = timestamp - lastTime;
// Update the lastTime
lastTime = timestamp;
[self checkCollisionWithScreenEdges];
// Calculate the new position of the ball
CGFloat x = ball.frame.origin.x + ballVelocity.x * timeDelta;
CGFloat y = ball.frame.origin.y + ballVelocity.y * timeDelta;
ball.frame = CGRectMake(x, y, BALL_SIZE, BALL_SIZE);
}
}
The View implementation file is the following:
#import "TestView.h"
#implementation TestView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect) rect {
}
#end
Finally, my View Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
gameModel = [[TestModel alloc] init];
[self.view addSubview:gameModel.ball];
// Set up the CADisplayLink for the animation
gameTimer = [CADisplayLink displayLinkWithTarget:self selector:#selector(updateDisplay:)];
// Add the display link to the current run loop
[gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void) updateDisplay:(CADisplayLink *) sender {
[gameModel updateModelWithTime:sender.timestamp];
}
OK, so now that I've provided a look at the structure of the code (hopefully I've given enough) I can get to my question. So when I add anything to drawRect a new object is drawn and does not get "animated" by the model logic methods.
Right now I have a bouncing square. When I try to fill the square with an ellipse in drawRect, I get a new object, drawn how I want, that just sits at 0,0 while the bouncing square is still active.
I'm sure I'm missing something really big here, but I've been banging my head against the wall for hours and can't figure it out. Any help would be greatly appreciated!
A couple of things here:
1- Have you overriden the view class in SB to TestView?
2- Looking at your code, I do not see how your model is connected to your View through your controller. Recall from the MVC model, that the Controller is on top and talks down (pyramid style) to the model and the view and so, somewhere in your view controller:
a) you need to instantiate your model
b) get values from your model and pass them to your view variables - which would be called in drawrect
Last but not least, lookup setNeedsDisplay which is the way to call and refresh the view.
Hope this helps without spoiling the assignment.

how to pass in BOOL value from one view to another in objective c

I am currently working on an app where if the user clicks on a button, it will set that buttonPressed to "YES" and goes to a new view. In this new view, you can select the colors and once the colors are chosen, it will go back to the previous view with its chosen color on the background of the button that was clicked.
I am having trouble accessing the boolean value and getting SIGBART error when I run the code.
What am I doing wrong here guys?
In my ChangeClothesViewController
#property (assign, readwrite) BOOL pantsPressedBool;
#synthesize pantsPressedBool = _pantsPressedBool;
- (IBAction)pantsPressed:(UIButton *)sender {
ChooseColorsViewController *color = [[ChooseColorsViewController alloc] initWithNibName:#"ChooseColorsViewController" bundle:nil];
[self.navigationController pushViewController:color animated:YES];
//AppDelegate *passColors = (AppDelegate *)[[UIApplication sharedApplication]delegate];
//this code above does nothing and is not even needed. I was testing something out and forgot to take it out
_pantsPressedBool = YES;
}
and inside my RectangleView (this is where I make a rectangle behind the button to make the background for the buttons)
- (void)drawRect:(CGRect)rect
{
//custom delegate
AppDelegate *passColors = (AppDelegate *)[[UIApplication sharedApplication]delegate];
changeClothes *whichButton = (changeClothes *)[[UIApplication sharedApplication]delegate];
for (int i=0; i < [passColors.getColors count]; i++) {
if ([[passColors.getColors objectAtIndex:i] isEqualToString: #"Black"]) {
NSLog(#"what button: %c", whichButton.pantsPressedBool); //HERE
if (whichButton.pantsPressedBool == YES ) { //AND HERE is where I get the SIGABRT error
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor blackColor] set];
//CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 0.5); //CGContextRef, Red, Green, Blue, Alpha
rect = CGRectMake(20, 20, 40, 80); //x, y, width, height
CGContextFillRect(context, rect); //CGContextRef, CGRect
}
}
}
}
as always, any help would be greatly appreciated guys.
Thanks in advance.
[EDIT]
so I am trying something different.
- (IBAction)pantsPressed:(UIButton *)sender {
ChooseColorsViewController *color = [[ChooseColorsViewController alloc] initWithNibName:#"ChooseColorsViewController" bundle:nil];
[self.navigationController pushViewController:color animated:YES];
AppDelegate *chosenButton = (AppDelegate *)[[UIApplication sharedApplication]delegate];
chosenButton.pantsButton = YES;
}
so inside my AppDelegate, I have
#property (assign, readwrite) BOOL pantsButton;
#synthesize pantsButton = _pantsButton;
I am trying to set the BOOL variable (pantsButton) inside the AppDelegate to "YES" if that button was clicked and make if statement so
if ([chosenButton.pantsButton == YES]) {
do something
}
You are casting the app delegate to (changeClothes *) when you assign to whichButton but that's not what it is (that is, I assume your app delegate is not a subclass of changeClothes).
This line...
changeClothes *whichButton = (changeClothes *)[[UIApplication sharedApplication]delegate];
...is saying, take the app delegate and pretend that it's a changeClothes object. The problem is that you're lying to the compiler. :-) Later, when the app tries to use the thing you've told it is a changeClothes object...
if (whichButton.pantsPressedBool == YES ) {
...it discovers that the thing you've given it doesn't act the way a changeClothes object is supposed to act (i.e. doesn't know anything about pantsPressedBool).
You are doing some strange things with the AppDelegate passColors and whichButton. In your drawRect you are referring to the pantsPressedBool property of the AppDelegate. Your property is declared in the ChangeClothesViewController however.
You need to reference to the correct object in both your drawRect and your pantsPressed and your function. In this case, it should be your ChangeClothesViewController instance.

GLKView set drawable properties

I'm trying to port Apples GLPaint example to use GLKit. Using a UIView, its possible to return the CAEAGLLayer of the view and set the drawableProperties to include kEAGLDrawablePropertyRetainedBacking. This has the effect of retaining the drawable contents after presenting the render buffer, as expected. Removing this property results in flickering after the draw call with part of the drawable content seemingly being drawn to different buffers.
The problem is this is exactly the issue I am now having in my GLKView, but there doesn't seem to be a way to set the drawable properties. Returning a CAEAGLLayer and setting the properties has no effect and I don't see any relevant properties of GLKView to set retained backing.
Has anybody else come across this or have a solution?
If you want to get kEAGLDrawablePropertyRetainedBacking in a GLKView, add the following category to your project.
#interface CAEAGLLayer (Retained)
#end
#implementation CAEAGLLayer (Retained)
- (NSDictionary*) drawableProperties
{
return #{kEAGLDrawablePropertyRetainedBacking : #(YES)};
}
#end
Setting the drawableProperties on the CAEAGLLayer maintained by the GLKView doesn't work because the GLKView overwrites those properties when it binds its drawable and generates its render storage. Using this method forces the GLKView to use your category's returned drawableProperties instead.
Simeon's answer works but changes the behavior for all EAGL-based views in an application. I have some views which need the backing forced and others which don't, so I came up with a slightly different solution by creating subclasses of GLKView and CEAGLLayer, like this:
#interface RetainedEAGLLayer : CAEAGLLayer
#end
#implementation RetainedEAGLLayer
- (void)setDrawableProperties:(NSDictionary *)drawableProperties {
// Copy the dictionary and add/modify the retained property
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] initWithCapacity:drawableProperties.count + 1];
[drawableProperties enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
// Copy all keys except the retained backing
if (![key isKindOfClass:[NSString class]]
|| ![(NSString *)key isEqualToString:kEAGLDrawablePropertyRetainedBacking])
[mutableDictionary setObject:object forKey:key];
}];
// Add the retained backing setting
[mutableDictionary setObject:#(YES) forKey:kEAGLDrawablePropertyRetainedBacking];
// Continue
[super setDrawableProperties:mutableDictionary];
[mutableDictionary release];
}
#end
and this
#interface RetainedGLKView : GLKView
#end
#implementation RetainedGLKView
+ (Class)layerClass {
return [RetainedEAGLLayer class];
}
#end
Now I can just use RetainedGLKView instead of GLKView for those views where I want to force a retained backing.
Not sure if this will work but here is some code we have:
GLKView * const view = (GLKView *)self.view;
view.context = self.context;
view.delegate = self;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
self.preferredFramesPerSecond = 30;
[EAGLContext setCurrentContext:self.context];
CAEAGLLayer * const eaglLayer = (CAEAGLLayer*) view.layer;
eaglLayer.opaque = YES;
You should be able to access eaglLayer.drawableProperties. Hopefully that lets you set the parameter you want.
In your GLKView implementation file:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
_eaglLayer = (CAEAGLLayer *)self.layer;
_eaglLayer.opaque = TRUE;
_eaglLayer.drawableProperties = #{ kEAGLDrawablePropertyRetainedBacking : [NSNumber numberWithBool:NO],
kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8};
}
return self;
}
I don't know how people manage to make things so complicated; it's like this, and only this.
Hi Please try this one
GLKView * const view = (GLKView *)self.view;
view.context = self.context;
view.delegate = self;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
self.preferredFramesPerSecond = 10;
[EAGLContext setCurrentContext:self.context];
CAEAGLLayer * const eaglLayer = (CAEAGLLayer*) view.layer;

Is - [UIView (MyOwnCategory) drawRect:] never called on 3.1.3?

I define my own my own drawRect method and it is called on 4.2.1 (iOS) 5.0 (iOS) and 4.3.2 (Simulator) sucesfully. But it never called on 3.1.3 (iPhone 2g).
What reason could be for this?
P.S. Since i start write the question i think about my 3.1.3 device is jailbroken. Maybe it is root cause of this strange behaviour.
Upd: To reproduce issue i use next code:
#implementation UIView (MyOwnCategory)
- (void)drawRect:(CGRect)rect
{
const char * function = __FUNCTION__;
[NSException raise: #"hi!" format: #"%s", function];
}
#end
exception never happened on 3.1.3 even when i call [super drawRect: rect] explicitly
I wanted to write about Method Swizzling for a few weeks now, and #Kevin Ballard's comment finally made me do it (thank you for the inspiration, Kevin).
So here's a solution for your problem using method swizzling which should also work on iOS 3.x:
UIView+Border.h:
#import <Foundation/Foundation.h>
#interface UIView(Border)
#end
UIView+Border.m:
#import "UIView+Border.h"
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
#implementation UIView(Border)
- (id)swizzled_initWithFrame:(CGRect)frame
{
// This is the confusing part (article explains this line).
id result = [self swizzled_initWithFrame:frame];
// Safe guard: do we have an UIView (or something that has a layer)?
if ([result respondsToSelector:#selector(layer)]) {
// Get layer for this view.
CALayer *layer = [result layer];
// Set border on layer.
layer.borderWidth = 2;
layer.borderColor = [[UIColor redColor] CGColor];
}
// Return the modified view.
return result;
}
- (id)swizzled_initWithCoder:(NSCoder *)aDecoder
{
// This is the confusing part (article explains this line).
id result = [self swizzled_initWithCoder:aDecoder];
// Safe guard: do we have an UIView (or something that has a layer)?
if ([result respondsToSelector:#selector(layer)]) {
// Get layer for this view.
CALayer *layer = [result layer];
// Set border on layer.
layer.borderWidth = 2;
layer.borderColor = [[UIColor blueColor] CGColor];
}
// Return the modified view.
return result;
}
+ (void)load
{
// 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 "- (id)initWithFrame:" method.
original = class_getInstanceMethod(self, #selector(initWithFrame:));
// Get the "- (id)swizzled_initWithFrame:" method.
swizzle = class_getInstanceMethod(self, #selector(swizzled_initWithFrame:));
// Swap their implementations.
method_exchangeImplementations(original, swizzle);
// Get the "- (id)initWithCoder:" method.
original = class_getInstanceMethod(self, #selector(initWithCoder:));
// Get the "- (id)swizzled_initWithCoder:" method.
swizzle = class_getInstanceMethod(self, #selector(swizzled_initWithCoder:));
// Swap their implementations.
method_exchangeImplementations(original, swizzle);
}
#end

Few questions on iphone memory management and cocos2d

I'm working on my first app and have a few questions on memory management.
First Question:
I'm working on an intro scene that looks like this
#import "Intro_Scene.h"
#import "Main_Menu.h"
#import "Label.h"
#implementation Intro_Scene
#synthesize logo,label;
-(id) init
{
self = [super init];
if(self != nil)
{
//Load logo image and set position
logo = [Sprite spriteWithFile:#"AVlogo_1.png"];
logo.position = ccp(-50, 0);
logo.scale = 1.8f;
[self addChild: logo];
//Creates 3 actions for the logo sprite
id action0 = [MoveTo actionWithDuration:0 position:ccp(160,270)];
id action1 = [FadeIn actionWithDuration:3];
id action2 = [FadeOut actionWithDuration:3];
//Logo runs the actions
[logo runAction: [Sequence actions:action0,action1, action2, nil]];
//Schedules the changeScene method to switch scenes to main menu within 6 seconds of loading.
[self schedule: #selector(changeScene) interval:6.0f];
//Creates a label and positions it, Alternative Visuals
label = [Label labelWithString:#"Alternative Visuals" fontName:#"Verdana" fontSize:22];
label.position = ccp(160, 120);
[self addChild:label];
}
return self;
}
//Method called after intro has run its actions, after 6 seconds it switches scenes.
-(void)changeScene
{
[self removeChild:logo cleanup:YES];
[self removeChild:label cleanup:YES];
Main_Menu *mainMenu = [Main_Menu node];
[[Director sharedDirector] replaceScene: mainMenu];
}
-(void)dealloc
{
[[TextureMgr sharedTextureMgr] removeUnusedTextures];
[label release];
[logo release];
[super dealloc];
}
#end
Have I released everything correctly, and avoided leaks? I ran it in instruments multiple times and it found no leaks and used about 2mb of memory, is that to much or the amount to be expected? Also does the dealloc method get called when the scene is replaced?
Question 2:
My main menu is set up like this
#import "Main_Menu.h"
#import "Sprite.h"
#import "cocos2d.h"
#implementation Main_Menu
#synthesize background, controlLayer;
-(id) init
{
self = [super init];
if(self != nil)
{
//Create the default background for main menu not including directional pad and highlight box
background = [Sprite spriteWithFile:#"Main_Menu_bg.png"];
background.position = ccp(160,240);
[self addChild:background];
//Adds the control later class to the main menu, control layer class displays and controls the directional pad and selector.
ControlLayer *layer = [[ControlLayer alloc] init];
self.controlLayer = layer;
[layer release];
[self addChild: controlLayer];
}
return self;
}
-(void) dealloc
{
[seld removeChild:background cleanup:YES];
[[TextureMgr sharedTextureMgr] removeUnusedTextures];
[background release];
[controlLayer release];
[super dealloc];
}
#end
Once again am I doing everything correctly? The layer ControlLayer I'm adding to this scene contains a directional pad sprite that the user uses to navigate the menu. In instruments It also confirms that their is no memory leaks, and it uses 4.79 mb of memory. Once again is that a reasonable amount? I will most likely switch to using AtlasSprite and AtlastSpriteManager to conserve memory.
I'm new to cocos2d, so if you see I'm doing anything wrong point it out! I'd rather fix bad habits in the early stages. And if you have any future tips for memory management please share.
Don't release logo, label, or background. You didn't alloc/copy/new/retain them, so you don't own them and must not release them.
I assume the controllerLayer property has the retain attribute? If not, you probably mean to do so.
In general I'd suggest two things going forward.
Read and understand the Cocoa Memory Management Fundamentals
Run the Clang analyzer on your code. This is available in Xcode 3.2 via Build->Build and Analyze. It will help detect these memory issues.
Also check out this SO question.