38

厳密な自動レイアウト環境を使用した UIScrollView でのズームは機能していないようです。

iOS 6 のリリース ノートでは、ここで「Pure Auto Layout アプローチ」について書いたとき、そうすべきだと確信するようになったので、これは特にイライラしますhttp://developer.apple.com/library/ios/#releasenotes/General/RN- iOSSDK-6_0/_index.html

WWDC 2012 のセッション 202、228、および 232 のスライドを見ましたが、これに対する回答はありませんでした。

この問題について特にインターネットで見た唯一の質問は、 Auto Layoutを使用した UIScrollView zooming ですが、問題のコードは提供されておらず、答えもありません。

このユーザーhttps://stackoverflow.com/users/341994/mattは UIScrollView autolayout の質問に多くの素晴らしい回答をしており、git ハブのコードにもリンクされていますが、この問題に答えるものを見つけることができませんでした。

明確にするために、この問題を最小限に抑えようとしました。

ストーリーボードを使用して新しいシングル ビュー アプリケーションを作成し、インターフェイス ビルダーを変更しませんでした。

プロジェクト「pic.jpg」に大きな画像ファイルを追加しました。

SVFViewController.h

#import <UIKit/UIKit.h> 
@interface SVFViewController : UIViewController <UIScrollViewDelegate>
@property (nonatomic) UIImageView *imageViewPointer;
@end

SVFViewController.m

#import "SVFViewController.h"

@interface SVFViewController ()

@end

@implementation SVFViewController


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    UIImageView *imageView = [[UIImageView alloc] init];
    [imageView setImage:[UIImage imageNamed:@"pic.jpg"]];
    [self.view addSubview:scrollView];
    [scrollView addSubview:imageView];

    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    self.imageViewPointer = imageView;
    scrollView.maximumZoomScale = 2;
    scrollView.minimumZoomScale = .5;
    scrollView.delegate = self;

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView,imageView);
    NSLog(@"Current views dictionary: %@", viewsDictionary);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
}

-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return self.imageViewPointer;
}

@end

iOS 6 リリース ノートで提供されているサンプル コードと同じように、ズームを実装するための最小限の処理を行っていることに注意してください。

それで、問題は?

このアプリケーションを実行してスクロール ビューをパンすると、すべてがうまくいきます。しかし、ズームすると問題は明らかで、画像が前後にちらつき、ズームするたびにスクロール ビュー内の画像の位置がさらにずれます。

imageView のコンテンツ オフセットをめぐって戦闘が行われているようです。「ズーム」ごとに 2 つの異なるものによって異なる値に設定されているようです。(これを確認するために、imageView のコンテンツ オフセット プロパティの NSLog が表示されます)。

ここで何が間違っていますか?純粋な自動レイアウト環境で UIScrollView 内でズームをプロパティ実装する方法を知っている人はいますか? この例はどこかにありますか?

助けてください。

4

6 に答える 6

10

発生する問題は、ズーム プロセス中にイメージビューの位置が変わることです。イメージビューの原点位置は、ズーム中に負の値に変更されます。これがぎくしゃくした動きが発生する理由だと思います。同様に、ズームが完了した後、imageView はまだ間違った場所にあるため、スクロールがずれているように見えます。

-(void) scrollViewDidZoom:(UIScrollView *)scrollViewこの間に UIImageView のフレームを実装してログに記録すると、元の変更が表示されます。

このような戦略を実行することで、物事がうまくいくようになりました

さらに、ズーム中に contentView のフレームを変更する

-(void) scrollViewDidZoom:(UIScrollView *)scrollView {
    CGRect cFrame = self.contentView.frame;
    cFrame.origin = CGPointZero;
    self.contentView.frame = cFrame;
}
于 2013-03-18T04:40:18.147 に答える
4

これらのソリューションはすべてうまくいきます。このセットアップで、ハックやサブクラスは必要ありません。

