我很难弄清楚如何最好地重新定位我的UIScrollView
图像视图(我现在有一个图库类型的应用程序,类似于Photos.app,特别是当您查看单个图像时,方向从纵向切换到横向,反之亦然。
我知道我最好的办法是操纵contentOffset
属性,但我不确定它应该改成什么。
我玩过很多次,似乎无论出于什么原因,128
的效果都很好。在我的视图控制器的viewWillLayoutSubviews
方法中,我有:
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
CGPoint newContentOffset = self.scrollView.contentOffset;
if (newContentOffset.x >= 128) {
newContentOffset.x -= 128.0;
}
else {
newContentOffset.x = 0.0;
}
newContentOffset.y += 128.0;
self.scrollView.contentOffset = newContentOffset;
}
else {
CGPoint newContentOffset = self.scrollView.contentOffset;
if (newContentOffset.y >= 128) {
newContentOffset.y -= 128.0;
}
else {
newContentOffset.y = 0.0;
}
newContentOffset.x += 128.0;
self.scrollView.contentOffset = newContentOffset;
}
它非常好用 。我讨厌它如何使用一个神奇的数字,我不知道它会来自何处。
此外,每当我缩放图像时,我都将其设置为居中(就像Photos.app一样):
- (void)centerScrollViewContent {
// Keep image view centered as user zooms
CGRect newImageViewFrame = self.imageView.frame;
// Center horizontally
if (newImageViewFrame.size.width < CGRectGetWidth(self.scrollView.bounds)) {
newImageViewFrame.origin.x = (CGRectGetWidth(self.scrollView.bounds) - CGRectGetWidth(self.imageView.frame)) / 2;
}
else {
newImageViewFrame.origin.x = 0;
}
// Center vertically
if (newImageViewFrame.size.height < CGRectGetHeight(self.scrollView.bounds)) {
newImageViewFrame.origin.y = (CGRectGetHeight(self.scrollView.bounds) - CGRectGetHeight(self.imageView.frame)) / 2;
}
else {
newImageViewFrame.origin.y = 0;
}
self.imageView.frame = newImageViewFrame;
}
因此我需要它以使其正确定位,以便在重新定位时不会在图像周围显示黑色边框。 (这是第一个代码块中的检查所用的内容。)
基本上,我很好奇如何实现像Photos.app这样的功能,其中旋转滚动视图智能地重新定位内容,以便旋转前可见内容的中间是相同的后旋转,所以它感觉很连续。
答案 0 :(得分:7)
每当scrollView在其UIScrollView
值更改后布置其子视图时,您应该更改contentOffset
的{{1}}属性。然后,当界面方向发生变化时,bounds
的{{1}}会相应更改UIScrollView
。
为了使事情“正确”,您应该将bounds
子类化并在那里进行所有调整。这也可以让您轻松重复使用“特殊”scrollView。
contentOffset
计算函数应放在UIScrollView
的{{1}}方法中。问题是这个方法不仅在contentOffset
值被更改时调用,而且在srollView被缩放或滚动时调用。因此,如果由于方向更改导致UIScrollView
发生更改,或者由于平移或捏合手势而导致调用layoutSubviews
方法,则应跟踪bounds
值。
因此bounds
子类的第一部分应如下所示:
layoutSubviews
此处,每次bounds
平移,缩放或更改UIScrollView
时,都会调用- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Set the prevBoundsSize to the initial bounds, so the first time
// layoutSubviews is called we won't do any contentOffset adjustments
self.prevBoundsSize = self.bounds.size;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (!CGSizeEqualToSize(self.prevBoundsSize, self.bounds.size)) {
[self _adjustContentOffset];
self.prevBoundsSize = self.bounds.size;
}
[self _centerScrollViewContent];
}
方法。 layoutSubviews
方法负责在缩放视图的大小小于scrollView边界的大小时使缩放视图居中。并且,每次用户平移或缩放scrollView或旋转设备时都会调用它。它的实现与您在问题中提供的实现非常相似。不同之处在于此方法是在UIScrollView
类的上下文中编写的,因此不使用bounds
属性来引用缩放视图,这可能在_centerScrollViewContent
类的上下文中不可用,使用UIScrollView
委托方法。
self.imageView
但更重要的是UIScrollView
方法。此方法负责调整viewForZoomingInScrollView:
。这样,当- (void)_centerScrollViewContent {
if ([self.delegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) {
UIView *zoomView = [self.delegate viewForZoomingInScrollView:self];
CGRect frame = zoomView.frame;
if (self.contentSize.width < self.bounds.size.width) {
frame.origin.x = roundf((self.bounds.size.width - self.contentSize.width) / 2);
} else {
frame.origin.x = 0;
}
if (self.contentSize.height < self.bounds.size.height) {
frame.origin.y = roundf((self.bounds.size.height - self.contentSize.height) / 2);
} else {
frame.origin.y = 0;
}
zoomView.frame = frame;
}
}
的{{1}}值更改时,更改前的中心点将保持在中心位置。并且由于条件语句,只有在_adjustContentOffset
的{{1}}被更改时才会调用它(例如:方向更改)。
contentOffset
我创建了一个有效的UIScrollView
课程(此处为link to GitHub),以实现上述行为和其他奖励:
bounds
之外,您可能还会发现还要调整scrollView的UIScrollView
。例如,假设您正在以纵向模式查看照片,该照片已缩放以适合屏幕尺寸。然后,当您将设备旋转到横向模式时,您可能希望升级照片以利用可用空间。