Getting Location of user in iOS differs with MKMapView and CLLocationManager - mkmapview

Im using CLLocationManager to get user location,In another case Im using MKMapview to show on map.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
16.50374457,+80.66301357 // lat and long
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D loc = [userLocation coordinate];
//(latitude = 16.507553768993734, longitude = 80.664011964856343)
}
Two results appeared differed a little bit. As per my observation second one is most accurate. AS R & D MKMapview Uses Cllocation manager internally, But why I get differences?

Related

Set round corners AVPlayer video frame

Anyone knowns how to set round corner to the video frame using AVPlayer?
I'm trying doing this:
- (void)loadVideoWithPlayer:(AVPlayer*)playerVideo
{
dispatch_async(dispatch_get_main_queue(), ^{
AVPlayerLayer *avLayer = [AVPlayerLayer playerLayerWithPlayer: playerVideo];
[avLayer setCornerRadius:20];
[avLayer setMasksToBounds:YES];
[self.playerViewController setPlayer:playerVideo];
[self insertSubview:self.playerViewController.view belowSubview:self.interactView];
[self.playerViewController.player play];
});
}
but it's not working. I can't set round corners to the AVPlayer.playerViewController.view because the video frame could be different.
I was just able to do this. The change could even be animatable, from no rounder corners to rounded corners.
I didn't do anything much different from you. Using iOS 10 at the moment. (Confirmed working on iOS 9.3.5 device also.)
self.viewVideo?.layer.masksToBounds = SHOW ? true : false
self.viewVideo?.layer.cornerRadius = SHOW ? 10 : 0
I should perhaps note that the viewVideo is a subclass of UIView. The only real change there is the layerClass being returned as AVPlayerLayer.self
override static var layerClass: AnyClass {
return AVPlayerLayer.self
}
So btw I do not use AVPlayerViewController etc. I just add my subclass of UIView to my usual UIViewController's view.

Positioning sprites inside scene

I would like when i create all my sprites to get centred in the screen, but that is not the case, i have a sprite when i set it's position to CGPointMake(self.size.width / 2, self.size.height / 2) it gets centred vertically but not horizontally, when i set it to CGPointMake(0, 0) it sets at the bottom of the screen with only half of it's body visible ( which is what you expect) but horizontally it doesn't get positioned right ( half his vertical body appears ) until i set it's X to 300.
How come the sprite's Y position gets set right but the X doesn't ?
scene.scaleMode = .AspectFill
and i haven't set any anchorPoint, 4' screen.
UPDATE:
I'm using Portrait, played around with different scaleMode and found out that the perfect (0, 0) that sets the sprite on the bottom left is:
scene.scaleMode = .ResizeFill
It also works fine with different screen sizes,but (self.size.width / 2) puts it further to the left.Do you think it's the best setting for all SpriteKit Portrait projects?
I tried to reproduce what you are saying, but I couldn't, either using .sks file or not for loading the scene. Also I've produced good results on both 7.1 and 8.1 simulators...The thing is that simulators sometimes could be tricky and not 100% reliable, so you should not trust them much.
I don't know if this will help you, but you should consider it...In Xcode 5 projects scene is programmatically created to have a size of the view. Basically it's done in viewDidLoad method like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
Or using viewWillLayoutSubviews like LearnCocos2D pointed:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
skView.showsDrawCount = YES;
//skView.showsQuadCount = YES;
skView.showsPhysics = YES;
skView.ignoresSiblingOrder = YES;
if(!skView.scene){
// Create and configure the scene.
GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}
But Xcode 6 uses an SKS file:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
}
}
If you look at the GameScene.sks you can see that the default scene size is 1024x768.
Try to print your scene size as well as view's bounds size to see actuall sizes. You can use something like:
println("view.bounds\(view.bounds), self.size\(self.size)")
I don't know if any of this helped, but I hope it will lead you somewhere. Goodluck!

