drawRect not called on MKPinAnnotationView subclass - mapkit

I implemented a class that extends MKPinAnnotationView. I want to draw something below the pin, which I hope to achieve by taking over the drawRect:rect message. I want to do this by painting something myself first and then chaining to the superclass.
The problem is that this message doesn't event get sent. I already tried setting the frame size to something not empty or nil (the classic cause) without any effect. Could the implementation of the MKPinAnnotationView somehow cause the drawRect:rect message to not be sent to subclasses?
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface QueryAnnotationView : MKPinAnnotationView {
}
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;
#end
Implementation :
#import "QueryAnnotationView.h"
#implementation QueryAnnotationView
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self)
{
self.frame = CGRectMake(0, 0, 65, 100);
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"drawing my own stuff..");
[super drawRect:rect];
}
#end

Try this:
in your (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
add this two lines at the end of if (self) block:
self.backgroundColor = any color but clear color (e.g. redColor)
self.backgroundColor = [UIColor clearColor];
This works on my code, but I don't know why.
Also, you can try this:
- (void)setAnnotation:(id <MKAnnotation>)annotation
{
[super setAnnotation:annotation];
[self setNeedsDisplay];
}

Related

Remove Edit Button from moreNavigationController dont work

i get some problem by removing the Edit Button from the moreNavigationController.
I cant find the mistake, it must be a simple one.
I create some TabBarViewController connect it in the IB with my TabBarViewController.
Here is the Code:
TabBarViewController.h:
#import <UIKit/UIKit.h>
#interface TabBarViewController : UITabBarController <UINavigationControllerDelegate, UITabBarControllerDelegate>
#end
TabBarViewController.m:
#import "TabBarViewController.h"
#interface TabBarViewController ()
#end
#implementation TabBarViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.delegate = self;
[self.moreNavigationController.navigationBar setBarStyle:UIBarStyleBlackOpaque];
[self.moreNavigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"navbar.bg.png"] forBarMetrics:UIBarMetricsDefault];
[self.moreNavigationController.navigationBar.topItem setRightBarButtonItem:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The Edit Button is stil there :/
You need to set the navigationController delegate to your tabBarController. Add the following line in your viewDidLoad method of your TabBarViewController class
self.moreNavigationController.delegate = self;
use the delegate method of UINavigationController navigationController:willShowViewController:animated: to hide the barButtonItem
Use the following code
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
navigationController.navigationBar.topItem.rightBarButtonItem = Nil;
}
This should work, it worked for me.
There is a more pretty solution:
tabBarController.customizableViewControllers = [];
Prasad Devadiga Thanks man!
In my TabBarViewController.m
#import "TabBarViewController.h"
#interface TabBarViewController ()
#end
#implementation TabBarViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.moreNavigationController.delegate = self;
navigationController:willShowViewController:animated:YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
navigationController.navigationBar.topItem.rightBarButtonItem = Nil;
}
#end
In my TabBarViewController.h
I insert this codes
#import <UIKit/UIKit.h>
#interface TabBarViewController : UITabBarController <UINavigationControllerDelegate, UITabBarControllerDelegate>
#end
This is working on IOS7
After reading all of the above and converting it to Swift 3 I noticed that when one of the view controllers which was shown after selecting the More... tab was a navigationcontroller and had a rightBarButton item, that item was removed as well! Since that is not desired, I came up with the following solution:
//
// CustomizedTabBarController.swift
//
import UIKit
class CustomizedTabBarController: UITabBarController, UINavigationControllerDelegate {
var root : UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
root = self.moreNavigationController.topViewController
// Make sure the icons have the proper tint color
if let view = root?.view {
view.tintColor = UIColor.green
}
self.moreNavigationController.delegate = self
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
// Only hide the rightBarButtonItem when this is the morenavigationcontroller
if( viewController == root ){
navigationController.navigationBar.topItem?.rightBarButtonItem = nil
}
}
}
As an extra I also force the icons shown in the moreNavigationController to be green instead of the standard blue tintcolor since I was using green icons on the tabbar as well.
This worked for me
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
tabBarController.customizableViewControllers?.removeAll()
}

