Ссылка NullReferenceException или Object, не установленная на экземпляр объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Как видно из вышеприведенного кода, оператор Student s - объявляет только переменную типа Student, обратите внимание, что класс Student не создается в этой точке. Следовательно, когда выполняется выполнение инструкции s.GetFullName (), она выкинет исключение NullReferenceException.
Фактически на MKMapView по умолчанию - аннотация (например, контакт или изображение) и выноска (например, пузырь) остаются того же размера, что и вы увеличиваете или уменьшаете масштаб. Они не масштабируются. Но я получаю вашу точку зрения по отношению к карте, которую они, по-видимому, растут по мере того, как карта масштабируется и сжимается по мере приближения карты.
Итак, есть две проблемы в вашей проблеме, и они работают несколько иначе:
-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated
из ссылки протокола MKMapViewDelegate, которую вы уже выполнили. UIPinchGestureRecognizer
к объекту MKMapView, а затем выполните действие. Вариант №1 - mapView:regionDidChangeAnimated:
будет вызван либо для прокрутки, либо для события масштабирования - в основном в любое время, когда область карты изменилась с учетом названия. Это приводит к чуть менее плавному изменению размеров значков, потому что события карты срабатывают реже.
Мои настройки предназначены для варианта № 2 - присоедините UIPinchGestureRecognizer
к объекту MKMapView и затем выполните действие. События жестового нажатия запускаются довольно быстро, поэтому вы получаете плавное изменение размера значка. И они только срабатывают для распознанного события пинча, поэтому они не будут стрелять во время события прокрутки.
Вызванные методы действия должны соответствовать одной из следующих подписей:
blockquote>
- (void)handleGesture;
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
Вы должны быть осторожны, чтобы не переопределять поведение по умолчанию по умолчанию для карт. См. Это сообщение: «UIMapView: UIPinchGestureRecognizer не называется» для получения дополнительной информации. Короткий ответ заключается в том, что вы должны реализовать
shouldRecognizeSimultaneouslyWithGestureRecognizer:
и вернуть YES.Все сказанное здесь - это пример кода:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; self.mapView.mapType = MKMapTypeStandard; // also MKMapTypeSatellite or MKMapTypeHybrid // Add a pinch gesture recognizer UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; pinchRecognizer.delegate = self; [self.mapView addGestureRecognizer:pinchRecognizer]; [pinchRecognizer release]; } #pragma mark - #pragma mark UIPinchGestureRecognizer - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinchRecognizer { if (pinchRecognizer.state != UIGestureRecognizerStateChanged) { return; } MKMapView *aMapView = (MKMapView *)pinchRecognizer.view; for (id <MKAnnotation>annotation in aMapView.annotations) { // if it's the user location, just return nil. if ([annotation isKindOfClass:[MKUserLocation class]]) return; // handle our custom annotations // if ([annotation isKindOfClass:[MKPointAnnotation class]]) { // try to retrieve an existing pin view first MKAnnotationView *pinView = [aMapView viewForAnnotation:annotation]; //Format the pin view [self formatAnnotationView:pinView forMapView:aMapView]; } } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }
Итак, на этом этапе у вас снова есть несколько вариантов как изменить размер аннотации. Оба следующих примера кода полагаются на код Трой Бранта для получения уровня масштабирования MKMapView .
- Измените размер аннотационного изображения и выноска с помощью преобразования. Лично я думаю, что преобразование приводит к более чистому изменению размера. Но в большинстве случаев - изменение размера выноски не требуется.
- Измените размер только аннотационного изображения. Я использую . Тревор Harmon's Resize a UIImage правильный путь , но опять же мое мнение состоит в том, что оно не так чисто выглядит, как изменение размера.
Вот еще пример кода:
- (void)formatAnnotationView:(MKAnnotationView *)pinView forMapView:(MKMapView *)aMapView { if (pinView) { double zoomLevel = [aMapView zoomLevel]; double scale = -1 * sqrt((double)(1 - pow((zoomLevel/20.0), 2.0))) + 1.1; // This is a circular scale function where at zoom level 0 scale is 0.1 and at zoom level 20 scale is 1.1 // Option #1 pinView.transform = CGAffineTransformMakeScale(scale, scale); // Option #2 UIImage *pinImage = [UIImage imageNamed:@"YOUR_IMAGE_NAME_HERE"]; pinView.image = [pinImage resizedImage:CGSizeMake(pinImage.size.width * scale, pinImage.size.height * scale) interpolationQuality:kCGInterpolationHigh]; } }
Если это работает, не забудьте отметить его как ответ.
Альтернативным методом было бы изменить размер свойства изображения представления аннотаций. Пример: , показанный в этом сообщении
@ Ответ Funktional в Swift 3:
class MapViewController: UIViewController: UIGestureRecognizerDelegate {
@IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// You can also add this gesture recognizer and set the delegate via storyboard
let pinchGR = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture))
pinchGR.delegate = self
self.mapView.addGestureRecognizer(pinchGR)
}
// link as @IBAction when added via storyboard
func handlePinchGesture(_ sender: UIPinchGestureRecognizer) {
if sender.state == .ended {
for annotation in mapView.annotations {
if annotation is MKUserLocation {
continue
}
guard let annotationView = self.mapView.view(for: annotation) else { continue }
let scale = -1 * sqrt(1 - pow(mapView.zoomLevel / 20, 2.0)) + 1.4
annotationView.transform = CGAffineTransform(scaleX: CGFloat(scale), y: CGFloat(scale))
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
extension MKMapView {
var zoomLevel: Double {
return log2(360 * ((Double(self.frame.size.width) / 256) / self.region.span.longitudeDelta)) - 1
}
}
В Swift 3 это сработало для меня. Мое изображение было 100% на уровне 19, поэтому 1/19 дает мне 0,5263158, что является моей линейной шкалой:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let mkView = MKAnnotationView(annotation: annotation, reuseIdentifier: "mkView")
mkView.image = UIImage(named: "Foo")
formatAnnotation(pinView: mkView, forMapView: mapView)
return mkView;
}
func formatAnnotation(pinView: MKAnnotationView, forMapView: MKMapView) {
let zoomLevel = forMapView.getZoomLevel()
let scale = 0.05263158 * zoomLevel //Modify to whatever scale you need.
pinView.transform = CGAffineTransform(scaleX: CGFloat(scale), y: CGFloat(scale))
}
Извините за мой плохой английский ... но я просто хочу помочь кому-то.
Большое спасибо, Funktional. Ваш ответ велик ... его работа над iOS5 отлично! Но это недействительно на iOS6, и, похоже, пока нет решения для решения этой проблемы.
Но, наконец, я решил это глупо / статически, и он отлично работает на обоих iOS. Я не собираюсь объяснять слишком много. Это то, что я сделал в своем проекте.
NSString* imageName =
[NSString stringWithFormat:@"%@%@.png",
[imageName substringToIndex:[imageName length]-4 ],
[self getImageLevel]];
-(NSString *)getImageLevel{
NSString* output;
double zoomLevel = [self getZoomLevel:_mapview];
if(zoomLevel >= 19.0)
output = @"";
else if(zoomLevel < 19.0 && zoomLevel >= 18.0)
output = @"-5";
else if(zoomLevel < 18.0 && zoomLevel >= 17.0)
output = @"-4";
else if(zoomLevel < 17.0 && zoomLevel >= 16.0)
output = @"-3";
else if(zoomLevel < 16.0 && zoomLevel >= 15.0)
output = @"-2";
else
output = @"-1";
return output;}
извините за плохое кодирование и заново английскую.