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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Xcode

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

Swift

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

Q&A

解決済

1回答

3194閲覧

Viewに下線をaddSublayerするとずれる(オートレイアウト)

Y.Kame

総合スコア13

Xcode

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

Swift

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

0グッド

0クリップ

投稿2020/05/09 17:00

編集2020/05/09 17:12

Swift

1 2//viewDidLoad()でSetupView()を実行 3 4 // SetupView 5 func SetupView() { 6 let bottomBorder = CALayer() 7 bottomBorder.frame = CGRect(x: 0, y: SafeAreaView.frame.height, width: SafeAreaView.frame.width, height: 1) 8 bottomBorder.backgroundColor = UIColor.lightGray.cgColor 9 SafeAreaView.layer.addSublayer(bottomBorder) 10 }

イメージ説明

発生している問題・エラーメッセージ

いろんな記事をみてみると、オートレイアウトで端末にあわせてviewのサイズが変わるまえにCALayerでフレームサイズ?を図ってるからオートレイアウトでviewの高さが変更されたときに下線がずれるものだと把握しています。

よってviewDidLoad()内ではなく、viewDidAppear()内でSetupView()を実行したら期待どおりの位置に下線を引いてくれました。

しかし、viewDidAppear()でSetupView()を実行するとなると下線が表示されるまで若干のタイムロスがあります(汗)

なにかいい解決策はありませんか・・・

またおそらく同じ理由で、CollectionViewのセルのサイズも端末によってずれています。
下記のように設定しているにも関わらずセルのサイズがCollectionViewのサイズに適応してくれません。

let layout = UICollectionViewFlowLayout() layout.itemsize = collectionView.bounds.size

わかる方がいらっしゃいましたらご教授いただけたらと思います。
どうぞよろしくお願いします。

補足情報(FW/ツールのバージョンなど)

Swift
XCODE11

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y.Kame

2020/05/09 18:31

回答ありがとうございます。 viewDidLayoutSubviewsで実行するといいという記事をみて実際に実装してみたんですが、仰っられているように、おそらくオートレイアウトが反映される前と、されたあとで2回 addSublayer(bottomBorder)が実行されて2本下線が引かれてしまいました・・・。 オートレイアウトが反映されたあとのみにSetupView()を実行したいのですが、いまいち理解できる記事がネットに見当たりませんでした。 また私が構成しているアプリはportfolioにのみ対応しているアプリを作成しているので画面の向きが変わったりしないのですが、横画面対応のアプリなどを作成している場合も、viewDidLayoutSubviews内に実装すると何回もaddSublayerが呼ばれることになる・・・という解釈だと使い物にならない気がするのですが、どのようにみなさんは実装しているものなんでしょうか。。
hoshi-takanori

2020/05/09 18:41

もちろん画面が回転したり、その他いろんな理由でレイアウトの変更は起こりますので、当然対応する必要があります。方法としては、前回 addSublayer したものを覚えておいて、nil でなければ削除してから新しいものを addSublayer するなどですね。
Y.Kame

2020/05/09 19:01

addSublayerしたものを覚えておく・・・というとaddSublayerするものをファンクション内でlet~として宣言するのでなくクラス内で宣言したほうがいいですよね(?) IBのオートレイアウトとCALayer()の組み合わせは結構面倒なことになるんですね!!(CALayerだけに限りませんが)
Y.Kame

2020/05/09 20:04

いろいろと自分で試行錯誤してみたのですが、 「前回 addSublayer したものを覚えておいて、nil でなければ削除〜」 の部分がコードで記述できませんでした。 ファンクションの外で、 let bottomBorder = CALayer() func SetupView(){ bottomBorder != nil { bottomBorder.removeFromSuperlayer() //ここにボーダーを引く処理 } else {    //ここにボーダーを引く処理 } こんなイメージかなと思ったんですがコードエラーでできませんでした・・・。
guest

回答1

0

自己解決

コメントをいただき自己解決しました

オートレイアウトでviewサイズが変わったあとにCALayerをaddSublayer()する必要があるので、viewDidLoad()内にコードを記述するのではなく、viewDidLayoutSubviews()にコードを記載します。

override func viewDidLoad(){ super.viewDidLoad() } //オートレイアウト後に呼ばれる処理、レイアウトが変わる度に呼ばれます(画面を横向きにしたり) override func viewDidLayoutSubviews() { SetupView() super.viewDidLayoutSubviews() } func SetupView(){ let btmBorder = CALayer() btmBorder.removeFromSuperlayer() //ここで一度CALayerを削除 btmBorder.frame = CGRect(x: 0, y: NaviView.frame.height, width:NaviView.frame.width, height: 1) btmBorder.backgroundColor = UIColor.lightGray.cgColor NaviView.layer.addSublayer(btmBorder) }

viewDidLayoutSubviews()メゾットは、レイアウトが変更される度に呼ばれるのでaddASublayer()を毎回削除しないと今回の例でいうと何本も線が引かれることになるので、SetupView()ファンクション内で一度削除してあげることで解決しました!!

投稿2020/05/09 20:29

Y.Kame

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問