UIScrollView ImageView с булавками сверху

У меня есть UIScrollView, у которого есть UIImageView. Я хочу показать булавки на этом imageView. Когда я добавляю булавки в качестве подвидов ImageView, все отлично, за исключением того, что когда вы увеличиваете масштаб, преобразование масштаба происходит и на булавках. Я не хочу такого поведения и хочу, чтобы мои контакты оставались прежними.

Поэтому я решил добавить пины в другое представление, которое находится поверх ImageView и также является подвидом представления UIScrollView. Идея здесь, если вы представляете, состоит в том, чтобы иметь слой, который нависает над картой и не масштабируется, но показывает булавки там, где я их рисую.

Булавка при добавлении в представление слоя не масштабируется, если масштабируется ImageView. Однако тогда проблема заключается в том, что положение штифтов не соответствует исходному началу x/y, поскольку ImageView имеет масштабное преобразование.

По сути, это пользовательская карта места с пинами. Я пытаюсь, чтобы булавки плавали, а не увеличивались и уменьшались над моим ImageView, но помню, где я их разместил, когда происходит увеличение.

Некоторый код:

scrollView = [[UIScrollView alloc] initWithFrame:viewRect];

scrollView.delegate = self;
scrollView.pagingEnabled = NO;
scrollView.scrollsToTop = NO;
[scrollView setBackgroundColor:[UIColor clearColor]];
scrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView.bounces = YES;
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;

imageViewMap = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image.png"]];

imageViewMap.userInteractionEnabled = YES;

viewRect = CGRectMake(0,0,imageViewMap.image.size.width,imageViewMap.image.size.height);

//viewRect = CGRectMake(0,0,2976,3928);

[scrollView addSubview:imageViewMap];

[scrollView setContentSize:CGSizeMake(viewRect.size.width, viewRect.size.height)];

iconsView = [[UIView alloc] initWithFrame:imageViewMap.frame];

[scrollView addSubview:iconsView];

Код для добавления Пина позже на какое-то событие.

[iconsView addSubview:pinIcon];

Я застрял в попытках выяснить, как заставить мои булавки зависать на карте, не двигаясь, когда происходит масштабирование.


person Koppo    schedule 27.06.2009    source источник


Ответы (5)


Мне нравится ваша идея хранить все булавки в представлении, посвященном булавкам (iconsView), но я решил просто добавить их в качестве подвидов того, что вы назвали imageViewMap.

Импортируйте файл QuartzCore.framework в свой проект.

Назовите свой контроллер представления MyViewController.

#import <QuartzCore/QuartzCore.h>
@interface MyViewController : UIViewController <UIScrollViewDelegate>
@property (retain) UIScrollView *scrollView;
@property (retain) UIImageView *imageView;

// и так далее

@implementation MyViewController

@synthesize scrollView;
@synthesize imageView;

Я предполагаю, что у вас есть вид булавки или контроллер представления под названием DropPinViewController. Если вы просто используете изображение, это может быть UIImageView, но у моих контактов есть метки, поэтому я использовал xib. Штифт должен указывать на нижний центр xib, потому что мы собираемся разместить там точку привязки.

В вашем viewDidLoad вашего MyViewController добавьте свои виды булавок в качестве подпредставлений imageView. Добавьте imageView в качестве подпредставления к scrollView. Установите размер содержимого scrollView.

scrollView.delegate = self;

Используйте эти методы делегата:

