web-dev-qa-db-ja.com

自動レイアウトでUIScrollView内のUIImageViewをズーム

IOS 6と自動レイアウトの前にUIScrollView内にUIImageViewを埋め込んでいますが、コントローラーのviedDidLoadメソッド内で次のスニペットを使用して、スクロール可能でズーム可能な画像を表示しました。

self.scrollView.contentSize = self.imageView.image.size;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);

ただし、ストーリーボードで設定された制約が代わりに使用されるようになりました。私はこの質問を見つけました iOS 6の自動レイアウトでScrollViewにImageViewを埋め込みます そしてここで他のいくつかはSOで、viewDidLoadの後に制約がロード/強制されることを示しています、そしてそれは以前のスニペットをviewDidAppearに移動するとこの問題は解決しますが、ズームが適切に機能せず、ピンチ操作でズームした後、scrollViewとimageViewのサイズがストーリーボードの制約にリセットされるようです。

私は推測しているだけですが、おそらく、機能するコードでscrollViewとimageViewの垂直および水平のスペース制約をオーバーライドする方法があると思います。

この問題を抱えている人は他にいますか?

19
Diego Allen

次のコードサンプルを使用して問題を解決しました。 githubリポジトリは、MattNeuburgによる本ProgrammingiOSに対応しています。

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/11c6c57743b04e6e722b635b87be69fa41a5abaf/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m

7
Diego Allen

最良の解決策は、コメントでZsoltによって提案されました。

http://github.com/evgenyneu/ios-imagescroll これをチェックしてください。私にとっては完璧に機能します。

このリポジトリで提案されている解決策は、画像を表示する前に最小ズームレベルと現在のズームレベルを調整することです。

@interface MyViewController () <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end


@implementation MyViewController

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.scrollView.delegate = self;

  [self initZoom];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
  [self initZoom];
}

// Zoom to show as much image as possible
- (void) initZoom {
  float minZoom = MIN(self.view.bounds.size.width / self.imageView.image.size.width,
                      self.view.bounds.size.height / self.imageView.image.size.height);
  if (minZoom > 1) return;

  self.scrollView.minimumZoomScale = minZoom;

  self.scrollView.zoomScale = minZoom;
}

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

ただし、サンプルのconatinsはズームアウトの問題です。画像が中央に配置されていません。これは、次のコードを含むカスタムスクロールビュークラスを使用することで簡単に修正できます。

@interface MyScrollView : UIScrollView
@end

@implementation MyScrollView

-(void)layoutSubviews
{
  [super layoutSubviews];
  UIView* v = [self.delegate viewForZoomingInScrollView:self];
  CGFloat svw = self.bounds.size.width;
  CGFloat svh = self.bounds.size.height;
  CGFloat vw = v.frame.size.width;
  CGFloat vh = v.frame.size.height;
  CGRect f = v.frame;
  if (vw < svw)
    f.Origin.x = (svw - vw) / 2.0;
  else
    f.Origin.x = 0;
  if (vh < svh)
    f.Origin.y = (svh - vh) / 2.0;
  else
    f.Origin.y = 0;
  v.frame = f;
}

@end
14
Anton Matosov

Zsoltの提案とリンクにも同意します。

ただし、幅/高さの制約を更新して、任意のサイズの画像を処理できるようにします。

- (void) initZoom
{
  for (NSLayoutConstraint *constraint in self.photoImageView.constraints)
  {
    if (constraint.firstAttribute == NSLayoutAttributeWidth)
      constraint.constant = self.photoImageView.image.size.width;
    else if (constraint.firstAttribute == NSLayoutAttributeHeight)
      constraint.constant = self.photoImageView.image.size.height;
  }

  float minZoom = MIN(self.scrollView.bounds.size.width / self.photoImageView.image.size.width,
                      self.scrollView.bounds.size.height / self.photoImageView.image.size.height);
  if (minZoom > 1) return;

  self.scrollView.minimumZoomScale = minZoom;

  self.scrollView.zoomScale = minZoom;
}
5
Mof