trainingApp.swift
import SwiftUI
@main
struct trainingApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
@State var current: Int = 0
@State var maxCnt: Int = 0
@State var itemList: [ItemModel] = []
@State var hasMorePages:Bool = true
var body: some View {
GeometryReader { geometry in
let columns: [GridItem] = [GridItem()]
let width = geometry.size.width / 1.05
let height = geometry.size.height / 2.5
let spacing = geometry.size.width / 40
ScrollView(.vertical, showsIndicators: false){
ZStack{
LazyVGrid(columns: columns, alignment: .center, spacing: spacing) {
ForEach(itemList) { item in
Button(action: {
print("item.label : \(item.label) item.id : \(item.id)")
}){
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(Color.white)
.overlay(
VStack{
Text(item.id)
.font(.system(size: 12))
.foregroundColor(.black)
.padding(.bottom, 10)
Text(item.label)
.foregroundColor(.black)
}
)
.frame(width: width, height: height)
.shadow(color: .gray, radius: 2, x: CGFloat(2), y: CGFloat(2))
}
.onAppear(){
let index = Int(item.label.components(separatedBy: "List Item ")[1])!
if(maxCnt < index){
maxCnt = index
if(maxCnt % 10 == 0){
loadItems()
}
}
}
}
}
}.onAppear(){
print("onAppear")
loadItems()
}
.padding(.vertical, 20)
}
}
}
func loadItems(){
print("loadItems")
if(hasMorePages){
current+=1
let request = HttpCommon().httpCall(url: "https://s3.eu-west-2.amazonaws.com/com.donnywals.misc/feed-\(current).json", method: "GET", body: nil)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil || data == nil {
print("Client error!")
return
}
if let response = response as? HTTPURLResponse {
let statusCode = response.statusCode
print("response.statusCode : ", response.statusCode)
if(statusCode == 401){
print("401 Error")
} else if((404...500).contains(response.statusCode)){
print("비정상 접근 또는 서버 에러")
} else if((200...299).contains(response.statusCode)){
do {
let responseModel = try JSONDecoder().decode(ResponseModel<ItemModel>.self, from:data!)
hasMorePages = responseModel.hasMorePages
let loadItems = responseModel.items
loadItems.forEach { loadItem in
itemList.append(loadItem)
}
} catch let e as NSError {
print("An error has occured while parsing JSON Obejt : \(e.localizedDescription)")
}
} else {
print("접속장애")
}
}
}
task.resume()
}
}
}
ResponseModel.swift
class ResponseModel<T : Decodable>: Decodable {
var items: [T]
var hasMorePages: Bool
}
ListItem.swift
import SwiftUI
struct ListItem: View {
let item: ItemModel
var body: some View {
ZStack(alignment: .center) {
RoundedRectangle(cornerRadius: 5)
.foregroundColor(.gray)
Text("item.id \(item.id)!")
Text("item.label \(item.label)!")
}
.frame(height: 72)
}
}
ItemModel.swift
class ItemModel: Decodable, Identifiable {
var id: String
var label: String
}
HttpCommon.swift
import SwiftUI
class HttpCommon {
init(){
print("HttpCommon Init()")
}
func httpCall(url: String, method: String, body: [String: String]?) -> URLRequest {
let Url = String(format: url)
let serviceUrl = URL(string: Url)
var request = URLRequest(url: serviceUrl!)
request.httpMethod = method
request.timeoutInterval = 20
if(method == "POST") {
request.httpBody = try? JSONSerialization.data(withJSONObject: body!, options: [])
}
print("url : ", serviceUrl!)
return request
}
}
초기화면
제일 높은 인덱스에 올랐을 경우 maxCnt에 대입하고 % 10 == 0 인 경우 로드한다.
스크롤 했을 경우
ForEach에서 몇번째 인덱스인지 추출하는 방법을 몰라서 List Item {number}를 포함한 data를 사용하기때문에 split해서 몇번째 인덱스인지 감지하였다.
LazyVGrid 를 꼭 사용해야만 가능한 스크롤 뷰이다. LazyVGrid는 수직으로 그리드에 자식 뷰를 정렬하여 필요한 만큼만 아이템을 생성하는 컨테이너 뷰이다. 때문에 그려질때마다 onAppear() 해서 가능하지만 LazyVGrid를 사용하지 않는경우에는 이미 화면에 항목을 다 그려버려서 onAppear()가 이미 실행되고 끝나버린다.
는 현재 화면에 표시되야 되는것을 감지하기 보여준다.
원래는 index % 10 == 0 인경우에 로드하였으나 위쪽으로 다시 올라가는경우, 예를들면 최초 10을 로드하고
20, 30까지 로드 후 다시 20 으로 가는경우 20 % 10 == 0 이 되기때문에 20번째에 위치해 있음에도 불구하고 40까지 로드해버린다.
이 때문에 maxCnt를 계속 대입해서 다시 위로 스크롤해서 올라가는것들에는 호출안되도록 막았다.
위치를 감지해서 로드하는것이 아니고 현재 생성된 데이터의 number를 위치로 보기 때문에 사용에 제한적이다.
'📱Mobile > 🔥Swift' 카테고리의 다른 글
[Swift] SwiftUI Push Notifications(FCM) APN(APNS) 푸쉬알림 예제 (62) | 2023.07.09 |
---|---|
[Swift] SwiftUI TabView(bottom navigation bar) + SideMenubar 예제 (0) | 2021.11.01 |
[Swift] SwiftUI KeyChain Service 예제 (0) | 2021.10.30 |
[Swift] SwiftUI WebView, WebView + javascript message handler 예제 (0) | 2021.09.28 |
[Swift] SwiftUI SHA256을 이용한 간단한 로그인 구현 예제 (0) | 2021.09.28 |