- (void)scrollViewDidZoom:(UIScrollView *)aScrollView
{   
    for (UIView *dropPinView in imageView.subviews) {       
    CGRect oldFrame = dropPinView.frame;
    // 0.5 means the anchor is centered on the x axis. 1 means the anchor is at the bottom of the view. If you comment out this line, the pin's center will stay where it is regardless of how much you zoom. I have it so that the bottom of the pin stays fixed. This should help user RomeoF.
   [dropPinView.layer setAnchorPoint:CGPointMake(0.5, 1)];
    dropPinView.frame = oldFrame;
    // When you zoom in on scrollView, it gets a larger zoom scale value.
    // You transform the pin by scaling it by the inverse of this value.
    dropPinView.transform = CGAffineTransformMakeScale(1.0/scrollView.zoomScale, 1.0/scrollView.zoomScale);
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return imageView;
}
person David Braun    schedule 02.12.2011
comment
Это так здорово, что я немного болен. У меня есть много других запутанных методов, которые делают это... Так просто. Я переключился на это, и это прекрасно работает. - person malaki1974; 03.07.2013
comment
Хороший трюк. Вы можете сделать то же самое, поместив булавки в отдельный вид и вместо этого масштабируя их координаты. Интересно, будет ли это более или менее производительным. - person Bob Spryn; 27.06.2014

Итак, я реализовал одну вещь, которая не решила мою проблему, но я думаю, что это правильный путь из этой статьи.

Привязка UIView

У меня есть иерархия представлений следующим образом.

UIScrollView
 - UIImageView (map image)
 - IconsView (layer image to hold icons)

Следующий шаг, который мне нужно решить, — это оставить мои контакты, добавленные к IconsView, закрепленными в одном и том же месте, когда UIImageView увеличивается и уменьшается.

У меня был цикл for, который прошел через все мои контакты, которые являются подвидами IconsView, и обновил их Origin X и Y. Это было в методе scrollViewDidScroll делегатов UIScrollView.

Проблема заключалась в том, что этот метод имеет ужасную производительность на устройстве, поскольку, когда на карте много точек, требуется слишком много обработки.

person Koppo    schedule 28.06.2009
comment
Вы также можете использовать scrollViewDidZoom() вместо scrollViewDidScroll(). - person kelin; 17.09.2019

Несколько рекомендаций:

1) Вы заметите в приложении Google Maps, что оно ограничивает количество контактов, которые оно пытается отобразить по умолчанию. Он будет отображать только результаты, наиболее близкие к центральной точке, даже если возможных совпадений больше.

2) Вы можете ненадолго скрыть булавки во время любого действия прокрутки или сжатия, чтобы интерфейс оставался отзывчивым, и перерисовывать их в тот момент, когда представление изображения перестает двигаться.

3) Если вам нужно отобразить большое количество булавок и анимировать их, вы также можете рассмотреть возможность использования CABasicAnimations для одновременной анимации булавок и фона, преобразования положения булавок с использованием той же математики, которая преобразует масштаб фона. Это может сгладить отображение за счет более плавного распространения анимации и запуска ее на довольно низком уровне, но создает другие проблемы и ограничения.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Animation_Types_Timing/Articles/PropertyAnimations.html#//apple_ref/doc/uid/TP40006672-SW1

Барни

person Barney Mattox    schedule 08.07.2009

У меня та же проблема, и я нахожу идею ручного исправления положения булавки не очень красивой. Затем я скорее рисую свои булавки на представлении, возвращаемом функцией делегата viewForZoomingInScrollView:, и обновляю размер подпредставления (маркеров) после завершения масштабирования.

Однако меня раздражает, что это возможно в приложении Google Maps, но я не могу его воссоздать.

Еще одна вещь: может ли кто-нибудь объяснить мне поведение экспонента, когда я добавляю подвиды в UIScrollView, которые не являются «viewForZoomingInScrollView»..? Например:

UIImageView* marker = [[UIImageView alloc] initWithImage: myMarkerImage];
[marker setCenter: CGPointMake(250,150)];
[myScrollView addSubview: marker];

Кажется, это отлично работает для начального просмотра и при панорамировании. При масштабировании размер этих подпредставлений не изменяется, к чему мы и стремимся, но проблема в том, что исходная точка кадра UIView перемещается по прокрутке каким-то довольно странным образом. Похоже, что если увеличить масштаб, marker.frame.size.origin всегда движется к верхнему левому углу (супервид (0,0)), создавая впечатление, что мы на самом деле уменьшаем масштаб. Это тоже странно, потому что «центр масштабирования» всегда должен быть в центре экрана, не так ли? Ну, я пока не понимаю.

удар. ;)

person Efrain    schedule 13.04.2010

Спасибо Дэвиду Брауну. Ваш код работает, за исключением одной строки, которую мне пришлось закомментировать. Мой проект включал наличие UIScrollView, затем UIImageView сверху, который показывает карту, а затем, наконец, контакты (кнопки), которые код позиционирует после обнаружения жеста двойного нажатия. Ваш код помог мне учесть масштаб масштабирования. Однако ограничение заключалось в том, что, когда я щипал для увеличения, каждая булавка не «прилипала» к определенной части рисунка, где я дважды нажал. Я наткнулся на решение, когда закомментировал эту строку:

//[dropPinView.layer setAnchorPoint:CGPointMake(0.5, 1)];

У меня нет полного понимания, но мой код теперь работает! Я надеюсь, что другим будет полезен мой опыт. Спасибо, Дэвид!

person RomeoF    schedule 01.02.2012