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

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

ただいまの
回答率

88.91%

画面を閉じて再度開いたとき,Viewを閉じる前と同じ配置にしたいです.

解決済

回答 1

投稿 編集

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

ponponpoo

score 1

前提・実現したいこと

画面AとBがあるとします.
画面Aはメニュー画面で,画面Bへ遷移するボタンがあります.
画面Bでは,画像にスタンプを貼り付けるような編集作業ができます.

画面Bで編集し終えた後,画面Aに戻り,また画面Bを開いたら,
編集していた画面に戻したいです.

スタンプは画面BにaddViewされており,戻ってきたときにも
また動かせるようにしたいので,一括画像保存とかではありません.

addViewされたViewの座標を配列かなにかで保存すれば
いいのかなと考えておりますが,もっとスマートなやり方はないでしょうか.

また,座標を保存する際に,いい感じのメソッドがあれば教えていただきたいです.
今のところは,frameが使えそうだと考えております.

よろしくおねがいします.



追記

画面AからBへはpresent()を使用しています.
画面Bは全画面表示なので画面BはAの子供となるのでしょうか?

画面Bはだいたい以下の構造です.(本当は下のContainerViewを変えるボタンがあります)
CollectionViewには,スタンプの画像一覧が表示されます.
イメージ

ContainerViewの中身は切り替えができます.
そこのところは,こちらを参考にしました.

動作イメージは,
Cellに表示されているスタンプ(Cell)を長押し → スタンプが手の動きに合わせて移動(Cellの画像を複製) → ImageViewに持っていく → 貼り付ける

貼り付けたものを長押し → スタンプを移動

といった具合です.

BVCは,ContainerViewの表示を切り替えるものが記述されています.
(上リンク)

CVCでは
① 長押しでCellの画像を複製,画像移動のために,ロングプレスとパンを設定

    func setGesture() {
        //長押しをセット
        let longPressGesture =
        UILongPressGestureRecognizer(target: self,
                                     action: #selector(self.longPress(_:)))
        longPressGesture.delegate = self

        //パンをセット
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(HGotItemViewController.panView(sender:)))
        panGesture.delegate = self

        self.collectionView.addGestureRecognizer(longPressGesture)
        self.collectionView.addGestureRecognizer(panGesture)

    }

② Cellを長押しされたらCell内の画像のUIImageViewを作る

    @objc func longPress(_ sender: UILongPressGestureRecognizer){
        if sender.state == .began {

            //押された座標とCell番号
            newTapPoint = sender.location(in: view)
            tapPoint = sender.location(in: view)
            let indexPath = self.collectionView.indexPathForItem(at: tapPoint)

            if indexPath != nil{
                //indexPathからアイテムの画像を判断
                itemImage = (UIImage(named: "item/\(indexPath!.row)")?.withRenderingMode(.alwaysTemplate))!

//追加するViewが手の位置にくるように設定
                stampView = UIImageView(frame: CGRect(x: tapPoint.x,y: tapPoint.y, width: 168, height: 90))
                stampView.backgroundColor = .red
                stampView.center = CGPoint(x:tapPoint.x+470,y:tapPoint.y)
                stampView.image = itemColorImage

//追加したあとも位置を変えられるように長押しとパンを設定

                let longPressGesture2 =
                    UILongPressGestureRecognizer(target: self,
                                                 action: #selector (self.move(_:)))
                longPressGesture2.delegate = self
                stampView.addGestureRecognizer(longPressGesture2)

                let panGesture2 = UIPanGestureRecognizer(target: self, action: #selector(self.panView(sender:)))
                panGesture2.delegate = self
                stampView.addGestureRecognizer(panGesture2)

                stampView.isUserInteractionEnabled = true

                //Viewを追加
                self.parent?.view.addSubview(stampView)
            }
        }else if sender.state == .ended{

                //画像以外のところに載せたら消す
                if imageView.frame.contains(endPoint){
                    print("endPoint=",endPoint)
                }else{
                    stampView.removeFromSuperview()
                }
           }
        }

    }

を行っています.

データの永続化もしたいです.
画面Aに戻った,アプリを落としたあとも,画面Bにくると編集していた画面を
表示させたいです.
永続化方法については,userDefaultsを使用しようと考えていますが,
初心者のため,何もわからず,データもそんな大きくならないと思うので
とりあえず検索して出てきたこれにしよう程度のです.
なので,もし,他に良い方法があれば教えて下さい.

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2020/07/12 00:03 編集

    画面Aと画面Bの関係、遷移の方法が把握できません。
    また、対象はgestureRecognizerが設定してあるViewでしょうが、addSubviewするものの条件によってはframeを保存する以外の方法がよりベターである可能性があります。
    以前と同じような不毛なやり取りはしたくありませんので、コードを提示してください。
    よりよい回答がつく可能性が高くなります。

    加えて、データの永続化が必要となるようでしたらその旨並びに永続化方法も記載されると良いと思います。

    キャンセル

回答 1

checkベストアンサー

0

Reflectionsubviewsで取得して、値渡しなどしていないようなのでライフサイクルにそって保存、読み込みすればよいかと思います。

subviewsからUILabeltextframeを保存してみました。読み込んだ情報から復元できると思います。

動かす場合はStoryboardにUILabelとか適当に貼り付けてください。

質問のケースではUIImageViewのようですが、UIImageViewをそのまま保存して、戻してgestureRecognizerなどがそのまま動くかなど試してみてもいいかもしれなせん。

import UIKit

class ViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // ユーザーデフォルトから取得
        let labels = UserDefaults.standard.decodedObject(Labels.self, forKey: "KEY")
        dump(labels)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        let labels = Labels()
        // self.viewのサブビューのうちラベルの値を取得する
        self.view.subviews.forEach {
            if let label = $0 as? UILabel {
                let l = LabelProperties(text: label.text ?? "", frame: label.frame)
                labels.labelProperties.append(l)
            }
        }
        dump(labels)
        // ユーザーデフォルトに保存
        UserDefaults.standard.setEncoded(labels, forKey: "KEY")
    }

}

class Labels: Codable {
    var labelProperties = [LabelProperties]()
}

class LabelProperties: Codable {

    let text: String
    let frame: CGRect

    init(text: String, frame: CGRect) {
        self.text = text
        self.frame = frame
    }
}


// https://teratail.com/questions/274938#reply-392168 をコピペ
// MasakiHoriさんありがとうございます。
extension UserDefaults {
  func setEncoded<T: Encodable>(_ value: T, forKey key: String) {
    guard let data = try? JSONEncoder().encode(value) else {
       print("Can not Encode to JSON.")
       return
    }

    set(data, forKey: key)
  }

  func decodedObject<T: Decodable>(_ type: T.Type, forKey key: String) -> T? {
    guard let data = data(forKey: key) else {
      return nil
    }

    return try? JSONDecoder().decode(type, from: data)
  }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/08/20 16:11

    回答ありがとうございます.
    無事に保存することができました.

    ですが,色と画像が保存できないので,別のページでまた質問させて頂きます.

    キャンセル

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

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

関連した質問

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