UIScrollView Просмотр изображений с выводами сверху
-
20-08-2019 - |
Вопрос
У меня есть 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];
Код для добавления PIN-кода позже при каком-либо событии.
[iconsView addSubview:pinIcon];
Я застрял в попытках выяснить, как заставить мои пины наводиться на карту, не перемещаясь при изменении масштаба.
Решение
Мне нравится ваша идея сохранить все пины в представлении, посвященном пинам (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;
Я предположу, что у вас есть представление pin-кода или контроллер представления под названием DropPinViewController .Если вы просто используете изображение, это может быть UIImageView, но у моих пинов есть метки, поэтому я использовал xib.Булавка должна указывать на нижний центр xib, потому что мы собираемся поместить там точку привязки.
В вашем viewDidLoad вашего MyViewController добавьте ваши pin-представления в качестве вложенных представлений 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;
}
Другие советы
Итак, одна вещь, которую я реализовал, которая не решила мою проблему, но я думаю, что это правильный путь, взята из этой статьи.
Закрепите пользовательский интерфейс
У меня есть иерархия представлений следующим образом.
UIScrollView
- UIImageView (map image)
- IconsView (layer image to hold icons)
Следующий шаг, который мне нужно решить, - это сохранить мои пин-коды, добавленные в IconsView
закрепленный в том же месте , когда UIImageView
увеличивается и уменьшается масштаб изображения.
У меня был цикл for, который проходил через все мои контакты, которые являются подвидами IconsView
и обновили их Происхождение X и Y.Это было в UIScrollView
делегаты scrollViewDidScroll
способ.
Проблема заключалась в том, что этот метод имеет ужасную производительность на устройстве, так как при большом количестве контактов на карте требуется слишком много обработки.
Несколько рекомендаций:
1) Вы заметите в приложении Google Maps, что оно ограничивает количество пин-кодов, которые оно пытается отобразить по умолчанию.Он будет отображать только результаты, наиболее близкие к центральной точке, даже если существует больше возможных совпадений.
2) Вы могли бы ненадолго скрыть контакты во время любого действия прокрутки или зажима, чтобы интерфейс оставался отзывчивым, и перерисовать их в тот момент, когда изображение перестанет двигаться.
3) Если вам необходимо отобразить большое количество пинов и анимировать их, вы также можете рассмотреть возможность использования CABasicAnimations для одновременной анимации пинов и фона, изменяя положение пинов с использованием той же математики, которая преобразует масштаб фонов.Это могло бы сгладить отображение за счет более плавного распространения анимации и запуска ее на довольно низком уровне, но создает другие проблемы и ограничения.
Барни
У меня такая же проблема, и я нахожу идею ручного исправления местоположения pin-кода не очень привлекательной.Затем я скорее рисую свои пины на представлении, возвращаемом в функции делегирования viewForZoomingInScrollView:
и обновите размер подвида (маркеров) после завершения масштабирования.
Тем не менее, меня раздражает, что это возможно в приложении Google Maps, но я не могу воссоздать его.
Еще одна вещь:Кто-нибудь может объяснить мне поведение exhibitet, когда я добавляю подвиды в UIScrollView, которые не являются 'viewForZoomingInScrollView' ..?Например:
UIImageView* marker = [[UIImageView alloc] initWithImage: myMarkerImage];
[marker setCenter: CGPointMake(250,150)];
[myScrollView addSubview: marker];
Кажется, это нормально работает для начального вида и при панорамировании.При масштабировании размер этих вложенных представлений не изменяется, к чему мы на самом деле и стремимся, но проблема в том, что начало кадра UIView перемещается по виду прокрутки каким-то довольно странным образом.Похоже, что если увеличить масштаб изображения, то marker.frame.size.origin
всегда перемещается к верхнему левому углу (superview (0,0)), создавая впечатление, что мы на самом деле уменьшаем масштаб.Это тоже странно, потому что "центр масштабирования" всегда должен быть в центре экрана, не так ли?Ну, пока я этого не понимаю.
удар.;)
Спасибо Дэвиду Брауну.Ваш код работает, за исключением одной строки, которую мне пришлось закомментировать.Мой проект включал в себя UIScrollView, затем UIImageView сверху, который показывает карту, затем, наконец, контакты (кнопки), которые код позиционирует после обнаружения жеста двойного касания.Ваш код помог мне учесть масштаб масштабирования.Ограничение, однако, заключалось в том, что когда я зажимаю для увеличения, каждый вывод не "прилипает" к определенной части рисунка, к которой я дважды прикоснулся.Я наткнулся на решение, когда закомментировал эту строку:
//[dropPinView.layer setAnchorPoint:CGPointMake(0.5, 1)]установка точки привязки слоя:;
У меня нет полного понимания, но мой код теперь работает!Я надеюсь, что мой опыт принесет пользу другим.Спасибо, Дэвид!