iOS - Create UIView subclass for rounded rectangle

I'm trying to create & use a very simple UIView subclass for a rectangle with rounded corners. I've created a new class as follows :
RoundedRect.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface RoundedRect : UIView
#end
RoundedRect.m
#import "RoundedRect.h"
#implementation RoundedRect
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[[self layer] setCornerRadius:10.0f];
[[self layer] setMasksToBounds:YES];
}
return self;
}
#end
I'm using iOS 5.1 with storyboards and have set the custom class property in the IB inspector window to 'RoundedRect', but when I run the app the rectangle still has square corners. Have I missed something obvious?
Thanks
Jonathan
In iOS 5 and up, there is absolutely no need to subclass - you can do it all from Interface Builder.
Select the UIView you want to modify.
Go to the Identity Inspector.
In "User Defined & Runtime Attributes", add "layer.cornerRadius" in Key Path, Type should be "Number" and whatever setting you require.
Also add 'layer.masksToBounds' as Boolean.
Done! With no subclassing, and all in IB.
The other guys have already answered the question but I would refactor it like this to enable use in nibs and in code
#import "RoundedRect.h"
#implementation RoundedRect
- (id)initWithFrame:(CGRect)frame;
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder;
{
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit;
{
CALayer *layer = self.layer;
layer.cornerRadius = 10.0f;
layer.masksToBounds = YES;
}
#end
The initWithFrame method is not called when the view is instantiated from a XIB file. Instead, the initWithCoder: initializer is called, so you need to perform the same initialization in this method.
For views that are loaded from a NIB file, the designated initializer is initWithCoder:. initWithFame: is not called in this case.
If UIView load from Nib, you should use method
- (void)awakeFromNib

Subclass of UIViewController shows black screen

I created a Subclass of UIViewController in my Project and linked it to a View which is modal-pushed by the "RootViewController". I made absolutely no changes to the derived class, but when the "SecondView" is pushed it turns black every time. If i link that view to the standard UIViewController class everything works fine?
Since the "SecondViewController" is derived from UIViewController I can only guess that the Problem has to do with the alloc/init function but I have no idea where to start.
I can provide the sample code I have in front of me now if necessary.
This is the derived subclass:
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self; }
- (void)loadView {}
- (void)viewDidLoad {
[super viewDidLoad]; }
- (void)viewDidUnload {
[super viewDidUnload];}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait); }
#end
Header:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#end
- (void)loadView
{
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
}
FYI, the comment is automatically generated too.
Change this:
- (void)loadView
{
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
}
To this:
- (void)loadView
{
[super loadView];
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
}
And it will work.
Try this
-(void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
[view setBackgroundColor:[UIColor whiteColor]];
UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(10, 50, 100, 100)];
[label setText:#"HAI"];
[view addSubview:label];
self.view = view;
}
If you are trying to get the view to load before it "shows" up during the segue from IB you might want to try something like this in the destination view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view layoutIfNeeded];
}

Add and control UIImageView Subview from another class

