I want to have the same functionality of MKUserTrackingBarButtonItem on a Map but I want to do it programmatically.
Normally using I do this on ViewController
- (void) viewDidLoad
{
...
MKUserTrackingBarButtonItem *buttonItem = [[MKUserTrackingBarButtonItem alloc] initWithMapView:self.map];
self.navigationItem.rightBarButtonItem = buttonItem;
...
}
But I want to try it by code. I know how to get the UserLocation, but how can I get the compass functionality?
I know it's an old post but isn't compass functionality the "heading"? And so, you can set the tracking mode of the map by changing the userTrackingMode of the MKMapView.
Related
I have a splitviewcontroller application where the master view controller is a UITableView and the detail view controller contains a MKMapView and a single annotation. When I make a selection in the UITableView the secondary view segues to a different map view with a single annotation.
When I select an annotation and then immediately afterwards (before the annotation popover appears) select a cell I receive an EXC_BAD_ACCESS crash. I used the Zombies tool to try and gather further information and I received this message.
An Objective-C message was sent to a deallocated 'MKPopoverBasedAnnotationCalloutController' object (zombie)
I believe the issue here is that the map view is still trying to display the annotations popover but the annotation has been deallocated.
So far I have tried:
•Setting MKMapView delegate nil on dealloc
Note: I am not using any custom popovers for the annotation. I also had a similar problem when calling [mapView selectAnnotation:mp animated:YES]; and then selecting another cell. I fixed this by just not calling it. This is obviously not an ideal solution.
Any suggestions on how to solve this? Or any insight on whether it is an issue with MapKit or an Issue with my application specifically?
Thanks in Advance,
Chris
I've been able to reproduce the issue consistently and it indeed looks like a bug with Apple's mapkit code. The only way i've been able to fix it was to create a singleton for MKMapView
-(MKMapView*)mapview{
static MKMapView *_mapview = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_mapview = [[MKMapView alloc] initWithFrame:[UIScreen mainScreen].bounds];
_mapview.showsPointsOfInterest = NO;
_mapview.pitchEnabled = NO;
});
return _mapview;
}
An important note, when you remove the map don't clear the annotations yet, wait until you initialize it..
so not here...
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[self.mapview removeFromSuperview];
self.mapview.delegate = nil; //AND OR IN DEALLOC
}
but here ...
- (void)viewDidLoad{
[super viewDidLoad];
[self.view addSubview:self.mapview];
self.mapview.delegate = self;
[self.mapview removeAnnotations:[self.mapview annotations]];
//RECREATE THOSE ANNOTATIONS
}
I want to create a simple mobilesubstrate tweak that hides and shows status bar icons like battery or Carrier or wifi signal indecator. I've seen libstatusbar project but i can't find out how to hide iOS's icons. Is there any other way to do this without the use of this library? I just want to hide and show the default icons
Not possible using public API. You can only hide the entire status bar, not only certain elements of it.
For jailbreak, take a look at:
https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIStatusBarItem.h
In particularly, look at the following methods:
+ (BOOL)itemType:(int)arg1 idiom:(int)arg2 appearsInRegion:(int)arg3;
+ (BOOL)itemType:(int)arg1 idiom:(int)arg2 canBeEnabledForData:(id)arg3 style:(id)arg4;
These methods are consulted whether iterms should appear or not. Return NO here to disable items.
Here is what I use in my tweak:
int itemToHide = 0;
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] beginCoalescentBlock];
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] _setItem:itemToHide enabled:NO];
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] endCoalescentBlock];
Only problem - iOS uses integer values for status bar items and they're different on different iOS versions. You could test every iOS version and store values for each one of them but I found a better way.
I hook SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 method. Then I call one of the SBStatusBarStateAggregator -(void)_update**** methods. For example, let's say I want to find location icon index. I call SBStatusBarStateAggregator -(void)_updateLocationItem method. It then will call hooked SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 where I will store the index.
I also hook SBStatusBarStateAggregator -(void)_notifyItemChanged:(int)arg. This method is called as part of SBStatusBarStateAggregator -(void)_update**** call. When determing status bar icon index I simply ignore calls to it by returning without calling original implementation.
And if you want to permanently hide some of the icons you still need to hook SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 and SBStatusBarStateAggregator -(void)_notifyItemChanged:(int)arg in order to ignore any iOS attempts to show hidden icons. For example, signal level and data/time are reanabled every time they're updated.
That's all for iOS 7. On iOS 5-6 API is different but I use pretty much the same approach. To hide status bar item
int itemToHide = 0;
[[objc_getClass("SBStatusBarDataManager") sharedDataManager] setStatusBarItem:itemToHide enabled:NO];
I hook SBStatusBarDataManager -(void)updateStatusBarItem:(int)item to determine icon index and then call SBStatusBarDataManager -(void)_locationStatusChange in case of location icon.
Ok. Here is solution.
In your plist file add row:
View controller-based status bar appearance : NO
Make a category on UINavigationBar with this content:
#import "UINavigationBar+StatusBar.h"
#import
#implementation UINavigationBar (StatusBar)
+ (void)load
{
[self swizzleOriginalSelectorWithName:#"layoutSubviews" toSelectorWithName:#"my_layoutSubviews"];
}
- (void)my_layoutSubviews
{
[self my_layoutSubviews];
[self setFrame:CGRectMake(0, 0, self.frame.size.width, 64)];
}
+ (void)swizzleOriginalSelectorWithName:(NSString *)origName toSelectorWithName:(NSString *)swizzleName
{
Method origMethod = class_getInstanceMethod([self class], NSSelectorFromString(origName));
Method newMethod = class_getInstanceMethod([self class], NSSelectorFromString(swizzleName));
method_exchangeImplementations(origMethod, newMethod);
}
#end
This will increase navigation bar for 20pt.
Then, make your custom view for status bar.
e.g.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self makeCustomSatusBar];
// Override point for customization after application launch.
return YES;
}
- (void)makeCustomSatusBar
{
[[UIApplication sharedApplication] setStatusBarHidden:YES];
UIColor *statusBarColor = [UIColor blackColor];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.window.frame.size.width, 20)];
view.layer.zPosition = INT_MAX;
view.backgroundColor = [UIColor clearColor];
// Making time label
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"HH:mm";
UILabel *timeLabel = [UILabel new];
timeLabel.text = [formatter stringFromDate:[NSDate date]];
timeLabel.textColor = statusBarColor;
timeLabel.font = [UIFont systemFontOfSize:12];
[timeLabel sizeToFit];
timeLabel.center = CGPointMake(view.frame.size.width/2, view.frame.size.height/2);
[view addSubview:timeLabel];
//
// make other indicators you need...
//...
[self.window addSubview:view];
}
And you will have something like this:
Note, that you need to update values of your custom view every time (i.e. time label, battery, etc..) , so it would be better to make a separate class for your status bar, and make a infinite timer with 1 sec of tick and do your updates in timer's action.
may be you just need this?
[[UIApplication sharedApplication] setStatusBarHidden:YES]
And if you want just empty view on top of 20pt height, then make that and add to UIWindow, and shift down subview of UIWindow for 20 pt
I am trying to add the default button to return to current Location within google map. I added the button using
self.mapView.myLocationButton = YES
But not able to hide the blue dot which is not required in my case.
If i set
self.mapView.myLocationEnabled = NO
It would remove the functionality to return back to current Location on pressing the current Location button.
Following is the code i've implemented
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.mapView.delegate = self;
self.mapView.settings.myLocationButton = YES;
self.mapView.myLocationEnabled = YES;
}
You can simply add the annotation view:
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *note= [mapView viewForAnnotation:mapView.userLocation];
note.hidden = YES;
}
In this way the map will still receive user's location updates but the blue dot is hidden. Remember that since this is a delegate method, you should correctly set the delegate.
self.mapView.myLocationEnabled = NO to hide the blue dot.
set a class to implement CLLocationManagerDelegate to track user's location.
try
self. mapView.showsUserLocation=NO;
Easier way would be to replace your annotation with view that has color as clearColor. This way our current location would be shown with an invisible annotation ;-)
Simply use mapView_.myLocationEnabled = NO;
Its solve your problem
In Swift 4x -
mapView.delegate = self
mapView.settings.myLocationButton = true
mapView.isMyLocationEnabled = true
Currently learning iOS development. I need to set my instance of MKMapView to display with satellite view. I know I can do this through the attribute settings, but I wish to do it through code using [myMapView setMapType:MKMapTypeSatellite], but my question is, where do I put this so that as soon as the mapView loads on the screen, it is already in satellite mode. My instinct is to send this message once my instance of mapview is instantiated, but where does this occur?
Typically this type of code is put into the view controller's viewDidLoad method, which is called once for each instance of a controller.
- (void)viewDidLoad {
[super viewDidLoad];
myMapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,0,200,200)];
myMapView.mapType = MKMapTypeSatellite;
[self.view addSubview:myMapView];
}
Hi I just came across MTLocation here: https://github.com/darkseed/MTLocation.
I want to use a locate me button in my app which will be located in navigation bar and when pressed will move the map to current location.
The author proposes to use the code like this:
// Configure Location Manager
[MTLocationManager sharedInstance].locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[MTLocationManager sharedInstance].locationManager.distanceFilter = kCLDistanceFilterNone;
[MTLocationManager sharedInstance].locationManager.headingFilter = 5; // 5 Degrees
// create locate-me item
MTLocateMeBarButtonItem *locateMeItem = [[[MTLocateMeBarButtonItem alloc] initWithLocationStatus:MTLocationStatusIdle] autorelease];
// set delegate that is called when mode of Button changes
locateMeItem.delegate = [MTLocationManager sharedInstance];
// add target-action
[locateMeItem addTarget:self action:#selector(myCustomSelector:) forControlEvents:UIControlEventTouchUpInside];
// disable heading
locateMeItem.headingEnabled = NO;
// create array with ToolbarItems
NSArray *toolbarItems = [NSArray arrayWithObject:locateMeItem];
// set toolbar items
[self.toolbar setItems:toolbarItems animated:NO];
which is great to show a locate me button in toolbar but how can we make this work to show current location through gps? I guess tha we have to implement myCustomSelector method but I do not know how. Any help?
Make sure that you have
self.mapView.showsUserLocation = YES;
And then implement myCustomSelector:, for example like this:
- (void) myCustomSelector:(MTLocateMeBarButtonItem*) button {
[self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate];
}
You'll need to take care of a proper functionality at different button modes (whether MTLocateMeBarButton is Idle, or something else), but that should give you a direction.