質問

UIScrollView内に描画されているグラフがあります。レイヤーとしてUIViewのカスタムサブクラスを使用する1つの大きなCATiledLayerです。

viewForZoomingInScrollViewを拡大および縮小するとき、scrollViewDidEndZoomingからグラフを返すときと同じように、グラフのサイズを動的に変更します。ただし、グラフは新しいズームレベルで自動的に再描画されるため、ユーザーが次にズームするときに現在のビューから変換が開始されるように、変換スケールを1x1にリセットします。 EXC_BAD_ACCSESでトランスフォームをIdentityにリセットすると、シミュレータでは機能しますが、デバイスで[CALayer retainCount]: message sent to deallocated instanceがスローされます。

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

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

編集:新しい調査結果 エラーは<!> quot; <=> <!> quot;

のようです

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

役に立ちましたか?

解決

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

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

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

回避策として、次のメソッドを定義してコンテンツビューに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;
}

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

UPDATE(7/23/2010):iPhone OS 3.2以降では、ズームに関するスクロールビューの動作が変更されました。現在、<=>は、コンテンツビューに適用するID変換を尊重し、<=>で相対的なスケールファクターのみを提供します。したがって、<=>サブクラスの上記のコードは、3.2より古いバージョンのiPhone OSを実行しているデバイスにのみ必要です。

他のヒント

これまでのすべての回答に感謝します。これが私の解決策です。
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 <!>#8212; UIScrollViewへのアウトレット
  • 前に maximumZoomScale minimumZoomScale を設定
  • previousScale インスタンス変数を作成し、その値を1.0fに設定します

完璧に機能します。

BR、ユージーン。

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

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

ゲームを変更しました。

github.com/andreyvit/ScrollingMadness/で、UIScrollViewのズームがどのように(そしてなぜ)機能するかについて詳しく説明しています。

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

引用:

UIScrollViewには<!>#8220; current zoom level <!>#8221;という概念がありません。これには、それに含まれる各サブビューに独自の現在のズームレベルがあるためです。現在のズームレベルを保持するフィールドはUIScrollViewにないことに注意してください。ただし、誰かがそのズームレベルを保存していることがわかります。サブビューをピンチズームしてからその変換をCGAffineTransformIdentityにリセットし、再度ピンチすると、サブビューの前のズームレベルが復元されていることがわかります。

実際に、逆アセンブリを見ると、独自のズームレベル(_gestureInfoフィールドが指すUIGestureInfoオブジェクト内)を格納するのはUIViewです。また、zoomScalesetZoomScale:animated:などのドキュメント化されていない素晴らしいメソッドのセットもあります。 (覚えておいてください、回転関連のメソッドもたくさんあります。おそらく、近いうちに回転ジェスチャをサポートするでしょう。)

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

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

必要なもの:

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

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

  • スケーラブルビューを作成し、タグ付けし、スクロールビューに挿入するメソッド(ここではviewDidLoadと呼びます)。スケールに従ってすべてを実行する必要があることを忘れないでください-ビューとそのサブビューまたは描画のサイズを調整し、スクロールビューのcontentSizeのサイズを一致させます。

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

非常によく。スクロールビューを作成するとき、スケール1.0でスケーラブルビューを挿入します。たとえば、これはsvにあります(<=>はスクロールビューです):

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

その後、<=>で同じことを行いますが、スケールの変更を補正します:

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;

ただし、Bradが提供するソリューションには1つの問題があります。プログラムでズームインを続け(ダブルタップイベントについて)、ユーザーに手動でズームアウト(ピンチアウト)させると、しばらくしてから真のスケールの差がまた、UIScrollViewが追跡しているスケールが大きくなりすぎるため、previousScaleはある時点でフロートの精度から外れ、最終的に予測不可能な動作になります

Swift 4。* および Xcode 9.3

scrollViewズームスケールを0に設定すると、scrollViewが初期状態にリセットされます。

self.scrollView.setZoomScale(0.0, animated: true)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top