自動レイアウトを使用して、UIScrollView
新しい方法 を実装しようとしています。内側のビューからスクロールビューへの制約を設定して、独自のcontentSize
を自動的に計算できるようにしました。これは魅力のように機能します。ただし、ズームインまたはズームアウトしようとすると、すべての地獄が解き放たれます。 。内面が「めちゃくちゃ」になっていると言う以外に、何が起こっているのかを正しく説明することすらできません。
この動作の例を見ることができます ここ (私のプロジェクトではありません。ズームが機能する前に、スクロールビューのmaximumZoomScale
を設定し、-viewForZoomingInScrollView:
を実装する必要があります)。
他の誰かがこの動作に遭遇しましたか?現在、ズーム動作を自分で本質的に再実装せずに、UIScrollView
でズームして自動レイアウトを操作する方法はありますか?
私が見た最良の答えは、ここに投稿されたMarkの( https://stackoverflow.com/users/1051919/mark-kryzhanouski )です: IScrollViewズームは自動レイアウトでは機能しません =。
重要なのは、スクロールビューにネストされている画像ビューをスクロールビューの親に固定する必要があることです。 iOS 6リリースノートのガイダンスにもかかわらず、どのビューが何に対して「フローティング」であるかは私には直感的ではありません。この場合、スクロールビューは単一の画像ビューにすぎません。
私はこれを使って多くの実験を行い、すべてIBのアプローチを見つけたいと思っていましたが、何も見つかりませんでした。 IBでビュー階層を生成することはできますが、プログラムで制約を追加する必要があります。デフォルトの制約の一部またはすべてを削除できますが(主に制約の競合の警告を和らげるため)、画像ビューをスクロールビューの親、つまり画像ビューの祖父母に関連付けるには、常にMarkのコードが必要です。
これよりも単純なはずです-「うまくいくはずです」が:
NSDictionary *viewsDictionary = @{ @"scrollView": self.scrollView, @"imageView": self.imageView };
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|[imageView(width)]"
options:0
metrics:@{@"width": @(self.imageView.image.size.width)}
views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[imageView(height)]"
options:0
metrics:@{@"height": @(self.imageView.image.size.height)}
views:viewsDictionary]];
ストーリーボードにimageViewを追加しなくても、次のことが完全に機能することがわかりました。
-(UIImageView *)imageView
{
if (!_imageView) _imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
return _imageView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.scrollView addSubview:self.imageView];
// Set the min and max:
self.scrollView.minimumZoomScale = 0.2;
self.scrollView.maximumZoomScale = 5.0;
self.scrollView.delegate = self;
// Set the content:
self.scrollView.zoomScale = 1.0; // reset zoomScale for new image
self.scrollView.contentSize = CGSizeMake(image.size.width/2, image.size.height/2);
self.imageView.frame = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
self.imageView.image = image;
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
私が考えることができる最も簡単な例は、UIImageView
をUIScrollView
に追加することです。これは100%コードです。プレイグラウンドにPNGを追加するだけです。私は私のと呼んだImage.png
。プレイグラウンドでは、「ライブビュー」にレンダリングされたすべてのものが表示されます。ピンチズームは、Ctrlキーを押しながらクリックして画面に1本の指を置き、ドラッグすることで機能します。コンテンツが画面よりも大きく拡大されるまで、パンは機能しません。画像をダブルタップして、1倍と3倍のスケールを切り替えます。
Appleの テクニカルノートTN2154に基づく:UIScrollViewとAutolayout
コンテンツが画面サイズより大きくない場合、全体が非常にイライラすることに気付くでしょう。コンテンツが画面に完全に収まる場合、何も起こりません。そのため、ズームも機能させる必要があります。それが機能することを自分自身に証明したい場合は、本当に大きな画像(ウィンドウよりも大きい)でテストしてください。
import UIKit
import PlaygroundSupport
enum TapToggle {
case Regular, Large
}
class ScrollingViewController : UIViewController
{
var tapToggle: TapToggle = .Large
var scrollView: UIScrollView?
var imageView: UIImageView?
override func viewDidLoad()
{
let image = UIImage(named: "Image")
let imageView = UIImageView(image: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .white
imageView.isUserInteractionEnabled = true
let scrollView = UIScrollView()
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 10.0
scrollView.delegate = self
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(imageView)
let imageViewKey = "imageView"
let imageViews = [imageViewKey: imageView]
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(imageViewKey)]|", options: [], metrics: nil, views: imageViews))
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(imageViewKey)]|", options: [], metrics: nil, views: imageViews))
self.imageView = imageView
scrollView.backgroundColor = .white
self.view.addSubview(scrollView)
let scrollViewKey = "scrollView"
let scrollViews = [scrollViewKey: scrollView]
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(scrollViewKey)]|", options: [], metrics: nil, views: scrollViews))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(scrollViewKey)]|", options: [], metrics: nil, views: scrollViews))
self.scrollView = scrollView
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap(sender:)))
tapGesture.numberOfTapsRequired = 2
self.imageView?.addGestureRecognizer(tapGesture)
}
@objc
public func didDoubleTap(sender: AnyObject)
{
switch self.tapToggle {
case .Regular:
self.scrollView?.zoomScale = 1.0
self.tapToggle = .Large
case .Large:
self.scrollView?.zoomScale = 3.0
self.tapToggle = .Regular
}
}
}
extension ScrollingViewController: UIScrollViewDelegate
{
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.imageView
}
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat)
{
print("\(scale)")
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = ScrollingViewController()