20

の中にグラフが描かれていUIScrollViewます。UIViewこれは、のカスタムサブクラスをCATiledLayerレイヤーとして使用する大きなものです。

をズームインおよびズームアウトするときにUIScrollView、からグラフを返すときと同じように、グラフのサイズを動的に変更する必要がありますviewForZoomingInScrollView。ただし、グラフは新しいズームレベルで再描画されるため、次にユーザーがズームしたときに現在のビューから変換が開始されるように、変換スケールを1x1にリセットしたいと思います。で変換をIdentityにリセットするscrollViewDidEndZoomingと、シミュレーターでは機能しEXC_BAD_ACCSESますが、デバイスにをスローします。

これは、シミュレーターでも問題を完全に解決するわけではありません。次にユーザーがズームすると、トランスフォームがズームレベルにリセットされるため、たとえば2倍にズームした場合のように見えます。突然4倍になります。ズームを終了すると、正しい縮尺になりますが、実際のズーム動作は悪く見えます。

まず、ズーム後にグラフを標準スケールの1x1で再描画するにはどうすればよいですか。また、全体をスムーズにズームするにはどうすればよいですか。

編集:新しい調査結果エラーは「[CALayer retainCount]: message sent to deallocated instance」のようです

自分でレイヤーの割り当てを解除することはありません。以前は、ビューなどを削除することすらしていませんでした。このエラーは、ズームと回転でスローされていました。回転する前にオブジェクトを削除し、後で再度追加しても、例外はスローされません。これはズームのオプションではありません。

4

7 に答える 7

44

コード内のどこかでビューまたはレイヤーを意図せずに自動リリースしていないことを確認するように指示する以外は、クラッシュの処理を支援することはできません。シミュレーターが自動リリースのタイミングをデバイスとは異なる方法で処理するのを見てきました(ほとんどの場合、スレッドが関係している場合)。

ただし、ビューのスケーリングはUIScrollView私が遭遇した問題です。ピンチズームイベント中に、 delegateメソッドでUIScrollView指定したビューを取得し、それに変換を適用します。viewForZoomingInScrollView:この変換により、フレームごとにビューを再描画することなく、ビューをスムーズにスケーリングできます。ズーム操作の最後に、デリゲートメソッドscrollViewDidEndZooming:withView:atScale:が呼び出され、新しい倍率でビューのより高品質なレンダリングを実行する機会が与えられます。通常、ビューの変換をリセットしてから、ビューをCGAffineTransformIdentity新しいサイズスケールで手動で再描画することをお勧めします。

UIScrollViewただし、コンテンツビューの変換を監視していないように見えるため、これにより問題が発生します。次のズーム操作で、コンテンツビューの変換が全体的な倍率に設定されます。最後の倍率でビューを手動で再描画したため、表示されているスケーリングが複雑になります。

回避策として、次のメソッドを定義して、コンテンツビューにUIViewサブクラスを使用します。

- (void)setTransformWithoutScaling:(CGAffineTransform)newTransform;
{
    [super setTransform:newTransform];
}

- (void)setTransform:(CGAffineTransform)newValue;
{
    [super setTransform:CGAffineTransformScale(newValue, 1.0f / previousScale, 1.0f / previousScale)];
}

ここで、previousScaleはビューのfloatインスタンス変数です。次に、ズームデリゲートメソッドを次のように実装します。

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
{
    [contentView setTransformWithoutScaling:CGAffineTransformIdentity];
// Code to manually redraw view at new scale here
    contentView.previousScale = scale;
    scrollView.contentSize = contentView.frame.size;
}

これにより、コンテンツビューに送信される変換は、ビューが最後に再描画されたスケールに基づいて調整されます。ピンチズームが完了すると、通常のsetTransform:方法で調整をバイパスすることにより、変換が1.0のスケールにリセットされます。これにより、ズームの完了時に鮮明なビューを描画しながら、正しいスケーリング動作が提供されるようです。

更新(2010年7月23日):iPhone OS 3.2以降では、ズームに関するスクロールビューの動作が変更されました。これで、UIScrollViewはコンテンツビューに適用するID変換を尊重し、の相対的な倍率のみを提供し-scrollViewDidEndZooming:withView:atScale:ます。したがって、UIViewサブクラスの上記のコードは、3.2より古いバージョンのiPhoneOSを実行しているデバイスにのみ必要です。

于 2009-01-16T19:29:19.393 に答える
14

以前のすべての回答に感謝します。これが私の解決策です。UIScrollViewDelegateメソッドを
実装します。

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return tmv;
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    CGPoint contentOffset = [tmvScrollView contentOffset];   
    CGSize  contentSize   = [tmvScrollView contentSize];
     CGSize  containerSize = [tmv frame].size;

    tmvScrollView.maximumZoomScale = tmvScrollView.maximumZoomScale / scale;
    tmvScrollView.minimumZoomScale = tmvScrollView.minimumZoomScale / scale;

    previousScale *= scale;

    [tmvScrollView setZoomScale:1.0f];

    [tmvScrollView setContentOffset:contentOffset];
    [tmvScrollView setContentSize:contentSize];
    [tmv setFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];  

    [tmv reloadData];
}
  • tmvは UIView のサブクラスです
  • tmvScrollView — UIScrollView へのアウトレット
  • maximumZoomScaleminimumZoomScaleを前に設定する
  • previousScaleインスタンス変数を作成し、その値を 1.0f に設定します