How to overlay MKPolyline on top of different maps

So I draw a MKPolyline with the users updated CLLocationCoordinates as per usual. When my quits and starts again, all of the past points are loaded onto the mapview to be displayed with
routeLine = [MKPolyline polylineWithCoordinates:clCoordinates count:numberOfSteps];
[_mapView addOverlay:routeLine];
and in MKOverlayRenderer method I have
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
This all works a treat, but problems arise when I change the type of map with
[self resetMapViewAndRasterOverlayDefaults];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
_rasterOverlay = [[MBXRasterTileOverlay alloc] initWithMapID:#"jonobolitho.j834jdml"];
_rasterOverlay.delegate = self;
[_mapView addOverlay:_rasterOverlay];
Note, I have the resetMapViewAndRasterOverlayDefaults helper method
// Reset the MKMapView to some reasonable defaults.
//
_mapView.mapType = MKMapTypeStandard;
_mapView.zoomEnabled = YES;
[_mapView removeAnnotations:_rasterOverlay.markers];
[_mapView removeOverlay:_rasterOverlay];
[_rasterOverlay invalidateAndCancel];
I am using MBXMapKit to display the maps. The maps display correctly, but the polyline isn't shown on top of the map. The map just loads over the top of my polyline (routeLine). I know this because in between the tiles of the new map I can see the routeLine underneath.
So basically is there a way to load the MKPolyline but always keep it on the top layer of the map, even if it changes?
Instead of:
[_mapView addOverlay:_rasterOverlay];
You want:
[_mapView insertOverlay:_rasterOverlay belowOverlay:routeLine];
Or something similar. Overlays have an order.

Centre location not updating, puts me in the middle of the ocean?

Stuck on something very basic, just started up with MKMapView and trying to get it to zoom in on my location.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate; }
This code seems to just not be working, I understand it usually takes a little bit of time to get the location and i have left it for a while with now luck. However the location shows up correctly but it doesn't centre in on this (it centres into the very middle of the map just off west africa)
I also have the following code in viewDidLoad, which seems to be correct as it zooms in to the specified height, just not place.
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 20000, 20000);
[self.mapView setRegion:region animated:YES];
EDIT: It seems to be working on the simulator now after pressing back once or twice and then re-viewing to the map. But it doesn't work on my iPhone still. I have checked all the location services settings and they seem to be all on.
I use the following code to set center and span to be shown in MapView. It should work.
MKCoordinateRegion region = {{0,0},{.5,.5}};
region.center.latitude = doubleLattitude;
region.center.longitude = doubleLongitude;
[mapView setRegion:region animated:YES];
If a MKMapView centers to just west of Gabon, it's very likely that one of your objects is nil and thus the coordinate is 0° latitude and 0° longitude. You can easily test it by setting a breakpoint in the debugger and analyzing your objects.
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
Does not center map on user location.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation is called only first time when device gets user location,
better use - (void)locationManager:didUpdateToLocation: fromLocation:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if(newLocation.horizontalAccuracy>0)
{
// set center of map (span will not be changed in this case)
[mymap setCenterCoordinate:newLocation.coordinate animated:YES];
// or use region to specify both span and center
MKCoordinateRegion region.span.latitudeDelta = .05 ;
region.span.longitudeDelta = .05 ;
region.center.latitude = newLocation.coordinate.latitude ;
region.center.longitude = newLocation.coordinate.longitude ;
[mymap setRegion:region animated:TRUE];
}
}

Resize CATextLayer to fit text on iOS

