使用严格的自动布局环境缩放UIScrollView似乎不起作用。
这尤其令人沮丧,因为iOS 6发行说明当然让我相信它应该在这里写一篇关于“纯自动布局方法”{@ 3}}
我查看了WWDC 2012幻灯片中的会话202,228和232,并没有找到答案。
我在互联网上专门针对此问题看到的唯一问题是http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html,但它没有提供问题的代码,也没有答案。
此用户UIScrollView zooming with Auto Layout已对UIScrollView自动布局问题做出了很多响应,甚至链接到git hub上的代码,但我找不到任何可以解决此问题的内容。
我试图将这个问题降到最低限度,以便明确。
我使用故事板创建了一个新的单一视图应用程序,并且未在界面构建器中进行任何更改。
我在项目“pic.jpg”中添加了一个大图片文件。
SVFViewController.h
#import <UIKit/UIKit.h>
@interface SVFViewController : UIViewController <UIScrollViewDelegate>
@property (nonatomic) UIImageView *imageViewPointer;
@end
SVFViewController.m
#import "SVFViewController.h"
@interface SVFViewController ()
@end
@implementation SVFViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIScrollView *scrollView = [[UIScrollView alloc] init];
UIImageView *imageView = [[UIImageView alloc] init];
[imageView setImage:[UIImage imageNamed:@"pic.jpg"]];
[self.view addSubview:scrollView];
[scrollView addSubview:imageView];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.imageViewPointer = imageView;
scrollView.maximumZoomScale = 2;
scrollView.minimumZoomScale = .5;
scrollView.delegate = self;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView,imageView);
NSLog(@"Current views dictionary: %@", viewsDictionary);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
}
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return self.imageViewPointer;
}
@end
请注意,我特别努力使其与iOS 6发行说明中提供的示例代码非常相似,只是尽量减少实现缩放。
那么,问题呢?
当您运行此应用程序并在滚动视图中平移时,一切都很好。但是当你缩放问题很明显时,图像来回闪烁,每次缩放时图像在滚动视图中的位置都会出错。
看起来像是对于imageView的内容偏移正在进行战斗,似乎每次“缩放”时它被两个不同的东西设置为不同的值。 (imageView的内容偏移属性的NSLog似乎证实了这一点。)
我在这里做错了什么?有没有人知道如何在纯自动布局环境中的UIScrollView中实现属性缩放。在那里的任何地方都有这样的例子吗?
请帮忙。
答案 0 :(得分:14)
再次重读iOS SDK 6.0 release notes我发现:
请注意,您可以通过在视图和滚动视图子树外部的视图之间创建约束(例如滚动视图的超级视图),使滚动视图的子视图显示为浮动(不滚动)其他滚动内容。
将子视图连接到外部视图。换句话说,就是嵌入了scrollview的视图。
以下列方式应用约束我已经开始工作了:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView(width)]" options:0 metrics:@{@"width":@(self.imageViewPointer.image.size.width)} views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(height)]" options:0 metrics:@{@"height":@(self.imageViewPointer.image.size.height)} views:viewsDictionary]];
答案 1 :(得分:10)
出现的问题是在缩放过程中更改imageview的位置。在缩放过程中,imageview的原点位置将变为负值。我相信这就是为什么会发生生涩的运动。同样,在缩放完成后,imageView仍然位于错误的位置,这意味着滚动将显示为偏移。
如果您实施-(void) scrollViewDidZoom:(UIScrollView *)scrollView
并在此期间记录UIImageView的框架,您可以看到其原点发生变化。
我最终通过实施像this
这样的策略来解决问题另外在缩放时更改contentView的框架
-(void) scrollViewDidZoom:(UIScrollView *)scrollView {
CGRect cFrame = self.contentView.frame;
cFrame.origin = CGPointZero;
self.contentView.frame = cFrame;
}
答案 2 :(得分:3)
这些解决方案都有点工作。以下是我所做的,不需要黑客或子类,使用此设置:
[view]
[scrollView]
[container]
[imageView]
[imageView2]
scrollView
的顶部,前导,底部和尾部连接到view
。container
的顶部,前导,底部和尾部连接到scrollView
。container
的center-x和center-y连接到scrollView
的center-x和center-y,并在构建时将其标记为 remove 即可。这只需要消除IB中的警告。viewForZoomingInScrollView:
,它应该是scrollView的委托,并从该方法返回container
。设置imageView
的图像时,确定最小缩放比例(现在它将以原始尺寸显示)并设置它:
CGSize mySize = self.view.bounds.size;
CGSize imgSize = _imageView.image.size;
CGFloat scale = fminf(mySize.width / imgSize.width,
mySize.height / imgSize.height);
_scrollView.minimumZoomScale = scale;
_scrollView.zoomScale = scale;
_scrollView.maximumZoomScale = 4 * scale;
这适用于我,在设置图像时缩放滚动视图以显示整个图像,并允许放大到初始尺寸的4倍。
答案 3 :(得分:1)
假设您在“UIImageView
”内的“UIScrollView
”内的故事板“UIView
”中有所说明。
将“UIScrollView
”中的所有约束与视图控制器+ UIView(Horizontal Space - Scroll View - View
&amp; Horizontal Space - Scroll View - View
)中的两个约束相关联。
为“UIScrollView
”设置视图控制器AS委托。
然后实现此代码:
@interface VC () <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray* constraints;
@end
@implementation FamilyTreeImageVC
- (void)viewDidLoad {
[super viewDidLoad];
[self.scrollView removeConstraints:self.constraints];
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
-(void) scrollViewDidZoom:(UIScrollView *)scrollView {
CGRect cFrame = self.imageView.frame;
cFrame.origin = CGPointZero;
self.imageView.frame = cFrame;
}
答案 4 :(得分:0)
尝试使用scrollView从故事板项目实现缩放时遇到了同样的问题。
我通过添加一个单独的捏手势识别器来修复它。我只是将它从工具箱拖到我的场景中。然后我将它连接到一个名为“doPinch”的动作,它实现了缩放。我把它连接到一个叫做“pinchRecognizer”的插座,以便我可以访问它的scale属性。这似乎覆盖了scrollView的内置缩放,跳跃消失了。也许它不会在起源上犯同样的错误,或者处理得更优雅。在IB的布局上,这是非常少的工作。
一旦将捏合手势识别器引入场景,您就需要动作和viewForZoomingInScrollView方法。错过任何一个,缩放停止工作。
我的视图控制器中的代码是:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.zoomableImage;
}
- (IBAction)doPinch:(id)sender
{
NSLog(@"In the pinch action now with scale: %f", self.pinchRecognizer.scale);
[scrollView setZoomScale:self.pinchRecognizer.scale animated:NO];
}
这个非常基本的实现确实有副作用:当你回到缩放的图像并缩放更多时,scale的值是1.0f,所以它会跳回到原始的比例。
您可以通过引入属性“currentScale”来对其进行排序,以跟踪比例并在再次开始缩放时设置捏合手势识别器比例。您需要使用手势识别器的状态属性:
- (IBAction)doPinch:(id)sender
{
NSLog(@"In the pinch action now with scale: %f", self.pinchRecognizer.scale);
NSLog(@"Gesture recognizer state is: %d", self.pinchRecognizer.state);
switch (self.pinchRecognizer.state)
{
case 1:
NSLog(@"Zoom begins, with current scale set to: %f", self.currentScale);
[self.pinchRecognizer setScale:self.currentScale];
break;
case 3:
NSLog(@"Zoom ends, with pinch recognizer scale set to: %f", self.pinchRecognizer.scale);
self.currentScale = self.pinchRecognizer.scale;
default:
break;
}
[scrollView setZoomScale:self.pinchRecognizer.scale animated:NO];
}
答案 5 :(得分:0)
所以这就是我设法解决的问题。
以下是我的更改原件:
@interface ScrollViewZoomTestViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIImageView* imageViewPointer;
// These properties are new
@property (nonatomic, strong) NSMutableArray* imageViewConstraints;
@property (nonatomic) BOOL imageViewConstraintsNeedUpdating;
@property (nonatomic, strong) UIScrollView* scrollViewPointer;
@end
@implementation ScrollViewZoomTestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] init];
UIImageView *imageView = [[UIImageView alloc] init];
[imageView setImage:[UIImage imageNamed:@"pic.jpg"]];
[self.view addSubview:scrollView];
[scrollView addSubview:imageView];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.imageViewPointer = imageView;
// New
self.scrollViewPointer = scrollView;
scrollView.maximumZoomScale = 2;
scrollView.minimumZoomScale = .5;
scrollView.delegate = self;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView, imageView);
NSLog(@"Current views dictionary: %@", viewsDictionary);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
// Saving the image view width & height constraints
self.imageViewConstraints = [[NSMutableArray alloc] init];
// Constrain the image view to be the same width & height of the scroll view
[_imageViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView(scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
[_imageViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
// Add the image view constraints to the VIEW, not the scroll view
[self.view addConstraints:_imageViewConstraints];
// Flag
self.imageViewConstraintsNeedUpdating = YES;
}
所以回顾一下,我将所有约束添加到self.view中,保存UIImageView
属性中NSMutableArray
上设置的约束,并设置UIImageView
的标记{1}}约束需要更新。
UIImageView
上的这些初始约束可以将其设置为开头。宽度和宽度相同。高度为UIScrollView
。但是,这个WON&#T; T允许我们缩放图像视图。它将保持与滚动视图相同的width
/ height
。不是我们想要的。这就是我保存约束和设置标志的原因。我们会在一分钟内处理好这件事。
现在,设置缩放视图:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageViewPointer;
}
好的,现在我们需要实际允许我们缩放。我删除了最初的UIImageView
约束并添加了一些新约束,这次限制为UIScrollView
contentSize
width
&amp; height
:
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
if(_imageViewConstraintsNeedUpdating)
{
// Remove the previous image view constraints
[self.view removeConstraints:_imageViewConstraints];
// Replace them with new ones, this time constraining against the `width` & `height` of the scroll view's content, not the scroll view itself
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_scrollViewPointer, _imageViewPointer);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageViewPointer(width)]|" options:0 metrics:@{@"width" : @(_scrollViewPointer.contentSize.width)} views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageViewPointer(height)]|" options:0 metrics:@{@"height" : @(_scrollViewPointer.contentSize.height)} views:viewsDictionary]];
self.imageViewConstraintsNeedUpdating = NO;
}
}
@end
我们无法在-viewDidLoad
中设置这样的约束,因为图片尚未呈现到UIImageView
,所以UIScrollView
&#39; s contentSize
将为{0,0}
。
对我来说这看起来很糟糕,但它确实有效,它确实使用了纯自动布局,而且我找不到更好的方法来做到这一点。在我看来,Apple需要提供更好的方式来缩放UIScrollView
中的内容并使用自动布局约束。