滚动,缩放UIScrollView和界面方向旋转。如何使用自动调整大小等更多功能。

4
这应该是一个相当常见的操作,但我一直没能做到完美无缺。
我有矩形内容。它通常适合于320x361:竖屏模式减去状态栏减去广告栏减去标签栏。
我将该内容放入UIScrollView并启用了缩放。我还希望界面旋转可以正常工作。内容始终是一个高矩形,但在缩放时,用户可能希望同时看到更多的宽度和较少的高度。
在Interface Builder和代码中我需要做什么来完成此操作?我应该如何设置不同视图的自动调整大小?如何设置我的contentSize和contentInsets?
我已经尝试了很多种不同的方法,但没有一种方法完全正确。在我的各种解决方案中,我遇到了问题,在某些缩放、界面旋转和滚动的组合后,不再可能将整个内容滚动到屏幕上。在您看到内容的边缘之前,滚动视图会将您弹回。
我现在的做法大约有80%的正确性。也就是说,它应该做10件事情中的8件。它做错的两件事是:
1. 在竖屏模式下缩放时,您可以滚动超过内容的边缘,并看到黑色背景。这也不是太值得抱怨。至少您可以看到所有的内容。在横向模式下,无论是否缩放,看到边缘之外的黑色背景都是正常的,因为内容在1:1缩放级别(最小)下没有足够的宽度来填满屏幕。
2. 当它在运行iOS 3.0的测试设备上运行时,我仍然会遇到内容卡在边缘的情况,但它在我的4.x上运行良好。 - 实际上,这是在先前的解决方案中发生的。我的测试人员还没有尝试最新的解决方案。
这是我目前正在使用的解决方案。总结一下,我使滚动视图宽高适应于任何方向,因为我发现手动或自动调整大小会增加复杂性并变得脆弱。
视图层次结构:
- 视图 - 滚动视图 - 可滚动区域 - 内容 - 广告
视图大小为320x411,并具有所有自动调整大小选项,因此符合屏幕形状。
滚动视图为480 x 361,起始位置为-80,0,并锁定顶部,禁用拉伸。
可滚动区域为480 x 361,锁定左侧和顶部。由于滚动视图禁用了拉伸,其子视图的自动调整大小掩码并不重要,但我还是告诉你。
内容为320x361,起始位置为80,0,并锁定顶部。
我正在设置scrollView.contentSize为480x361。

shouldAutorotateToInterfaceOrientation 支持除了倒立的竖屏外的所有朝向。

didRotateFromInterfaceOrientation 方法中,如果方向是横向,则设置底部内容插入量为 160,否则重置为 0。如果方向是纵向,则将左右指示器插入量各设置为 80,否则重置。

scrollView.minimumZoomScale = 1.0

scrollView.maximumZoomScale = 2.0

viewForZoomingInScrollView返回可滚动区域

4个回答

4
// in IB it would be all options activated
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
scrollView.contentSize = content.frame.size; // or bounds, try both

你所说的scrollableArea是什么意思?

你的minZoomScale被设为1.0,这对于纵向模式来说很好,但对于横向模式就不太适用了。因为在横屏模式下,视图的高度比纵向模式小,所以需要一个比1.0更小的值。我使用以下实现方式,在每次scrollView的frame发生变化时调用它:

- (void)setMaxMinZoomScalesForCurrentBounds {
    CGSize boundsSize = self.bounds.size; // self is a UIScrollView here
    CGSize contentSize = content.bounds.size;

    CGFloat xScale = boundsSize.width / contentSize.width;
    CGFloat yScale = boundsSize.height / contentSize.height;
    CGFloat minScale = MIN(xScale, yScale);

    if (self.zoomScale < minScale) {
        [self setZoomScale:minScale animated:NO];
    }
    if (minScale<self.maximumZoomScale) self.minimumZoomScale = minScale;
    //[self setZoomScale:minScale animated:YES];
}

- (void)setFrame:(CGRect)rect { // again, this class is a UIScrollView
    [super setFrame:rect];
    [self setMaxMinZoomScalesForCurrentBounds];
}

谢谢,看起来很有前途。所以你似乎已经子类化了UIScrollView? - morningstar
scrollableArea只是一个普通的UIView。它除了包含其他的UIView之外什么也不做。它是我的viewForZoomingInScrollView。我需要它在scrollView和content之间,因为我设置了一些有趣的尺寸来使事情大致工作。我还需要它,因为有时除了content之外还会有另一个视图在其中。 - morningstar
我曾考虑过将最小缩放比设置为小于1.0,但实际上在横屏模式下看到内容的全部高度并没有必要,而且两侧会有很多黑色区域。这样一来,界面会变得太小而无法使用。如果您想看到完整的高度,请使用纵向模式。我其实考虑将横屏模式下的最小缩放比设置为1.5或更高,这样内容总是能够至少填满屏幕。 - morningstar
如果contentSize应该是可滚动区域的框架。是的,我已经对其进行了子类化,因为我有一些石英渲染PDF。 - user207616