All my research so far seems to indicate it is not possible to do this accurately. The only two options available to me at the outset were:
a) Using a Layout manager for the CATextLayer - not available on iOS as of 4.0
b) Use sizeWithFont:constrainedToSize:lineBreakMode: and adjust the frame of the CATextLayer according to the size returned here.
Option (b), being the simplest approach, should work. After all, it works perfectly with UILabels. But when I applied the same frame calculation to CATextLayer, the frame was always turning out to be a bit bigger than expected or needed.
As it turns out, the line-spacing in CATextLayers and UILabels (for the same font and size) is different. As a result, sizeWithFont (whose line-spacing calculations would match with that of UILabels) does not return the expected size for CATextLayers.
This is further proven by printing the same text using a UILabel, as against a CATextLayer and comparing the results. The text in the first line overlaps perfectly (it being the same font), but the line-spacing in CATextLayer is just a little shorter than in UILabel. (Sorry I can't upload a screenshot right now as the ones I already have contain confidential data, and I presently don't have the time to make a sample project to get clean screenshots. I'll upload them later for posterity, when I have the time)
This is a weird difference, but I thought it would be possible to adjust the spacing in the CATextLayer by specifying the appropriate attribute for the NSAttributedString I use there, but that does not seem to be the case. Looking into CFStringAttributes.h I can't find a single attribute that could be related to line-spacing.
Bottomline:
So it seems like it's not possible to use CATextLayer on iOS in a scenario where the layer is required to fit to its text. Am I right on this or am I missing something?
P.S:
The reason I wanted to use CATextLayer and NSAttributedString's is because the string to be displayed is to be colored differently at different points. I guess I'd just have to go back to drawing the strings by hand as always....of course there's always the option of hacking the results from sizeWithFont to get the proper line-height.
Abusing the 'code' tags a little to make the post more readable.
I'm not able to tag the post with 'CATextLayer' - surprisingly no such tags exist at the moment. If someone with enough reputation bumps into this post, please tag it accordingly.
Try this:
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth withAttributedString:(NSAttributedString *)attributedString {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) attributedString);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, CGFLOAT_MAX), NULL);
CFRelease(framesetter);
return suggestedSize.height;
}
You'll have to convert your NSString to NSAttributedString. In-case of CATextLayer, you can use following CATextLayer subclass method:
- (NSAttributedString *)attributedString {
// If string is an attributed string
if ([self.string isKindOfClass:[NSAttributedString class]]) {
return self.string;
}
// Collect required parameters, and construct an attributed string
NSString *string = self.string;
CGColorRef color = self.foregroundColor;
CTFontRef theFont = self.font;
CTTextAlignment alignment;
if ([self.alignmentMode isEqualToString:kCAAlignmentLeft]) {
alignment = kCTLeftTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentRight]) {
alignment = kCTRightTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentCenter]) {
alignment = kCTCenterTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentJustified]) {
alignment = kCTJustifiedTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentNatural]) {
alignment = kCTNaturalTextAlignment;
}
// Process the information to get an attributed string
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
if (string != nil)
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)string);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTForegroundColorAttributeName, color);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTFontAttributeName, theFont);
CTParagraphStyleSetting settings[] = {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTParagraphStyleAttributeName, paragraphStyle);
CFRelease(paragraphStyle);
NSMutableAttributedString *ret = (NSMutableAttributedString *)attrString;
return [ret autorelease];
}
HTH.
I have a much easier solution, that may or may not work for you.
If you aren't doing anything special with the CATextLayer that you can't do a UILabel, instead make a CALayer and add the layer of the UILabel to the CALayer
UILabel*label = [[UILabel alloc]init];
//Do Stuff to label
CALayer *layer = [CALayer layer];
//Set Size/Position
[layer addSublayer:label.layer];
//Do more stuff to layer
With LabelKit you don't need CATextLayer anymore. No more wrong line spacing and wider characters, all is drawn in the same way as UILabel does, while still animated.
This page gave me enough to create a simple centered horizontally CATextLayer : http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
- (void)drawInContext:(CGContextRef)ctx {
CGFloat height, fontSize;
height = self.bounds.size.height;
fontSize = self.fontSize;
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, (fontSize-height)/2.0 * -1.0);
[super drawInContext:ctx];
CGContextRestoreGState(ctx);
}

Resources