【问题标题】:Zoom unscaled views in UIScrollView to bounds将 UIScrollView 中的未缩放视图缩放到边界
【发布时间】:2019-10-02 07:43:24
【问题描述】:

我需要将灰色视图内的红色视图缩放到滚动视图内的给定红色边界(在本例中,滚动视图边界取决于给定的宽度/高度比),同时保持视图可见大小不变。他们还应该始终触摸绿色边框。

我尝试在此视图上使用缩放变换来实现这一点,以便在向上缩放滚动视图时我使用公式1 / zoomScale 缩小此视图并更改它们的锚点以使其保持在绿色边框。

问题是在所有这些操作之后,我不知道如何计算红色视图的目标边界矩形,因此我可以使用适当的 zoomScale 滚动到它。

Please see full demo project here

编辑

灰色视图可能会缩小滚动视图边框(见上图),主要是适合红色视图包围的绿色矩形(您可能会将它们视为绿色区域的负插图)在滚动视图边界内,所以我们实际上应该考虑绿色矩形的初始和结束大小来计算,红色视图应该被“固定”到。

基本方法

- (void)adjustScrollPositionAndZoomToFrame:(CGRect)frame
{
    CGFloat viewWidth = frame.size.width;
    CGFloat viewHeight = frame.size.height;

    CGFloat scrollViewWidth = self.scrollView.frame.size.width;
    CGFloat scrollViewHeight = self.scrollView.frame.size.height;

    CGSize newSize = [self scaleSize:frame.size toHeight:scrollViewHeight];

    if (newSize.width > scrollViewWidth) {
        newSize = [self scaleSize:frame.size toWidth:scrollViewWidth];
    }

    CGFloat scaleFactor = newSize.height == scrollViewHeight
        ? scrollViewHeight / viewHeight
        : scrollViewWidth / viewWidth;

    [self scrollRect:frame toCenterInScrollView:self.scrollView animated:NO];

    self.scrollView.zoomScale = scaleFactor;
}

缩放

- (void)handleZoom:(CGFloat)zoom
{
    NSArray *anchorPoints = @[[NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 1.0)],

                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 0.5)],

                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)]
                              ];

    for (UILabel *label in _labels) {
        [self setViewAnchorPoint:label value:[anchorPoints[[_labels indexOfObject:label]] CGPointValue]];
        label.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1 / zoom, 1 / zoom);
    }
}

/**
 * @see https://stackoverflow.com/a/9649399/3004003
 * @param value See view.layer.anchorPoint
 */
- (void)setViewAnchorPoint:(UIView *)view value:(CGPoint)value
{
    CGPoint newPoint = CGPointMake(view.bounds.size.width * value.x,
                                   view.bounds.size.height * value.y);
    CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
                                   view.bounds.size.height * view.layer.anchorPoint.y);

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);

    CGPoint position = view.layer.position;

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    view.layer.position = position;
    view.layer.anchorPoint = value;
}

缩放前的初始场景:

缩放后的效果:

缩放后我需要什么:

【问题讨论】:

    标签: objective-c algorithm uiscrollview cgaffinetransform


    【解决方案1】:

    我下载了你的项目,发现如下问题:

    当您初始化zoomingView 时,您设置其框架的原点,以便zoomingView 位于scrollView 的中间。当您然后缩放scrollView 时,它也会缩放到原点的偏移量,必须考虑到正确放置缩放的zoomingView

    我认为如果将原点设置为0会更清楚:

    self.zoomingView = [[ZoomingView alloc] initWithFrame:CGRectMake(0, 0, kZoomingViewWidth, kZoomingViewHeight)];
    

    缩放zoomingView 后,您必须将其居中。这可以做到,例如由

    self.scrollView.zoomScale = scaleFactor;
        CGRect svb = self.scrollView.bounds;
        CGRect zvf = self.zoomingView.frame;
        self.scrollView.bounds = CGRectMake((zvf.size.width - svb.size.width)/2.0, (zvf.size.height - svb.size.height)/2.0, svb.size.width, svb.size.height);
    

    那么下面的函数就变得很简单了:

    - (void)scrollViewDidZoom:(UIScrollView *)scrollView
    {
       [self.zoomingView handleZoom:scrollView.zoomScale];
    }
    

    通过这些修改,缩放的zoomingView 正确居中。

    但是,缩放因子仍然是错误的,因为内部绿色矩形被缩放以填充可用空间。原因是必须考虑另外两个大小为 30 的框必须是可见的,即缩放的可用空间更小。这可以做到,例如由

    CGFloat scaleFactor = newSize.height == scrollViewHeight
        ? (scrollViewHeight - 60.0) / viewHeight
        : (scrollViewWidth - 60.0) / viewWidth;
    

    当然,常量必须在以后被变量替换。

    通过这些修改,您的代码对我来说可以正常运行。

    还有一件事:This excellent post 详细讨论了滚动视图。

    【讨论】:

    • 非常感谢!考虑到盒子大小的比例因子计算部分是我真正错过的部分。
    • 很高兴能帮上忙!
    【解决方案2】:

    如果将锚点更改为值会怎样:

    NSArray *anchorPoints = @[[NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.0)],
                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.0)],
    
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)],
                              [NSValue valueWithCGPoint:CGPointMake(1.0, 0.5)],
    
                              [NSValue valueWithCGPoint:CGPointMake(0.0, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(0.5, 1.0)],
                              [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)]
                              ];
    

    因此,您将视图调整到缩放视图的边缘并得到您想要的:

    【讨论】:

    • 不是我想要的,请看我的编辑。我还对测试存储库做了一些新的提交。
    猜你喜欢
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多