0

如果我理解正确,您想要一个带有图像的滚动视图。它需要从全屏开始,并且您需要能够放大缩小。除此之外,您还希望它能根据方向旋转。

好吧,我过去一直在进行原型设计,如果上述所有内容都正确,那么以下代码应该适用于您。

我留了一些白色区域用于条形/自定义条形。

- (void)viewDidLoad
{  
    [super viewDidLoad];

    //first inits and allocs
    scrollView2 = [[UIScrollView alloc] initWithFrame:self.view.frame];
    imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImageName"]];
    [scrollView2 addSubview:imageView];
    [self drawContent]; //refreshing the content
    [self.view addSubview:scrollView2];
}

-(void)drawContent
{
    //this refreshes the screen to the right sizes and zoomscales.
    [scrollView2 setBackgroundColor:[UIColor blackColor]];
    [scrollView2 setCanCancelContentTouches:NO];
    scrollView2.clipsToBounds = YES;
    [scrollView2 setDelegate:self];
    scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;

    [scrollView2 setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
    [scrollView2 setScrollEnabled:YES];

    float minZoomScale;
    float zoomHeight = imageView.frame.size.height / scrollView2.frame.size.height;
    float zoomWidth = imageView.frame.size.width / scrollView2.frame.size.width;

    if(zoomWidth > zoomHeight)
    {
        minZoomScale = 1.0 / zoomWidth;
    }
    else
    {
        minZoomScale = 1.0 / zoomHeight;
    }

    [scrollView2 setMinimumZoomScale:minZoomScale];
    [scrollView2 setMaximumZoomScale:7.5];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations

    if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {

        // Portrait 
        //the 88pxls is the white area that is left for the navbar etc.

        self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.width, self.view.frame.size.height - 88);
        [self drawContent];
    }
    else {

        // Landscape
        //the 88pxls is the white area that is left for the navbar etc.

        self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.height, self.view.frame.size.width);
        [self drawContent];
    }
    return YES;
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

我希望这能解决你的问题。如果不能,请留下评论。


0

当您想要将内容(一个UIView实例,我们称之为theViewInstance)放入UIScrollView中,然后在theViewInstance上滚动/缩放时,操作方式如下:

  • 应将theViewInstance作为子视图添加到UIScrollView中。
  • 将委托设置为UIScrollView实例并实现选择器来返回用于缩放/滚动的视图:

    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
        return theViewInstance;
    }
    
  • 默认情况下,应将UIScrollView的内容大小设置为theViewInstance的框架大小:

    scrollView.contentSize = theViewInstance.frame.size;
    

    此外,可以在UIScrollView中设置接受的缩放级别:

    scrollView.minimumZoomScale = 1.0;
    scrollView.maximumZoomScale = 3.0;
    

这是在UIImage上实现捏合缩放的方法:将UIImageView添加到UIScrollView中,在UIScrollViewDelegate实现中,返回UIImageView(例如在此处所述)。

至于旋转支持,则是在包含我们刚刚谈论过的UIScrollView的UIView的UIViewController中完成的。


0

我觉得我没有完全理解你在帖子中提出的问题,但是对于我所理解的部分,这里有一个答案。

据我所知(并且使用过UIScrollView),UIScrollView内部的内容不会随着UIScrollView自动调整大小。

将UIScrollView视为通往另一个宇宙的窗口/门户,在那里您的内容存在。当自动调整UIScrollView时,您只是改变了查看窗口的形状/大小...而不是其他宇宙中内容的大小。

但是,如果需要,您可以拦截旋转事件并手动更改您的内容(使用动画使其看起来很好)。

为了正确自动调整大小,您应该更改scrollView的contentSize(以便它知道您的宇宙的大小),但也要更改UIView的大小。我认为这就是您能够滚动并获得黑色内容的原因。也许您只是更新了contentSize,但现在实际上是内容视图。

个人而言,我没有遇到任何需要随UIScrollView一起调整大小的情况,但我希望这可以让您朝着正确的方向开始。


为了澄清你的回答,这是否意味着打开视图和滚动视图的所有自动调整大小栏,并关闭可滚动区域的所有自动调整大小栏? - morningstar
我尝试了这个方法,并将所有大小设置回正常大小,并删除了我的自定义代码,例如设置内容插图。但是我遇到了一些问题。1 当我旋转到横向时,我的内容很好地居中,但我无法滚动到内容的顶部。2 如果我缩放,然后旋转到横向,我可以访问所有内容,但如果我缩小内容,则不会居中;它在屏幕左侧。3 如果我在横向模式下缩放,然后返回到纵向模式,我无法访问所有内容。通过多个步骤,我甚至将内容完全移出了屏幕。 - morningstar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接