覆盖UIScrollView缩放的“位图缩放”效果

时间:2012-11-14 13:33:00

标签: ios cocoa-touch uiscrollview uikit

在我的iPad应用程序Universal Combat Log(新布局分支)中,我有一个UIView子类(UCLLineChartView),它包含一个UIScrollView,而scrollview又包含另一个UIView子类(ChartView)。 ChartView有多个子图层,每个子图层对应于已添加到图表的每行数据。 UCLLineChartView绘制轴和标记。这些视图/图层的内容完全是自定义绘制的,没有使用库存视图(例如UIImageView)。

我遇到缩放问题 - 它将ChartView缩放为图像,这使得绘制的线条变得模糊和拉伸。我希望线条保持清晰,最好是在用户进行缩放时,但是经过3天的黑客攻击后,我无法让它工作。

如果我覆盖ChartView上的setTransform以从变换中获取比例因子但不调用[super setTransform],则scrollview的zoomScale保持为1.我尝试保留给定的变换并覆盖transform方法以返回它。我尝试通过更改ChartView的中心和边界来复制setTransform的效果但是我无法使行为完全正确并且它似乎仍然没有影响scrollview的zoomScale。似乎scrollview的zoomScale取决于setTransform的效果,但我无法确定如何。

非常感谢任何协助。

2 个答案:

答案 0 :(得分:1)

您需要做的是更新chartView的contentScaleFactor。您可以通过在scrollViewDidEndZooming:withView:atScale:scrollViewDidZoom:中添加以下代码来实现此目的。

CGFloat newScale = scrollView.zoomScale * [[UIScreen mainScreen] scale];
[self.chartView setContentScaleFactor:newScale];

答案 1 :(得分:0)

我已经找到了一个解决我的问题的方法,这个解决方案并不太严重。在您的UIScrollViewDelegate中:

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
    [_contentView beginZoom];
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    CGSize size = scrollView.bounds.size;
    CGPoint contentOffset = _scrollView.contentOffset;

    CGFloat newScale = _contentView.scale;
    newScale = MAX(newScale, kMinZoomScale);
    newScale = MIN(newScale, kMaxZoomScale);

    [_scrollView setZoomScale:1.0 animated:NO];
    _scrollView.minimumZoomScale = kMinZoomScale / newScale;
    _scrollView.maximumZoomScale = kMaxZoomScale / newScale;

    _contentView.scale = newScale;

    CGSize newContentSize = CGSizeMake(size.width * newScale, size.height);

    _contentView.frame = CGRectMake(0, 0, newContentSize.width, newContentSize.height);
    _scrollView.contentSize = newContentSize;

    [_scrollView setContentOffset:contentOffset animated:NO];

    [_contentView updateForNewSize];
    [_contentView setNeedsDisplay];
}

在内容视图中,声明一个scale属性和以下方法:

- (void)beginZoom
{
    _sizeAtZoomStart = CGSizeApplyAffineTransform(self.frame.size, CGAffineTransformMakeScale(1/self.scale, 1));
    _scaleAtZoomStart = self.scale;
}

- (void)setTransform:(CGAffineTransform)transform
{
    self.scale = _scaleAtZoomStart * transform.a;
    self.frame = CGRectMake(0, 0, _sizeAtZoomStart.width * self.scale, _sizeAtZoomStart.height);

    [self updateForNewSize];
    [self setNeedsDisplay];
}

如果您的内容视图使用子图层,则需要通过将以下内容添加到子图层的委托来禁用其隐式动画:

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
    // prevent animation of the individual layers so that zooming doesn't cause weird jitter
    return (id<CAAction>)[NSNull null];
}

这里的基本思想是被覆盖的setTransform使用转换矩阵中的比例因子来计算内容视图的新比例因子,然后相应地调整内容视图的大小。 scrollview会自动调整内容偏移量以使内容视图居中。

scrollViewDidEndZooming代码保持缩放范围。

例如,在旋转设备时,处理调整滚动视图的大小还有其他复杂性。