0
1

[Swift]特定のViewがスクリーンに表示されたことを検知する

Last updated at Posted at 2023-10-27

結論(急いでいる人用)

Listメソッドの中に検知したいViewを配置し、
.onAppear,.onDisappearを使って検知およびトリガーとする。

経緯

画像を複数表示するためのアプリを作成していて、ScrollViewで管理していると複数の画像によって、メモリが圧迫されてしまいアプリが落ちるようになってしまいました。

そこで、それなら画面に表示されている画像だけ読み込もうという考えに至り、
色々調べたという流れです。
結果として、これが現状一番楽で見やすいかなと思い、自分の備忘録も含めて掲載します。

実装方法

色々調べていると以下のような記事を見つけました。

やりたいことはまさにこれじゃ!!

ということで早速実装

ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // スクロール可能なコンテンツ
            List(){
                ForEach(0..<50) { index in
                    ZStack{
                        HStack{
                            VStack{
                                AsyncImage(url: URL(string: "画像を保存しているパス")) { phase in
                                    switch phase{
                                    case .success(let image):
                                        ZStack{
                                            Circle()
                                                .fill(Color.white)
                                                .frame(width:40,height: 40)
                                            image
                                                .resizable()
                                                .scaledToFit()
                                                .background(Color.white)
                                                .frame(width:40,height: 40)
                                                .clipShape(Circle())
                                            Circle()
                                                .stroke(Color.gray, lineWidth: 1)
                                                .frame(width:40,height: 40)
                                        }
                                    default:
                                        ZStack{
                                            Circle()
                                                .fill(Color.white)
                                                .frame(width:40,height: 40)
                                            Circle()
                                                .stroke(Color.gray, lineWidth: 1)
                                                .frame(width:40,height: 40)
                                        }
                                    }
                                }
                                Spacer()
                            }.padding(.trailing,5)
                            VStack{
                                HStack{
                                    Text("名前")
                                        .font(.custom("Roboto-Medium", size: 16))
                                        .foregroundColor(Color.black)
                                        .lineLimit(nil)
                                        .fixedSize(horizontal: false, vertical: true)
                                    Spacer()
                                }
                                HStack{
                                    Text("hogehoge")
                                        .font(.custom("Roboto-Medium", size: 16))
                                        .foregroundColor(Color.black)
                                        .lineLimit(nil)
                                        .fixedSize(horizontal: false, vertical: true)
                                    Spacer()
                                }
                                .padding(.all,20)
                                .background(Color.gray).opacity(0.5)
                                .cornerRadius(5)
                                Spacer()
                            }
                        }.padding(.all,15)
                    }.background(Color.white)
                        .listRowBackground(Color.clear)
                        .listRowSeparator(.hidden) // 区切り線を非表示にする
                        .onAppear(){
                            print("表示されたよ!")
                        }
                        .onDisappear(){
                            print("非表示になったよ!")
                        }
                }
            }.listStyle(PlainListStyle())
        }
    }
}

冗長な部分が多々あるかと思いますが、ご容赦ください。

ここで大事なのは特定のViewがスクリーンに表示されたのをトリガーとすることです。
.onAppear{}と.onDisAppear{}がトリガーとなり、この中に行なってほしい処理を記述します。

.onAppear{}には、Viewが表示された際の処理、.onDisappear{}にはViewが画面外に行った時の処理を記述します。

ついでに

この実装を行なっている際に気がついたのですが、List{}ではスクリーン内のViewしか描画しないのに対し、ScreenView{}ではたとえ画面外であっても全てのViewを描画しようとすることがわかりました。

ですので、今回私のメモリ圧迫の件はScrollView{}ではなく、List{}を使うだけでよかったです。
もしかしたら、スクリーン表示した時に何かを実行したい人のためになるかな。。。?

きっとドキュメント等を確認すればわかることなのかもしれませんが、まだまだ私自身知識が浅いため、苦手意識が強く。。。

しかし、少しずつでもドキュメントを見ていく癖をつける必要があるなと感じました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1