私にとって完璧に機能します。

BR、ユージーン。

于 2011-08-02T16:33:33.377 に答える
10

ロード時にデフォルトのズームスケールにリセットしようとしていました。ズームすると、スクロールビューは割り当てが解除されるまで次回も同じズームスケールになるためです。

-(void) viewWillAppear:(BOOL)animated {
      [self.scrollView setZoomScale:1.0f];
}

ゲームを変更しました。

于 2015-06-03T06:53:00.010 に答える
5

UIScrollViewズームがどのように(そしてなぜ)機能するかについての詳細な議論がgithub.com/andreyvit/ScrollingMadness/にあります。

(このリンクには、UIScrollViewをプログラムでズームする方法、フォトライブラリスタイルのページング+ズーム+スクロールをエミュレートする方法、サンプルプロジェクト、およびズームの魔法の一部をカプセル化するZoomScrollViewクラスの説明も含まれています。)

引用:

UIScrollViewには、「現在のズームレベル」の概念がありません。これは、UIScrollViewに含まれる各サブビューに、独自の現在のズームレベルがある場合があるためです。UIScrollViewには、現在のズームレベルを維持するためのフィールドがないことに注意してください。ただし、誰かがそのズームレベルを保存していることはわかっています。サブビューをピンチズームし、その変換をCGAffineTransformIdentityにリセットしてからもう一度ピンチすると、サブビューの以前のズームレベルが復元されたことがわかります。

実際、逆アセンブリを見ると、独自のズームレベル(_gestureInfoフィールドが指すUIGestureInfoオブジェクト内)を格納するのはUIViewです。また、やのような文書化されていない優れたメソッドのセットもzoomScaleありsetZoomScale:animated:ます。(念のために言っておきますが、回転に関連するメソッドもたくさんあります。近いうちに回転ジェスチャのサポートが提供されるようになるかもしれません。)

ただし、ズーム専用の新しいUIViewを作成し、その子として実際のズーム可能なビューを追加する場合は、常にズームレベル1.0から開始します。プログラムによるズームの実装は、このトリックに基づいています。

于 2009-05-07T23:04:08.860 に答える
3

iOS 3.2 および 4.0 以降に適した、かなり信頼性の高い方法は次のとおりです。要求されたスケールでスケーラブル ビュー (スクロール ビューの主なサブビュー) を提供できるように準備する必要があります。次に、scrollViewDidEndZooming:このビューのぼやけた縮尺変換バージョンを削除し、新しい縮尺で描画された新しいビューに置き換えます。

必要になるだろう:

  • 以前のスケールを維持するための ivar。それをoldScaleと呼びましょう

  • viewForZoomingInScrollView:との両方で、スケーラブル ビューを識別する方法scrollViewDidEndZooming:。ここで、タグ (999) を適用します。

  • スケーラブル ビューを作成し、タグを付けて、スクロール ビューに挿入するメソッド (ここでは と呼びますaddNewScalableViewAtScale:)。ビューとそのサブビューまたは描画のサイズを変更し、スクロール ビューの contentSize を一致するようにサイズ変更します。

  • minimumZoomScale および maximumZoomScale の定数。これらが必要なのは、拡大縮小されたビューを詳細なより大きなバージョンに置き換えると、システムは現在のスケールが 1 であると見なすため、ユーザーがビューを縮小して戻すことができるようにする必要があるためです。

非常によく、その後。スクロール ビューを作成するときは、スケール 1.0 でスケーラブル ビューを挿入します。viewDidLoadたとえば、これはあなたの中にあるかもしれません(svはスクロールビューです):

[self addNewScalableViewAtScale: 1.0];
sv.minimumZoomScale = MIN;
sv.maximumZoomScale = MAX;
self->oldScale = 1.0;
sv.delegate = self;

次にscrollViewDidEndZooming:、同じことを行いますが、スケールの変化を補正します:

UIView* v = [sv viewWithTag:999];
[v removeFromSuperview];
CGFloat newscale = scale * self->oldScale;
self->oldScale = newscale;
[self addNewScalableViewAtScale:newscale];
sv.minimumZoomScale = MIN / newscale;
sv.maximumZoomScale = MAX / newscale;
于 2010-11-12T05:33:14.393 に答える
2

ただし、Brad が提供する解決策には 1 つの問題があることに注意してください。プログラムでズームインし続け (たとえば、ダブルタップ イベントで)、ユーザーが手動で (ピンチアウトして) ズームアウトすると、しばらくすると実際のスケールとスケールの差が生じます。 UIScrollView の追跡は大きくなりすぎるため、previousScaleある時点で float の精度から外れ、最終的に予測不能な動作が発生します。

于 2009-07-28T03:43:41.040 に答える