質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.40%

  • Swift

    9138questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    5142questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

iOSフォトライブラリの写真をドラッグ操作時に、トリミング枠から出ないようにしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 309

RyomaD

score 10

フォトライブラリの写真をドラッグ操作時に、トリミング枠から出ないようにしたいと考えております。
現状のドラッグ時は以下のような形になっており、
![イメージ説明](419abd6eb35276fac84a99e58ef60fe1.png)

「picker.allowsEditing = true」を設定した時のような挙動にしたいと考えております。
(ドラッグ操作した際に画像がトリミング枠から出たらふわっと戻るような仕様です。)

「picker.allowsEditing = true」を使えば済むような話ですが、
どうしてもデフォルトのトリミング枠の形状を変更できなので、自作中です。

コードは以下のようになっております。

    var image : UIImage!
    var imageView : UIImageView! //トリミング対象画像を表示するためのUIImageView
    var previousImages = [UIImage]()
    var nextImages = [UIImage]()
    var scaleZoomedInOut : CGFloat = 1.0 //拡大・縮小した時にはUIImageViewのサイズのみが変わるので、実際のUIImageのサイズとUIImageViewとの倍率の差を記録する
    var previousScaleZoomedInOut = [CGFloat]()
    var nextScaleZoomedInOut = [CGFloat]()


    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        finishEditingButton.addTarget(self, action: #selector(finishEdittingAlert), for: .touchUpInside)

        editPhotoView.layer.borderColor = UIColor.black.cgColor
        editPhotoView.layer.borderWidth = 1
        setUpPinchInOutAndDoubleTap()

        //load image and show UIImageView
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        image = appDelegate.photoLibraryImage
        previousScaleZoomedInOut.append(scaleZoomedInOut)
        createImageView(sourceImage: image, on: editPhotoView)
        mainStackView.bringSubview(toFront: headerView)
    }



    func createImageView(sourceImage: UIImage, on parentView: UIView){
        imageView = UIImageView(image: sourceImage)
        // 画像の幅・高さの取得
        let imageWidth = sourceImage.size.width
        let imageHeight = sourceImage.size.height
        let screenWidth = editPhotoView.frame.width
        let screenHeight = editPhotoView.frame.height

        if scaleZoomedInOut == 1.0{
            if imageHeight > screenHeight{
                scaleZoomedInOut = screenHeight/imageHeight
            }
        }

        let rect:CGRect = CGRect(x:0, y:0, width:scaleZoomedInOut*imageWidth, height:scaleZoomedInOut*imageHeight)
        imageView.frame = rect// ImageView frame をCGRectで作った矩形に合わせる
        imageView.contentMode = .scaleAspectFill // Aspect Fill = 縦横の比率はそのままで短い辺を基準に全体を表示する
        imageView.center = CGPoint(x:screenWidth/2, y:screenHeight/2) // 画像の中心をスクリーンの中心位置に設定

        parentView.addSubview(imageView)
        parentView.sendSubview(toBack: imageView)
    }

 //上下左右の移動は、ドラッグ操作できる。
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

        // タッチイベントを取得.
        let aTouch: UITouch = touches.first!

        // 移動した先の座標を取得.
        let location = aTouch.location(in: editPhotoView)

        // 移動する前の座標を取得.
        let prevLocation = aTouch.previousLocation(in: editPhotoView)

        //移動した距離
        let deltaX = location.x - prevLocation.x
        let deltaY = location.y - prevLocation.y

        // 移動した分の距離を座標にプラスする.
        imageView.frame.origin.x += deltaX
        imageView.frame.origin.y += deltaY

    }

