Is it possible to use custom view for SKCalloutView? - ios

Is it possible to make a custom UIView, with elements such as Label and Button, and use it as a CalloutView?
What I read through the documentation so far doesn't implicates that it is possible.
Changing left and right button is possible, together with adding custom UIImageView for an arrow, but couldn't figure out if customising entire view is actually possible.

Yes - you just have to override the calloutViewForAnnotation callback. There is an example in the demo project (see inside AnnotationsViewController.m) where you can create a user defined UIView and return that
- (UIView*)mapView:(SKMapView *)mapView calloutViewForAnnotation:(SKAnnotation *)annotation
{
//Custom callouts.
if (annotation.identifier == self.annotation1.identifier)
{
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 50.0f)];
view.backgroundColor = [UIColor purpleColor];
view.alpha = 0.5f;
return view;
}
return nil;// Default callout view will be used.
}

Related

prepareForInterfaceBuilder doesn't update my storyboard

I've created a simple day calendar view and I'd like to see it rendering live on my storyboard, but I've managed to show only the code in -drawRect:.
Running on the simulator I get this image, that represents the correct final result, but in storyboard I get this.
On storyboard I get this
The CalendarDayView is a subclass of a another view whose purpose is to load a nib with a specific name and add it a as a subview. CalendarDayView is tagged as IB_DESIGNABLE.
It is added as a subview directly on the storyboard.
To show also the label inside the CalendarDayView in the -prepareForInterfaceBuilder method I've written some placeholder text.
- (void) prepareForInterfaceBuilder {
[super prepareForInterfaceBuilder];
self.yearLabel.text = #"2015";
self.monthLabel.text = #"FEBRUARY";
self.dayLabel.text = #"28";
}
Draw rect is shown fine
- (void) drawRect:(CGRect)rect {
self.backgroundColor = [UIColor clearColor];
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:20];
[APP_CALENDAR_VIEW_COLOR setFill];
[path fill];
}
How can I achieve to show labels while editing my storyboard? even if I show the preview nothing is shown.

Is UICollectionView.backgroundView broken

I'm writing something relatively simple, or so I thought.
Firstly, the code, for which I'm trying to place an image on the background of the UICollectionView if there are no results returned from my server. The image is 200 by 200:
UIView *myView = [[UIView alloc] initWithFrame:self.view.bounds];
CGRect myViewSpace = self.view.bounds;
CGFloat myX = (myViewSpace.size.width /2.0) - 100;
CGFloat myY = (myViewSpace.size.height /2.0) - 100;
UIImageView *imView = [[UIImageView alloc] initWithFrame:CGRectMake(myX, myY, 200, 200)];
imView.image = [UIImage imageNamed:#"imNotHome"];
[myView addSubview:imView];
myCollectionView.backgroundView = myView;
Once there are results, I want to be able to remove it.
I thought it'd be as simple as placing the following, before I reloaded the UICollectionView:
[myCollectionView.backgroundView removeFromSuperview];
However, it appears to be doing nothing.
Am I missing something?
Thanks in advance!
It should be done this way instead:
myCollectionView.backgroundView = nil;
Explanation: You should unset the UICollectionView's background in the same way as you set it. You didn't set it by manipulating the view hierarchy, but by setting the background property. You did call addSubview in the previous line, but that was to add a subview to your background view, not to add the background view itself.
Edit:
There is a very good article about this UICollectionView bug here:
http://blog.spacemanlabs.com/2013/11/uicollectionviews-backgroundview-property-is-horribly-broken/
The solution the author gives is to reset the background to an empty opaque view:
UIView *blankView = [UIView new];
blankView.backgroundColor = [UIColor whiteColor];
[myCollectionView.backgroundView removeFromSuperview];
myCollectionView.backgroundView = blankView;
Also, the author recommends not using the backgroundView property at all but doing it yourself:
Frankly, I think the best solution is to just ignore the backgroundView property all together. Instead, make the collection view’s background clear, and implement your own backgroundView; just throw a view behind the collection view.

iOS - UIView Always on Front without BringSubviewToFront

Can I have some UIView which will always appear on top in iOS?
There are lots of addSubview in my project but I need to have one small view which will always appear. SO is there any other option than
[self.view bringSubViewToFront:myView];
Thanks
One more option (especially if you want to overlap several screens, with logo for example) - separate UIWindow. Use windowLevel to set the level of new window.
UILabel *devLabel = [UILabel new];
devLabel.text = #" DEV ";
devLabel.font = [UIFont systemFontOfSize:10];
devLabel.textColor = [UIColor grayColor];
[devLabel sizeToFit];
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
static UIWindow *notificationWindow;
notificationWindow = [[UIWindow alloc] initWithFrame:
CGRectMake(screenSize.width - devLabel.width, screenSize.height - devLabel.height,
devLabel.width, devLabel.height)];
notificationWindow.backgroundColor = [UIColor clearColor];
notificationWindow.userInteractionEnabled = NO;
notificationWindow.windowLevel = UIWindowLevelStatusBar;
notificationWindow.rootViewController = [UIViewController new];
[notificationWindow.rootViewController.view addSubview:devLabel];
notificationWindow.hidden = NO;
Another option is set layer.zPosition of your UIView.
You need to add
#import <QuartzCore/QuartzCore.h>
Framework to your .m file.
And set such like
myCustomView.layer.zPosition = 101;// set maximum value as per your requirement.
For more information about layer.zPosition read this documentation.
Discussion
The default value of this property is 0. Changing the value of this property changes the the front-to-back ordering of layers onscreen. This can affect the visibility of layers whose frame rectangles overlap.
The other option is to add other subviews below this always-on-top subview. For example:
[self.view insertSubview:subview belowSubview:_topSubview];
There's no solution with Interface Builder if you search for this kind. It should be done programmatically. If you don't want to use bringSubviewToFront: everytime, just insert other subviews below this one.
Many times your view did not appear in viewDidLoad or, if your view comes from parentViewController (for example in many transitions like modal segue..) your can see parentViewController only in viewDidAppear so:
Try to put bringSubviewToFront in :
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.view bringSubViewToFront:myView];
// or if your view is attached in parentViewController
[self.parentViewController.view bringSubViewToFront:myView];
}
Good luck!