[view]
  [scrollView]
    [container]
      [imageView]
      [imageView2]
  1. IB では、 to のトップ、リーディング、ボトム、トレーリングを接続scrollViewviewます。
  2. のトップ、リーディング、ボトム、トレーリングをフックしcontainerますscrollView
  3. center-x と center-ycontainerを center-x と center-y に接続し、ビルド時に removescrollView としてマークします。これは、IB の警告を黙らせるためにのみ必要です。
  4. viewForZoomingInScrollView:scrollView のデリゲートである必要があるビュー コントローラーに実装し、そのメソッドから return を実装しcontainerます。
  5. の画像を設定するときはimageView、最小ズーム スケールを決定し (現在はネイティブ サイズで表示されます)、次のように設定します。

    CGSize mySize = self.view.bounds.size;
    CGSize imgSize = _imageView.image.size;
    CGFloat scale = fminf(mySize.width / imgSize.width,
                          mySize.height / imgSize.height);
    _scrollView.minimumZoomScale = scale;
    _scrollView.zoomScale = scale;
    _scrollView.maximumZoomScale = 4 * scale;
    

これは私にとってはうまくいきます。画像を設定すると、スクロールビューがズームされて画像全体が表示され、初期サイズの4倍にズームインできます。

于 2014-01-06T10:23:43.117 に答える
0

それで、これが私がうまくいくことができたものです。

ここに私の変更を加えたオリジナルがあります:

@interface ScrollViewZoomTestViewController () <UIScrollViewDelegate>

@property (nonatomic, strong) UIImageView* imageViewPointer;

// These properties are new
@property (nonatomic, strong) NSMutableArray* imageViewConstraints;
@property (nonatomic) BOOL imageViewConstraintsNeedUpdating;
@property (nonatomic, strong) UIScrollView* scrollViewPointer;

@end

@implementation ScrollViewZoomTestViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    UIImageView *imageView = [[UIImageView alloc] init];
    [imageView setImage:[UIImage imageNamed:@"pic.jpg"]];
    [self.view addSubview:scrollView];
    [scrollView addSubview:imageView];

    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    self.imageViewPointer = imageView;
    // New
    self.scrollViewPointer = scrollView;
    scrollView.maximumZoomScale = 2;
    scrollView.minimumZoomScale = .5;
    scrollView.delegate = self;

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView, imageView);
    NSLog(@"Current views dictionary: %@", viewsDictionary);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];

    // Saving the image view width & height constraints
    self.imageViewConstraints = [[NSMutableArray alloc] init];
    // Constrain the image view to be the same width & height of the scroll view
    [_imageViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView(scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
    [_imageViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];

    // Add the image view constraints to the VIEW, not the scroll view
    [self.view addConstraints:_imageViewConstraints];

    // Flag
    self.imageViewConstraintsNeedUpdating = YES;
}

ここで要約すると、すべての制約を self.view に追加しUIImageView、プロパティに設定された制約を保存し、制約の更新が必要なNSMutableArrayフラグを設定しています。UIImageView

これらの最初の制約は、最初UIImageViewに設定する作業です。と同じ幅と高さになりUIScrollViewます。ただし、これでは画像ビューをズームできません。スクロール ビューと同じwidth/維持します。height私たちが望むものではありません。そのため、制約を保存してフラグを設定しています。すぐに処理します。

次に、ズーム用のビューを設定します。

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageViewPointer;
}

では、実際にズームできるようにする必要があります。最初の制約を削除し、いくつかのUIImageView新しい制約を追加します。今回は&に制約します。UIScrollViewcontentSize widthheight

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
    if(_imageViewConstraintsNeedUpdating)
    {
        // Remove the previous image view constraints
        [self.view removeConstraints:_imageViewConstraints];

        // Replace them with new ones, this time constraining against the `width` & `height` of the scroll view's content, not the scroll view itself
        NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_scrollViewPointer, _imageViewPointer);
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imageViewPointer(width)]|" options:0 metrics:@{@"width" : @(_scrollViewPointer.contentSize.width)} views:viewsDictionary]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageViewPointer(height)]|" options:0 metrics:@{@"height" : @(_scrollViewPointer.contentSize.height)} views:viewsDictionary]];

        self.imageViewConstraintsNeedUpdating = NO;
    }
}

@end

-viewDidLoad画像がまだ にレンダリングされていないため、このように制約を設定することはできませUIImageViewん。したがって、は になりUIScrollViewます。contentSize{0,0}

これは私にはかなりハックに思えますが、機能し、純粋な自動レイアウトを使用しており、それを行うためのより良い方法を見つけることができません. Apple はコンテンツをズームし、UIScrollView自動レイアウト制約を使用するためのより良い方法を提供する必要があるように思えます。

于 2014-04-03T20:50:25.120 に答える