Simple App in SwiftUI

lyvennitha sasikumar
4 min readAug 5, 2021

Hey Guys! Here i got one more new concept in SwiftUI for you. Here i implemented List with pop up where the datas come from an open API provided by gov.in. Here i used fish related API i’d get from https://www.fishwatch.gov/api/species. And used the species image and species name to make list in SwiftUI.

Fish App

Prepare for Network Layer

Here i used URLSession to fetch data from the fishwatch API. Create Network Folder. And Create NetworkLayer.swift file in that folder. Create a singleton class.

struct Network{
static var shared = Network()
}

Add some network constants like URL and httpmethod in enum

enum NetworkConstants: String{
case URL = "https://www.fishwatch.gov/api/species"
case httpMethod = "GET"
}

Add Model class for the result JSON in model class file. Here i wont share that as it contains a large set of struct datas. I just provide the typealias for it.

typealias MyFishRecordData = [MyFishRecord]

Create a method to implement URLsession task for getting data. Final Network class looks like below.

struct Network{
static var shared = Network()
var fishRecords = MyFishRecordData()
func getData(completion: @escaping (Result<MyFishRecordData, Error>) -> Void){
let urlRequest = URLRequest(url: URL(string: NetworkConstants.URL.rawValue)!)
URLSession.shared.dataTask(with: urlRequest){ data,response,error in
let
fishRecords = try? JSONDecoder().decode(MyFishRecordData.self, from: data!)
print(fishRecords?.count ?? 0, "count")
completion(.success(fishRecords!))
}.resume()
}
}

Lets prepare for ContentView.swift. Start with creating list with navigation title.

struct ContentView: View {
@State var fishData = MyFishRecordData()
var
body: some View {
NavigationView {
VStack{
List(fishData) { fish in
}
}
}.onAppear(){
getDataforFish()
}
.navigationTitle("Fishes")
}
}
}
}

Output:

OutPut

OOPS!🤭. We forgot to create cell!

Its time to create cells for List.

Here Create a separate file. I just named it as FishRow.swift. Here i used SDWebimage SDK for downloading image from URL. PodFile initiation is normal as like as before. Just add import SDWebImageSwiftUI.

struct FishRow: View {  var fish: MyFishRecord  var body: some View {   HStack {    AnimatedImage(url: URL(string: fish.speciesIllustrationPhoto?.src ?? "")!)   .resizable()    .frame(width: 70, height: 70)  Text(verbatim: fish.speciesName ?? "")  } }}

Result:

Output

Now we will add pop up to list to view more about the listed fishes. Lets create a popup view. Here the datas for more about fish are came in HTML string. I gonna show that in a scroll view for label. Let me explain here how i done this.

Create a PopupView.swift file. Lets create some enum for convenience to make it as Alert look.

enum AlertAction {  case ok  case cancel}

Create a view for popup. I create popup with a image, text, ok and cancel button actions. Below is the code set where we need image, text data from API.

struct AlertView: View {@Binding var shown: Bool@Binding var closureA: AlertAction?var message: Stringvar fish: MyFishRecordvar body: some View {VStack {AnimatedImage(url: URL(string: fish.speciesIllustrationPhoto?.src ?? "")!).resizable().frame(width: 250, height: 250)Spacer()ScrollView{HTMLText(html: fish.biology ?? "", width: 300).padding(15)}Spacer()Divider()HStack {Button("Close") {closureA = .cancelshown.toggle()}.frame(width: UIScreen.main.bounds.width/2-30, height: 40).foregroundColor(.white)Button("Ok") {closureA = .okshown.toggle()}.frame(width: UIScreen.main.bounds.width/2-30, height: 40).foregroundColor(.white}}.frame(width: UIScreen.main.bounds.width-50, height: UIScreen.main.bounds.height - 200).background(Color.black.opacity(0.5)).cornerRadius(12).clipped()}}

What is that HTML text. Yes that is where we convert the html string to normal customised String. He i provided code below for HTMLText.

struct HTMLText: UIViewRepresentable {let html: Stringvar width: CGFloatfunc makeUIView(context: UIViewRepresentableContext<Self>) -> UILabel {let label = UILabel()label.numberOfLines = 0var attributes = [NSAttributedString.Key.font:UIFont(name: "Helvetica", size: 20.0)!,NSAttributedString.Key.foregroundColor: UIColor.white] as NSDictionary?DispatchQueue.main.async {let data = Data(self.html.utf8)if let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: &attributes) {label.attributedText = attributedStringlabel.textColor = .whitelabel.font = UIFont.systemFont(ofSize: 20)label.preferredMaxLayoutWidth = width}}return label}func updateUIView(_ uiView: UILabel, context: Context) {
}
}

Here in the above code, i just initiated a UILabel instance and use it by customising color and font size for attributed string get from HTML String to String converted.

How to use the above popup in List.

AlertView(shown: $shown, closureA: $c, message: message, fish: fishData[selectedIndex ?? 0])

Final Code of ContentView.swift is looks like below!

struct ContentView: View {@State var fishData = MyFishRecordData()@State var shown = false@State var message = ""@State var c: AlertAction?@State var fishD: MyFishRecord?@State var selectedIndex: Int?var body: some View {NavigationView {VStack{List(fishData) { fish inFishRow(fish: fish).onTapGesture {selectedIndex = fishData.firstIndex(where: {$0.speciesName == fish.speciesName})shown.toggle()}}}.onAppear(){getDataforFish()}.navigationTitle("Fishes")}if fishData.count > 0 && shown{AlertView(shown: $shown, closureA: $c, message: message, fish: fishData[selectedIndex ?? 0])}}}

Where to call the API.

extension ContentView{func getDataforFish(){let selfi = self Network.shared.getData(completion: {(result) inswitch(result){case .success(let records):DispatchQueue.main.async {selfi.fishData = records}case .failure(_):print("An error occurred")}})}}

Final Result for popup:

Popup

Just unable to share the code. Soon code for all blogs available in every blog.

HAPPY CODING!🌎

--

--

lyvennitha sasikumar

Passionate iOS developer chasing my dreams toward success