1

In my iPad app, Universal Combat Log (new-layout branch), I have a UIView subclass (UCLLineChartView) which contains a UIScrollView and the scrollview in turn contains another UIView subclass (ChartView). ChartView has multiple sub-layers, one for each line of data that has been added to the chart. UCLLineChartView draws the axes and markers. The contents of these views/layers are entirely custom drawn, no stock views are used (e.g. UIImageView).

I'm having a problem with zooming -- it's scaling the ChartView like an image, which makes the drawn line all blurred and stretched. I want the line to stay sharp, preferably even while the user is in the act of zooming, but after 3 days of hacking at this, I cannot get it to work.

If I override setTransform on the ChartView to grab the scale factor from the transform but don't call [super setTransform], then the scrollview's zoomScale stays at 1. I tried keeping the given transform and overriding the transform method to return it. I tried replicating the effects of setTransform by changing the ChartView's center and bounds but I wasn't able to get the behaviour quite right and it still didn't seem to affect the scrollview's zoomScale. It seems that the scrollview's zoomScale depends on the effects of setTransform, but I cannot determine how.

Any assistance would be greatly appreciated.

4

2 に答える 2

1

あなたがする必要があるのcontentScaleFactorは、chartView の更新です。scrollViewDidEndZooming:withView:atScale:または のいずれか に次のコードを追加することで、これを行うことができますscrollViewDidZoom:

CGFloat newScale = scrollView.zoomScale * [[UIScreen mainScreen] scale];
[self.chartView setContentScaleFactor:newScale];
于 2012-11-14T15:44:01.383 に答える
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 が変換行列の倍率を使用してコンテンツ ビューの新しい倍率を計算し、それに応じてコンテンツ ビューのサイズを変更するというものです。スクロールビューはコンテンツ オフセットを自動的に調整して、コンテンツ ビューを中央に維持します。

scrollViewDidEndZooming コードは、ズームを制限したままにします。

たとえば、デバイスを回転させるときのスクロールビューのサイズ変更を処理するには、さらに複雑な作業があります。

于 2012-11-16T05:39:22.230 に答える