I have two classes: MainViewController and PlayerImageController (NSObject)
How would I be able to add the subview of my UIImageView from PlayerImageController to my MainViewController and dictate actions like
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:[PlayerImageController addPlayerImage]];
}
- (void)somethingHappened
{
[PlayerImageController changePlayerImage];
}
and have my methods in my PlayerImageController class like
+ (UIImageView *) addPlayerImage
{
heroPlayerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"hero-still.png"]];
[heroPlayerImageView setFrame:CGRectMake(151, 200, 17, 23)];
return heroPlayerImageView;
}
+ (void) changePlayerImage
{
//change image
}
Thanks!
I think in your case you should use the Delegate pattern.
Declare:
#protocol PlayerImageUpdater
- createPlayerImage;
- changePlayerImage;
#end
Then add:
#interface PlayerImageController <PlayerImageUpdater>
then add to MainViewController ivar and property like:
#property (...) id<PlayerImageUpdater> playerDelegate;
set this delegate like: mainViewController.playerDelegate = playerImageControllerInstance;
and use in code:
[playerDelegate createPlayerImage];
[playerDelegate changePlayerImage];
On one hand, I would not recommend using class methods but instance methods. This way, you could implement as many instances of your class as you need and keep a reference to your instances to update them.
On the other hand, if the UIImageView is the important attribute of your class, I suggest you implement it as a UIView subclass (if it is not, you can do it as an NSObject subclass as well, and get its UIImageView attribute).
Have a look at the following code:
PlayerImageController.h:
#interface PlayerImageController : UIView{
UIImageView *_heroPlayerImageView;
}
-(void) changePlayerImage;
PlayerImageController.m:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_heroPlayerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"hero-still.png"]];
// x = 0 and y = 0 because its relative to its parent view, the object itself.
[_heroPlayerImageView setFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
[self addSubview:_heroPlayerImageView];
}
return self;
}
MainViewController.h:
#import "PlayerImageController.h"
#interface MainViewController : UIViewController{
PlayerImageController *_player;
}
MainViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
_player = [[PlayerImageController alloc] initWithFrame:CGRect(151, 200, 17, 23)];
[self.view addSubview:_player];
}
- (void)somethingHappened
{
[_player changePlayerImage];
}
I hope it can help you (I haven't actually tried the code above, it could have some syntax errors).
If you are not using ARC, remember to retain and release your variables! Good luck!

setting self of UIView background color

i'm trying to do this from inside the .m of a custom view class that is not being loaded from the XIB, but rather programmatically:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor=[UIColor redcolor];
}
return self;
}
i have the same result whether i put the background color in the initWithFrame or other methods. the background color property doesn't take. from the controller, which owns this custom view, i can set the background color fine, with:
self.mycustomview.backgroundColor=[UIColor redcolor];
But I'd like to do this from within the custom view itself, keep stuff like this independent. both the controller and the custom view import UIKit.
I also tried this, which was available from Code Sense:
self.View.backgroundColor=[UIColor redcolor];
but that doesn't work either. i tried both view and View here. I'm sure I'm overlooking something very obvious.
in the view controller i have this, and it works fine. the custom view is called "mapButtons.h":
- (void)viewDidLoad
{
CGRect frame=CGRectMake(0, 0, 320, 460);
self.mapButtons=[[mapButtons alloc] initWithFrame:frame];
self.mapButtons.backgroundColor=[UIColor redColor];
[self.view addSubview:self.mapButtons];
the .h of the custom view is this:
#import <UIKit/UIKit.h>
#interface mapButtons : UIView
If your view is getting created from a XIB (i.e. you added it to some other view using Interface Builder), -initWithFrame: is not going to get called. An object being loaded from a XIB receives -initWithCoder: instead. Try this:
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if(self)
{
self.backgroundColor = [UIColor redColor];
}
return self;
}
I have tested again and this is the full source for what I am doing that works
// MapButtons.h
#import <UIKit/UIKit.h>
// As a note you normally define class names starting with a capital letter
// but I did test this with mapButtons as you had it
#interface MapButtons : UIView
#end
// MapButtons.m
#import "mapButtons.h"
#implementation mapButtons
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor redColor];
}
return self;
}
#end
// TestAppDelegate.m
#implementation TestAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MapButtons *view = [[MapButtons alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window addSubview:view];
[self.window makeKeyAndVisible];
return YES;
}
The fact that xcode is not auto completing is odd but I seem to have this issue intermittently so I have no real solution. People sometimes suggest deleting the projects derived data and restarting xcode.