How to show overlay info view with two button more when i click a marker on google in iOS

I am trying to show a custom overlay view from the Google Maps through the Google Maps API for iOS. This overlay view content info of marker, and two my button. But I cannot find any references for this. My desired overlay view is as image with link below:
http://i1121.photobucket.com/albums/l515/dungnlh_khtn07/NguoiMoCay/overlayinfoview_zps8110b7ed.jpg
Please give me a guide for this!
Possibly, as mentioned officially in documentation of Google Maps Android API, the below restriction regarding infowindows applies to Google Maps iOs SDK also :
Info window is not a live View, rather the view is rendered as an image onto the map. As a result, any listeners you set on the view are disregarded and you cannot distinguish between click events on various parts of the view. You are advised not to place interactive components — such as buttons, checkboxes, or text inputs — within your custom info window.
So bascially clicking on any part of the infowindow will trigger only "didTapWindowOfMarker"
The best way of achieving this is to pass your GMSMapView a custom view for your info windows via the GMSMapViewDelegate's mapView:markerInfoWindow: method.
To accomplish this, set yourself up as the delegate for your GMSMapView instance, like so:
self.mapView.delegate = self;
Then return a custom UIView when requested:
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(id<GMSMarker>)marker
{
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
customView.backgroundColor = [UIColor redColor];
return customView;
}
You can find a little more information by looking in the GMSMapView header, which states:
/**
* Called when a marker is about to become selected, and provides an optional
* custom info window to use for that marker if this method returns a UIView.
* If you change this view after this method is called, those changes will not
* necessarily be reflected in the rendered version.
*
* The returned UIView must not have bounds greater than 500 points on either
* dimension. As there is only one info window shown at any time, the returned
* view may be reused between other info windows.
*
* #return The custom info window for the specified marker, or nil for default
*/
OK, but can someone please clarify how to get a UIButton on that UIView to respond to touches? Like two buttons in Dung Nguyen Le Hoang's attached picture. For example, if I add a button like this:
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(id<GMSMarker>)marker
{
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
customView.backgroundColor = [UIColor redColor];
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
[button setFrame:CGRectMake(0, 0, 30, 30)];
[customView addSubview:button];
return customView;
}
and of course have buttonPressed
- (void)buttonPressed
{
NSLog(#"Hello");
}
it doesn't get called. If I added the button as a subview to self.mapView then it appears on mapView, not InfoWindow and, of course, is responsive to touches. I suppose it's due to some unset frames, but can't quite get it. Can someone please clarify?
(void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker
You can show AlertView or ActionSheet with two buttons when the user tap on the markerInfoContents

Add opaque subview to UITextField

I have a subclass of UITextField and I'm trying ot add an opaque subview to it. However, when I type in the UITextField, it appears transparent and I can see the text behind the view. How can I make the view fully opaque? Here is the code that inits the subclass and adds the view.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_dropdownIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"ab- dropdown-on"]];
dropdownIcon.backgroundColor = [UIColor blackColor];
_dropdownIcon.frame = CGRectMake(self.frame.size.width-DROPDOWN_ICON_SIZE,0,DROPDOWN_ICON_SIZE,DROPDOWN_ICON_SIZE);
[self addSubview:_dropdownIcon];
}
return self;
}
Your subclass needs to override the -textRectForBounds: method to return the actual area you want text to draw in, e.g.
- (CGRect)textRectForBounds:(CGRect)bounds
{
CGRect textRect = [super textRectForBounds:bounds];
textRect.size.width -= 30; // or however wide your control is—play with this value
return textRect;
}
What you’re seeing is not the icon being non-opaque—the text is just being drawn over it, because the text field doesn’t “know” the icon is there.
You might also look into the rightView property and the related -rightViewRectForBounds: method, though those are mostly useful if you want the text field to automatically show and hide your accessory view.

Resources