@objc func pinchAction(gesture: UIPinchGestureRecognizer) {

        if gesture.state == UIGestureRecognizerState.began {
            // ピンチを開始したときの画像の中心点を保存しておく
            pinchStartImageCenter = imageView.center
            touchPoint1 = gesture.location(ofTouch: 0, in: self.view)
            touchPoint2 = gesture.location(ofTouch: 1, in: self.view)

            // 指の中間点を求めて保存しておく
            // UIGestureRecognizerState.Changedで毎回求めた場合、ピンチ状態で片方の指だけ動かしたときに中心点がずれておかしな位置でズームされるため
            pichCenter = CGPoint(x: (touchPoint1.x + touchPoint2.x) / 2, y: (touchPoint1.y + touchPoint2.y) / 2)

        } else if gesture.state == UIGestureRecognizerState.changed {
            // ピンチジェスチャー・変更中
            var pinchScale :  CGFloat// ピンチを開始してからの拡大率。差分ではない
            if gesture.scale > 1 {
                pinchScale = 1 + gesture.scale/100
            }else{
                pinchScale = gesture.scale
            }
            if pinchScale*self.imageView.frame.width < editPhotoView.frame.width {
                pinchScale = editPhotoView.frame.width/self.imageView.frame.width
            }
            scaleZoomedInOut *= pinchScale

            // ピンチした位置を中心としてズーム(イン/アウト)するように、画像の中心位置をずらす
            let newCenter = CGPoint(x: pinchStartImageCenter.x - ((pichCenter.x - pinchStartImageCenter.x) * pinchScale - (pichCenter.x - pinchStartImageCenter.x)),y: pinchStartImageCenter.y - ((pichCenter.y - pinchStartImageCenter.y) * pinchScale - (pichCenter.y - pinchStartImageCenter.y)))
            self.imageView.frame.size = CGSize(width: pinchScale*self.imageView.frame.width, height: pinchScale*self.imageView.frame.height)
            imageView.center = newCenter
        }
    }

    //ダブルタップは、ダブルタップを行うとタップをしたところを中心にUIImageViewが2倍の大きさになる
    @objc func doubleTapAction(gesture: UITapGestureRecognizer) {

        if gesture.state == UIGestureRecognizerState.ended {

            let doubleTapStartCenter = imageView.center
            let doubleTapScale: CGFloat = 2.0 // ダブルタップでは現在のスケールの2倍にする
            scaleZoomedInOut *= doubleTapScale
            let tapPoint = gesture.location(in: self.view)
            let newCenter = CGPoint(x:
                doubleTapStartCenter.x - ((tapPoint.x - doubleTapStartCenter.x) * doubleTapScale - (tapPoint.x - doubleTapStartCenter.x)),
                                    y: doubleTapStartCenter.y - ((tapPoint.y - doubleTapStartCenter.y) * doubleTapScale - (tapPoint.y - doubleTapStartCenter.y)))

            // 拡大・縮小とタップ位置に合わせた中心点の移動
            UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {() -> Void in
                self.imageView.frame.size = CGSize(width: doubleTapScale*self.imageView.frame.width, height: doubleTapScale*self.imageView.frame.height)
                self.imageView.center = newCenter
            }, completion: nil)
        }
    }


ドラッグして画像を動かした際に移動した距離を割り出し、
トリミング対象画像を表示するためのUIImageViewのorigin.x(y)をインクリメントすることで
動作しております。

 試したこと

if imageView.frame.origin.y < 0{
            imageView.frame.origin.y = 0
        }else if imageView.frame.origin.y > 0{
            imageView.frame.origin.y = 0
        }else if imageView.frame.origin.x > 0{
            imageView.frame.origin.x = 0
        }


上記のやり方ではトリミング枠から出ないものの、ピンチインアウト時や、ズームインアウト時におかしな挙動になり想定の動きかたをしてくれませんでした。

画像の幅・高さを取得して、=> let imageWidth = sourceImage.size.width

「トリミング対象画像を表示するためのUIImageViewが、let imageWidth 以上になったらドラッグ移動させない」ようなやり方で試そうと思っています。

他に拡張性の高いやり方など、ご存知の方がいらっしゃればご教授頂けないでしょうか!!!!!
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

一応、ドラッグ移動時は余白が出ないようになっています。
ピンチインアウト時の挙動が理想の挙動とは異なるので引き続き改善してみます。

if imageView.frame.origin.y < 0{
            imageView.frame.origin.y = 0
        }else if imageView.frame.origin.y > 0{
            imageView.frame.origin.y = 0
        }else if imageView.frame.origin.x > 0{
            imageView.frame.origin.x = 0
        }else if editPhotoView.frame.size.width > (imageView.frame.size.width + imageView.frame.origin.x){ 
            imageView.frame.origin.x += editPhotoView.frame.size.width - (imageView.frame.size.width + imageView.frame.origin.x)
        }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.40%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Swift

    9138questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    5142questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。