SwiftUI优秀文章经典案例制作简易的新闻列表Demo

SwiftUI优秀文章经典案例制作简易的新闻列表Demo,第1张

SwiftUI制作简易的新闻列表Demo
import SwiftUI

struct HomeView: View {
   @StateObject var  newsViewModelVM = NewsViewModel()
   var body: some View {
       ZStack{
           Group{
               switch newsViewModelVM.state{
               case .loading:
                   ProgressView()
               case .failed(let error):
                   ErrorView(error: error) {
                       newsViewModelVM.getArticels()
                   }
               case .success(let articels):
                   NavigationView{
                       List(articels){ item in
                           PostCellView(article: item)
                       }
                       .listStyle(.plain)
                       .navigationTitle(Text("News"))
                   }
               }
           }
           .onAppear {
               newsViewModelVM.getArticels()
           }
           
           Text("Desgin By Lujun 2022.2.8")
               .font(.system(size: 30).bold())
               .foregroundColor(.orange)
               .shadow(color: .black, radius: 5, x: 5, y: 5)
               .offset(y: 300)
       }
    }
}
struct NewsModel: Codable {
    let articles: [Article]
}
// MARK: - Article
struct Article: Codable,Identifiable {
    var id = UUID()
    let author: String?
    let url: String?
    let source, title, articleDescription: String?
    let image: String?
    let date: Date?

    enum CodingKeys: String, CodingKey {
        case author, url, source, title
        case articleDescription = "description"
        case image, date
    }
}

错误自定义

enum APIError: Error {
    case decodingError
    case errorCode(Int)
    case unknow
}
extension APIError: LocalizedError{
    var errorDescription: String?{
        switch self {
        case .decodingError:
            return "failurs"
        case .errorCode(let code):
            return "\(code) -somethinds error"
        case .unknow:
            return "the error in unknown"
        }
    }
}

请求数据流核心

import SwiftUI
import Combine

enum ResultState{
    case loading
    case success(content: [Article])
    case failed(error: APIError)
}

let baseURL = "http://localhost:8081/"
class NewsViewModel: ObservableObject {
    @Published  var state: ResultState = .loading
    private  var aticels = [Article]()
    private  var cancelables = Set<AnyCancellable>()
    func getArticels(){
        let cancellable = request(from: "http://localhost:8081/news.json")
            .sink { res in
                switch res{
                case .finished:
                    self.state = .success(content: self.aticels)
                case .failure(let error):
                    self.state = .failed(error: error)
                    
                }
            } receiveValue: { response in
                self.aticels = response.articles
            }
        self.cancelables.insert(cancellable)
        
    }
    func request(from apiUrl: String) -> AnyPublisher<NewsModel,APIError>{
        URLSession.shared
            .dataTaskPublisher(for: URL(string: apiUrl)!)
            .receive(on: DispatchQueue.main)
            .mapError{_ in APIError.unknow}
            .flatMap{data,response -> AnyPublisher<NewsModel,APIError> in
                guard let response = response as? HTTPURLResponse else {
                    return Fail(error: APIError.unknow).eraseToAnyPublisher()
                }
                if (200...299).contains(response.statusCode) {
                    let jsonDeconder = JSONDecoder()
                    jsonDeconder.dateDecodingStrategy = .iso8601
                    return Just(data)
                        .decode(type: NewsModel.self, decoder: jsonDeconder)
                        .mapError{_ in APIError.decodingError}
                        .eraseToAnyPublisher()
                }else{
                    return Fail(error: APIError.errorCode(response.statusCode)).eraseToAnyPublisher()
                }
            }
           .eraseToAnyPublisher()
    }
    
}

postCell核心

import SDWebImageSwiftUI
struct PostCellView: View {
    let article: Article
    var body: some View {
        HStack{
            if let imgUrl = article.image,
               let url = URL(string: String(format: "%@%@", baseURL,imgUrl)) {
                WebImage(url: url)
                    .placeholder(content: {
                        Color.gray
                    })
                    .resizable()
                    .scaledToFill()
                    .frame(width: 100, height: 100)
                    .cornerRadius(10)
             }else{
                Image(systemName: "photo.fill")
                    .foregroundColor(.white)
                    .background(Color.gray)
                    .frame(width: 100, height: 100)
                    .cornerRadius(10)
            }
            
            VStack(alignment: .leading, spacing: 4){
                Text(article.title ?? "")
                    .foregroundColor(.black)
                    .font(.system(size: 18, weight: .semibold))
                Text(article.source ?? "N/A")
                    .foregroundColor(.gray)
                    .font(.footnote)
             }
         }
        .padding(.vertical
        ,10)
    }
}

自定义错误View核心

struct ErrorView: View {
    typealias ErrorViewActionHander = () -> Void
    let hander : ErrorViewActionHander
    internal init(error: Error,
                  hander: @escaping ErrorView.ErrorViewActionHander
    ){
        self.error = error
        self.hander = hander
    }
    
    let error: Error
    var body: some View {
        VStack{
            Image(systemName: "exclamationmark.icloud.fill")
                .foregroundColor(.gray)
                .font(.system(size: 50, weight: .heavy))
            Text("some error")
                .font(.system(size: 30))
                .fontWeight(.bold)
            Text(error.localizedDescription)
                .padding(4)
            Button {
                hander()
            } label: {
                Text("retry")
            }
            .foregroundColor(.white)
            .padding(.vertical,17)
            .padding(.horizontal,30)
            .background(Color.blue)
            .font(.system(size: 15, weight: .heavy))
            .cornerRadius(10)

        }
    }
}

数据api来源 https://api.lil.software/news,需要未批嗯

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/web/993721.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存