IPhone WWDC 2010-104 PhotoScroller Appのサンプルコードを見ていきます。プロジェクト関連の画像(PDFページ画像)でうまく機能しています
しかし、私はPhotoScrollerアプリでタッチの検出に苦労しています。複数のタッチを使用したズームは、ScrollVoiewによって処理されます。次に、ダブルタップで写真をズームイン/アウトします。 Touchesbeganメソッドは、TilingViewクラスで呼び出されています。次に、[super touchesbegan:withevent:]を使用しましたが、タッチはImageScrollViewクラスにあります。
PhotoViewControllerでこれらのタッチイベントを取得する方法。タッチでズームインとズームアウトを達成する方法は?
誰でもこの点で助けてもらえますか?
私はいくつかの異なるWebサイトを調査し、次のことを思いつきました...
このコードをviewDidLoadまたはviewWillAppearメソッドに配置します。
//////////////////////////////
// Listen for Double Tap Zoom
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.scrollView addGestureRecognizer:doubleTap];
[doubleTap release];
これをヘッダーファイルに追加します。
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer;
これを実装に追加します。
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
if(self.scrollView.zoomScale > self.scrollView.minimumZoomScale)
[self.scrollView setZoomScale:self.scrollView.minimumZoomScale animated:YES];
else
[self.scrollView setZoomScale:self.scrollView.maximumZoomScale animated:YES];
}
現在、これは、ユーザーがダブルタップした領域を中心としていません。
リンク「 IImageViewはズームしません 」の一部のコードに基づいた私のコードは、このコードはズームインとズームアウトの切り替えを処理し、シングルタップとダブルタップの検出を可能にします。また、ビュー変換を適用することにより、埋め込み画像のズームを適切に中央に配置します。このコードは、サンプルコードのImageScrollViewクラスに入ります。
- (void)setupGestureRecognisers:(UIView *)viewToAttach {
UITapGestureRecognizer *dblRecognizer;
dblRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleDoubleTapFrom:)];
[dblRecognizer setNumberOfTapsRequired:2];
[viewToAttach addGestureRecognizer:dblRecognizer];
self.doubleTapRecognizer = dblRecognizer;
UITapGestureRecognizer *recognizer;
recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapFrom:)];
[recognizer requireGestureRecognizerToFail:dblRecognizer];
[viewToAttach addGestureRecognizer:recognizer];
self.tapRecognizer = recognizer;
}
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {
// do your single tap
}
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
zoomRect.size.height = [_imageView frame].size.height / scale;
zoomRect.size.width = [_imageView frame].size.width / scale;
center = [_imageView convertPoint:center fromView:self];
zoomRect.Origin.x = center.x - ((zoomRect.size.width / 2.0));
zoomRect.Origin.y = center.y - ((zoomRect.size.height / 2.0));
return zoomRect;
}
- (void)handleDoubleTapFrom:(UITapGestureRecognizer *)recognizer {
float newScale = [self zoomScale] * 4.0;
if (self.zoomScale > self.minimumZoomScale)
{
[self setZoomScale:self.minimumZoomScale animated:YES];
}
else
{
CGRect zoomRect = [self zoomRectForScale:newScale
withCenter:[recognizer locationInView:recognizer.view]];
[self zoomToRect:zoomRect animated:YES];
}
}
@ possen's 素晴らしい答えに基づいたSwiftソリューションです。
-これを、ScrollViewを含み、ScrollViewデリゲートであるView Controllerに配置します。
-このソリューションは、実際にタップ位置にズームするため、素晴らしいです。
@IBAction func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
if scrollView.zoomScale == 1 {
scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
} else {
scrollView.setZoomScale(1, animated: true)
}
}
func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = scrollView.convert(center, from: imageView)
zoomRect.Origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.Origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
self.minimumZoomScale
とself.maximumZoomScale
に適切な値を設定している限り、@ jayesh kavathiyaと@possenからの回答を1つの実装にまとめて、かなりうまく機能します。
- (void)doubleTap:(UITapGestureRecognizer*)recognizer
{
if (self.zoomScale > self.minimumZoomScale)
{
[self setZoomScale:self.minimumZoomScale animated:YES];
}
else
{
CGPoint touch = [recognizer locationInView:recognizer.view];
CGSize scrollViewSize = self.bounds.size;
CGFloat w = scrollViewSize.width / self.maximumZoomScale;
CGFloat h = scrollViewSize.height / self.maximumZoomScale;
CGFloat x = touch.x-(w/2.0);
CGFloat y = touch.y-(h/2.0);
CGRect rectTozoom=CGRectMake(x, y, w, h);
[self zoomToRect:rectTozoom animated:YES];
}
}
Swift 3
通常、ダブルタップジェスチャとピンチジェスチャの両方で画像ズーム機能が必要なので、同じことを達成するための完全なソリューションを提供しています。ダブルタップズームは上記の回答に触発され、ピンチズームは here から取得されました。
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var imageView: UIImageView!
var scrollImg: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let vWidth = self.view.frame.width
let vHeight = self.view.frame.height
scrollImg = UIScrollView()
scrollImg.delegate = self
scrollImg.frame = CGRect(x: 0, y: 0, width: vWidth, height: vHeight)
scrollImg.backgroundColor = UIColor(red: 90, green: 90, blue: 90, alpha: 0.90)
scrollImg.alwaysBounceVertical = false
scrollImg.alwaysBounceHorizontal = false
scrollImg.showsVerticalScrollIndicator = true
scrollImg.flashScrollIndicators()
scrollImg.minimumZoomScale = 1.0
scrollImg.maximumZoomScale = 10.0
let doubleTapGest = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTapScrollView(recognizer:)))
doubleTapGest.numberOfTapsRequired = 2
scrollImg.addGestureRecognizer(doubleTapGest)
self.view.addSubview(scrollImg)
imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: vWidth, height: vHeight))
imageView.image = UIImage(named: "cat")
imageView!.layer.cornerRadius = 11.0
imageView!.clipsToBounds = false
scrollImg.addSubview(imageView!)
}
func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
if scrollImg.zoomScale == 1 {
scrollImg.zoom(to: zoomRectForScale(scale: scrollImg.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
} else {
scrollImg.setZoomScale(1, animated: true)
}
}
func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = imageView.convert(center, from: scrollImg)
zoomRect.Origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.Origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.imageView
}
}
このコードを使用して、クリックした場所をズームします.......
- (void)handleDoubleTap:(UIGestureRecognizer *)recognizer {
if(zoomCheck){
CGPoint Pointview=[recognizer locationInView:self];
CGFloat newZoomscal=3.0;
newZoomscal=MIN(newZoomscal, self.maximumZoomScale);
CGSize scrollViewSize=self.bounds.size;
CGFloat w=scrollViewSize.width/newZoomscal;
CGFloat h=scrollViewSize.height /newZoomscal;
CGFloat x= Pointview.x-(w/2.0);
CGFloat y = Pointview.y-(h/2.0);
CGRect rectTozoom=CGRectMake(x, y, w, h);
[self zoomToRect:rectTozoom animated:YES];
[self setZoomScale:3.0 animated:YES];
zoomCheck=NO;
}
else{
[self setZoomScale:1.0 animated:YES];
zoomCheck=YES;
}
}
このコードを使用して、クリックした場所をズームします。
以前の答えは、以下のように BlocksKit を使用すると簡単になります。
#import "BlocksKit.h"
...
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithHandler:^(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
if(scrollView.zoomScale != 1.0){
[scrollView setZoomScale:1.0 animated:YES];
}else{
[scrollView setZoomScale:2.0 animated:YES];
}
}];
[doubleTap setNumberOfTapsRequired:2];
[scrollView addGestureRecognizer:doubleTap];
UITapGestureRecognizerをImageScrollViewに追加するのはどうですか?
サンプルコードを見ている限り、 ScrollViewSuiteサンプルコード でUIGestureRecognizerがどのように使用されているかを確認できます。
タップ位置を拡大
CGFloat scale = 3.0;
CGFloat scale = ScaleToAspectFitRectAroundRect(frame, self.bounds) * 2.0;
CGRect zoomRect;
CGPoint point = [gestureRecognizer locationOfTouch:0 inView:[gestureRecognizer view]];
zoomRect.size.height = frame.size.height * scale;
zoomRect.size.width = frame.size.width * scale;
zoomRect.Origin.x = CGRectGetMidX(frame) - (CGRectGetWidth(zoomRect)/2) + (scale * (CGRectGetWidth(frame)/2 - point.x)) - (CGRectGetWidth(frame)/2 - point.x);
zoomRect.Origin.y = CGRectGetMidY(frame) - (CGRectGetHeight(zoomRect)/2) + (scale * (CGRectGetHeight(frame)/2 - point.y)) - (CGRectGetHeight(frame)/2 - point.y);
これはSwift 5のピンチズームとダブルタップズームの場合の最新のコードです。
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
let doubleTapGest = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTapScrollView(recognizer:)))
doubleTapGest.numberOfTapsRequired = 2
scrollView.addGestureRecognizer(doubleTapGest)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
@objc func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
if scrollView.zoomScale == 1 {
scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
}
else {
scrollView.setZoomScale(1, animated: true)
}
}
func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = imageView.convert(center, from: scrollView)
zoomRect.Origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.Origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
}
絵コンテの絵も添付しました。
これはconvertRect:fromView:
およびzoomToRect:animated:
を使用して機能するようです:
-(void)tap:(UITapGestureRecognizer *)tapGestureRecognizer
{
CGFloat zoomeScaleMultiplier = 0.5;
UIScrollView *scrollView = (UIScrollView *) tapGestureRecognizer.view;
UIView *zoomableView = [scrollView.delegate viewForZoomingInScrollView:scrollView];
CGRect rect = scrollView.bounds;
rect.Origin = CGPointZero;
CGAffineTransform transform = CGAffineTransformMakeScale(zoomeScaleMultiplier, zoomeScaleMultiplier);
rect = CGRectApplyAffineTransform(rect, transform);
rect.Origin = [tapGestureRecognizer locationInView:scrollView];
rect = CGRectOffset(rect, CGRectGetWidth(rect)/-2., CGRectGetHeight(rect)/-2.);
rect = [zoomableView convertRect:rect fromView:scrollView];
[scrollView zoomToRect:rect animated:YES];
}
UIScrollViewをサブクラス化し、in mファイルを追加します
#pragma mark -
#pragma mark doubleTouch
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSUInteger tapCount = [touch tapCount];
switch (tapCount) {
case 2:
{
if(self.zoomScale <1.0){
[self setZoomScale:1.0 animated:YES];
}else{
[self setZoomScale:0.1 animated:YES];
}
break;
}
default:
break;
}
}
@ n8trの回答を機能させるには、viewForZooming(in scrollView: UIScrollView) -> UIView? in UIScrollViewDelegate
を実装する必要があります。
したがって、完全なコードは次のようになります
class ViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
@IBAction func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
if scrollView.zoomScale == 1 {
scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
} else {
scrollView.setZoomScale(1, animated: true)
}
}
func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = imageView.convert(center, from: scrollView)
zoomRect.Origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.Origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}