如何在 SwiftUI 中使用 .refreshable 调用 API 并刷新列表
How to use .refreshable in SwiftUI to call API and refresh list
我正在尝试将 .refreshable 添加到我的 SwiftUI openweathermap 应用程序,以便下拉和刷新从 API 返回到应用程序的值。我将我的应用程序设置为允许用户在文本字段中输入城市名称,点击搜索按钮,然后在 sheet 中查看该城市的天气详细信息。关闭 sheet 后,用户可以在列表中看到所有 his/her 之前搜索过的城市作为导航 link,城市名称和温度在每个列表中可见 link .我试图将 .refreshable {}
添加到我的 ContentView 中的列表中。我尝试设置 .refreshable 以在我的 ViewModel 中调用 fetchWeather()
,而 ViewModel 又设置为将用户输入的 cityName 作为参数传递到 API URL(也在 ViewModel 中).但是,我现在认为这无法刷新天气数据,因为调用 fetchWeather()
的操作是在工具栏按钮中定义的,而不是在列表中定义的。知道如何设置 .refreshable 来刷新列表中每个搜索城市的天气数据吗?请参阅下面的代码。谢谢!
内容视图
struct ContentView: View {
// Whenever something in the viewmodel changes, the content view will know to update the UI related elements
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State private var showingDetail = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(viewModel.cityNameList) { city in
NavigationLink(destination: DetailView(detail: city), label: {
Text(city.name).font(.system(size: 32))
Spacer()
Text("\(city.main.temp, specifier: "%.0f")°").font(.system(size: 32))
})
}.onDelete { index in
self.viewModel.cityNameList.remove(atOffsets: index)
}
}.refreshable {
viewModel.fetchWeather(for: cityName)
}
}.navigationTitle("Weather")
.toolbar {
ToolbarItem(placement: (.bottomBar)) {
HStack {
TextField("Enter City Name", text: $cityName)
.frame(minWidth: 100, idealWidth: 150, maxWidth: 240, minHeight: 30, idealHeight: 40, maxHeight: 50, alignment: .leading)
Spacer()
Button(action: {
viewModel.fetchWeather(for: cityName)
cityName = ""
self.showingDetail.toggle()
}) {
HStack {
Image(systemName: "plus")
.font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}.sheet(isPresented: $showingDetail) {
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
}
}
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
详细视图
struct DetailView: View {
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State var selection: Int? = nil
var detail: WeatherModel
var body: some View {
VStack(spacing: 20) {
Text(detail.name)
.font(.system(size: 32))
Text("\(detail.main.temp, specifier: "%.0f")°")
.font(.system(size: 44))
Text(detail.firstWeatherInfo())
.font(.system(size: 24))
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(detail: WeatherModel.init())
}
}
视图模型
class WeatherViewModel: ObservableObject {
@Published var cityNameList = [WeatherModel]()
func fetchWeather(for cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&units=imperial&appid=<MyAPIKey>") else { return }
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else { return }
do {
let model = try JSONDecoder().decode(WeatherModel.self, from: data)
DispatchQueue.main.async {
self.cityNameList.append(model)
}
}
catch {
print(error) // <-- you HAVE TO deal with errors here
}
}
task.resume()
}
}
型号
struct WeatherModel: Identifiable, Codable {
let id = UUID()
var name: String = ""
var main: CurrentWeather = CurrentWeather()
var weather: [WeatherInfo] = []
func firstWeatherInfo() -> String {
return weather.count > 0 ? weather[0].description : ""
}
}
struct CurrentWeather: Codable {
var temp: Double = 0.0
}
struct WeatherInfo: Codable {
var description: String = ""
}
我会做的是这个(或类似的更并发和防错的方法):
在WeatherViewModel
中添加更新所有城市天气信息的功能:
func updateAll() {
// keep a copy of all the cities names
let listOfNames = cityNameList.map{[=10=].name}
// remove all current info
cityNameList.removeAll()
// fetch the up-to-date weather info
for city in listOfNames {
fetchWeather(for: city)
}
}
并在 ContentView
中:
.refreshable {
viewModel.updateAll()
}
注意:DetailView
中不应包含 @StateObject var viewModel = WeatherViewModel()
。
您应该传入模型(如果需要),并具有 @ObservedObject var viewModel: WeatherViewModel
.
编辑 1:
由于 fetching/appending 新的天气信息是异步的,它
可能导致 cityNameList
.
中的顺序不同
对于少数城市,可以尝试在每个fetchWeather
之后对城市进行排序,例如:
func fetchWeather(for cityName: String)
...
DispatchQueue.main.async {
self.cityNameList.append(model)
self.cityNameList.sort(by: {[=12=].name < .name}) // <-- here
}
...
如果要获取大量城市时这变得很麻烦,
你将需要一个更健壮和独立的排序机制。
EDIT2:这是一个更强大的排序方案。
从 fetchWeather
中删除 self.cityNameList.sort(by: {[=27=].name < .name})
。
在ContentView
中对城市进行排序,例如:
ForEach(viewModel.cityNameList.sorted(by: { [=13=].name < .name })) { city in ... }
并使用:
.onDelete { index in
delete(with: index)
}
与:
private func delete(with indexSet: IndexSet) {
// must sort the list as in the body
let sortedList = viewModel.cityNameList.sorted(by: { [=15=].name < .name })
if let firstNdx = indexSet.first {
// get the city from the sorted list
let theCity = sortedList[firstNdx]
// get the index of the city from the viewModel, and remove it
if let ndx = viewModel.cityNameList.firstIndex(of: theCity) {
viewModel.cityNameList.remove(at: ndx)
}
}
}
EDIT3:保持原来添加的顺序。
删除 EDIT1
和 EDIT2
的所有模组。
在WeatherViewModel
中添加这些函数:
func updateAllWeather() {
let listOfNames = cityNameList.map{[=16=].name}
// fetch the up-to-date weather info
for city in listOfNames {
fetchWeather(for: city)
}
}
func addToList( _ city: WeatherModel) {
// if already have this city, just update
if let ndx = cityNameList.firstIndex(where: {[=16=].name == city.name}) {
cityNameList[ndx].main = city.main
cityNameList[ndx].weather = city.weather
} else {
// add a new city
cityNameList.append(city)
}
}
在fetchWeather
中,使用:
DispatchQueue.main.async {
self.addToList(model)
}
在ContentView
,
.onDelete { index in
viewModel.cityNameList.remove(atOffsets: index)
}
.refreshable {
viewModel.updateAll()
}
请注意,异步函数 fetchWeather
的逻辑存在错误。
您应该使用完成处理程序在完成后继续。
特别是在 add
按钮中使用时。
最后编辑:
这是我在实验中使用的代码 swift 5.5 async/await:
struct ContentView: View {
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State private var showingDetail = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(viewModel.cityNameList) { city in
NavigationLink(destination: DetailView(detail: city), label: {
Text(city.name).font(.system(size: 32))
Spacer()
Text("\(city.main.temp, specifier: "%.0f")°").font(.system(size: 32))
})
}.onDelete { index in
viewModel.cityNameList.remove(atOffsets: index)
}
}.refreshable {
viewModel.updateAllWeather() // <--- here
}
}
.environmentObject(viewModel) // <--- here
.navigationTitle("Weather")
.toolbar {
ToolbarItem(placement: (.bottomBar)) {
HStack {
TextField("Enter City Name", text: $cityName)
.frame(minWidth: 100, idealWidth: 150, maxWidth: 240, minHeight: 30, idealHeight: 40, maxHeight: 50, alignment: .leading)
Spacer()
Button(action: {
Task { // <--- here
await viewModel.fetchWeather(for: cityName)
cityName = ""
showingDetail.toggle()
}
}) {
HStack {
Image(systemName: "plus").font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}
.sheet(isPresented: $showingDetail) {
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
.environmentObject(viewModel) // <--- here
}
}
}
}
}
}
}
}
}
struct DetailView: View {
@EnvironmentObject var viewModel: WeatherViewModel // <--- here
@State private var cityName = ""
@State var selection: Int? = nil
var detail: WeatherModel
var body: some View {
VStack(spacing: 20) {
Text(detail.name)
.font(.system(size: 32))
Text("\(detail.main.temp, specifier: "%.0f")°")
.font(.system(size: 44))
Text(detail.firstWeatherInfo())
.font(.system(size: 24))
}
}
}
class WeatherViewModel: ObservableObject {
@Published var cityNameList = [WeatherModel]()
// add or update function
func addToList( _ city: WeatherModel) {
// if already have this city, just update it
if let ndx = cityNameList.firstIndex(where: {[=19=].name == city.name}) {
cityNameList[ndx].main = city.main
cityNameList[ndx].weather = city.weather
} else {
// add a new city to the list
cityNameList.append(city)
}
}
// note the async
func fetchWeather(for cityName: String) async {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&units=imperial&appid=YOURKEY") else { return }
do {
let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url))
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
// throw URLError(.badServerResponse) // todo
print(URLError(.badServerResponse))
return
}
let result = try JSONDecoder().decode(WeatherModel.self, from: data)
DispatchQueue.main.async {
self.addToList(result)
}
}
catch {
return // todo
}
}
// fetch all the latest weather info concurrently
func updateAllWeather() {
let listOfNames = cityNameList.map{[=19=].name}
Task {
await withTaskGroup(of: Void.self) { group in
for city in listOfNames {
group.addTask { await self.fetchWeather(for: city) }
}
}
}
}
}
import UIKit
class VC: UIViewController {
var arrlabelpass = [String]()
var arrimagepass = [UIImage]()
var arrTable = ["1","1","1","1","1","1"]
var arrTablelbl = ["12","14","13","11","16","17"]
let itemcell = "CCell"
let itemcell1 = "TCell"
var refresh : UIRefreshControl {
let ref = UIRefreshControl()
ref.addTarget(self, action: #selector(handler(_:)), for: .valueChanged)
return ref
}
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
collectionView.delegate = self
collectionView.dataSource = self
let nib = UINib (nibName: itemcell, bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: itemcell)
let nib1 = UINib(nibName: itemcell1, bundle: nil)
tableView.register(nib1, forCellReuseIdentifier: itemcell1)
collectionView.addSubview(refresh)
collectionView.isHidden = true
}
@objc func handler(_ control:UIRefreshControl) {
// collectionView.backgroundColor = self.randomElement()
control.endRefreshing()
}
}
extension VC : UITableViewDelegate , UITableViewDataSource , UICollectionViewDelegate , UICollectionViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrTable.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tCell = tableView.dequeueReusableCell(withIdentifier: itemcell1, for: indexPath)as! TCell
tCell.tIMG.image = UIImage(named: arrTable[indexPath.row])
tCell.LBL.text = arrTablelbl[indexPath.row]
return tCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let lblindex = arrTablelbl[indexPath.row]
let imageindex = UIImage(named: arrTable[indexPath.row])
arrlabelpass.append(lblindex)
arrimagepass.append(imageindex!)
collectionView.reloadData()
collectionView.isHidden = false
arrTablelbl[indexPath.row].removeAll()
arrTable[indexPath.row].removeAll()
tableView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrlabelpass.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let ccell = collectionView.dequeueReusableCell(withReuseIdentifier: itemcell, for: indexPath)as! CCell
ccell.cIMG.image = arrimagepass[indexPath.row]
ccell.cLBL.text = arrlabelpass[indexPath.row]
return ccell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tableView.reloadData()
arrimagepass.remove(at: indexPath.row)
arrlabelpass.remove(at: indexPath.row)
collectionView.reloadData()
}
}
我正在尝试将 .refreshable 添加到我的 SwiftUI openweathermap 应用程序,以便下拉和刷新从 API 返回到应用程序的值。我将我的应用程序设置为允许用户在文本字段中输入城市名称,点击搜索按钮,然后在 sheet 中查看该城市的天气详细信息。关闭 sheet 后,用户可以在列表中看到所有 his/her 之前搜索过的城市作为导航 link,城市名称和温度在每个列表中可见 link .我试图将 .refreshable {}
添加到我的 ContentView 中的列表中。我尝试设置 .refreshable 以在我的 ViewModel 中调用 fetchWeather()
,而 ViewModel 又设置为将用户输入的 cityName 作为参数传递到 API URL(也在 ViewModel 中).但是,我现在认为这无法刷新天气数据,因为调用 fetchWeather()
的操作是在工具栏按钮中定义的,而不是在列表中定义的。知道如何设置 .refreshable 来刷新列表中每个搜索城市的天气数据吗?请参阅下面的代码。谢谢!
内容视图
struct ContentView: View {
// Whenever something in the viewmodel changes, the content view will know to update the UI related elements
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State private var showingDetail = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(viewModel.cityNameList) { city in
NavigationLink(destination: DetailView(detail: city), label: {
Text(city.name).font(.system(size: 32))
Spacer()
Text("\(city.main.temp, specifier: "%.0f")°").font(.system(size: 32))
})
}.onDelete { index in
self.viewModel.cityNameList.remove(atOffsets: index)
}
}.refreshable {
viewModel.fetchWeather(for: cityName)
}
}.navigationTitle("Weather")
.toolbar {
ToolbarItem(placement: (.bottomBar)) {
HStack {
TextField("Enter City Name", text: $cityName)
.frame(minWidth: 100, idealWidth: 150, maxWidth: 240, minHeight: 30, idealHeight: 40, maxHeight: 50, alignment: .leading)
Spacer()
Button(action: {
viewModel.fetchWeather(for: cityName)
cityName = ""
self.showingDetail.toggle()
}) {
HStack {
Image(systemName: "plus")
.font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}.sheet(isPresented: $showingDetail) {
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
}
}
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
详细视图
struct DetailView: View {
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State var selection: Int? = nil
var detail: WeatherModel
var body: some View {
VStack(spacing: 20) {
Text(detail.name)
.font(.system(size: 32))
Text("\(detail.main.temp, specifier: "%.0f")°")
.font(.system(size: 44))
Text(detail.firstWeatherInfo())
.font(.system(size: 24))
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(detail: WeatherModel.init())
}
}
视图模型
class WeatherViewModel: ObservableObject {
@Published var cityNameList = [WeatherModel]()
func fetchWeather(for cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&units=imperial&appid=<MyAPIKey>") else { return }
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else { return }
do {
let model = try JSONDecoder().decode(WeatherModel.self, from: data)
DispatchQueue.main.async {
self.cityNameList.append(model)
}
}
catch {
print(error) // <-- you HAVE TO deal with errors here
}
}
task.resume()
}
}
型号
struct WeatherModel: Identifiable, Codable {
let id = UUID()
var name: String = ""
var main: CurrentWeather = CurrentWeather()
var weather: [WeatherInfo] = []
func firstWeatherInfo() -> String {
return weather.count > 0 ? weather[0].description : ""
}
}
struct CurrentWeather: Codable {
var temp: Double = 0.0
}
struct WeatherInfo: Codable {
var description: String = ""
}
我会做的是这个(或类似的更并发和防错的方法):
在WeatherViewModel
中添加更新所有城市天气信息的功能:
func updateAll() {
// keep a copy of all the cities names
let listOfNames = cityNameList.map{[=10=].name}
// remove all current info
cityNameList.removeAll()
// fetch the up-to-date weather info
for city in listOfNames {
fetchWeather(for: city)
}
}
并在 ContentView
中:
.refreshable {
viewModel.updateAll()
}
注意:DetailView
中不应包含 @StateObject var viewModel = WeatherViewModel()
。
您应该传入模型(如果需要),并具有 @ObservedObject var viewModel: WeatherViewModel
.
编辑 1:
由于 fetching/appending 新的天气信息是异步的,它
可能导致 cityNameList
.
对于少数城市,可以尝试在每个fetchWeather
之后对城市进行排序,例如:
func fetchWeather(for cityName: String)
...
DispatchQueue.main.async {
self.cityNameList.append(model)
self.cityNameList.sort(by: {[=12=].name < .name}) // <-- here
}
...
如果要获取大量城市时这变得很麻烦, 你将需要一个更健壮和独立的排序机制。
EDIT2:这是一个更强大的排序方案。
从 fetchWeather
中删除 self.cityNameList.sort(by: {[=27=].name < .name})
。
在ContentView
中对城市进行排序,例如:
ForEach(viewModel.cityNameList.sorted(by: { [=13=].name < .name })) { city in ... }
并使用:
.onDelete { index in
delete(with: index)
}
与:
private func delete(with indexSet: IndexSet) {
// must sort the list as in the body
let sortedList = viewModel.cityNameList.sorted(by: { [=15=].name < .name })
if let firstNdx = indexSet.first {
// get the city from the sorted list
let theCity = sortedList[firstNdx]
// get the index of the city from the viewModel, and remove it
if let ndx = viewModel.cityNameList.firstIndex(of: theCity) {
viewModel.cityNameList.remove(at: ndx)
}
}
}
EDIT3:保持原来添加的顺序。
删除 EDIT1
和 EDIT2
的所有模组。
在WeatherViewModel
中添加这些函数:
func updateAllWeather() {
let listOfNames = cityNameList.map{[=16=].name}
// fetch the up-to-date weather info
for city in listOfNames {
fetchWeather(for: city)
}
}
func addToList( _ city: WeatherModel) {
// if already have this city, just update
if let ndx = cityNameList.firstIndex(where: {[=16=].name == city.name}) {
cityNameList[ndx].main = city.main
cityNameList[ndx].weather = city.weather
} else {
// add a new city
cityNameList.append(city)
}
}
在fetchWeather
中,使用:
DispatchQueue.main.async {
self.addToList(model)
}
在ContentView
,
.onDelete { index in
viewModel.cityNameList.remove(atOffsets: index)
}
.refreshable {
viewModel.updateAll()
}
请注意,异步函数 fetchWeather
的逻辑存在错误。
您应该使用完成处理程序在完成后继续。
特别是在 add
按钮中使用时。
最后编辑:
这是我在实验中使用的代码 swift 5.5 async/await:
struct ContentView: View {
@StateObject var viewModel = WeatherViewModel()
@State private var cityName = ""
@State private var showingDetail = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(viewModel.cityNameList) { city in
NavigationLink(destination: DetailView(detail: city), label: {
Text(city.name).font(.system(size: 32))
Spacer()
Text("\(city.main.temp, specifier: "%.0f")°").font(.system(size: 32))
})
}.onDelete { index in
viewModel.cityNameList.remove(atOffsets: index)
}
}.refreshable {
viewModel.updateAllWeather() // <--- here
}
}
.environmentObject(viewModel) // <--- here
.navigationTitle("Weather")
.toolbar {
ToolbarItem(placement: (.bottomBar)) {
HStack {
TextField("Enter City Name", text: $cityName)
.frame(minWidth: 100, idealWidth: 150, maxWidth: 240, minHeight: 30, idealHeight: 40, maxHeight: 50, alignment: .leading)
Spacer()
Button(action: {
Task { // <--- here
await viewModel.fetchWeather(for: cityName)
cityName = ""
showingDetail.toggle()
}
}) {
HStack {
Image(systemName: "plus").font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}
.sheet(isPresented: $showingDetail) {
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
.environmentObject(viewModel) // <--- here
}
}
}
}
}
}
}
}
}
struct DetailView: View {
@EnvironmentObject var viewModel: WeatherViewModel // <--- here
@State private var cityName = ""
@State var selection: Int? = nil
var detail: WeatherModel
var body: some View {
VStack(spacing: 20) {
Text(detail.name)
.font(.system(size: 32))
Text("\(detail.main.temp, specifier: "%.0f")°")
.font(.system(size: 44))
Text(detail.firstWeatherInfo())
.font(.system(size: 24))
}
}
}
class WeatherViewModel: ObservableObject {
@Published var cityNameList = [WeatherModel]()
// add or update function
func addToList( _ city: WeatherModel) {
// if already have this city, just update it
if let ndx = cityNameList.firstIndex(where: {[=19=].name == city.name}) {
cityNameList[ndx].main = city.main
cityNameList[ndx].weather = city.weather
} else {
// add a new city to the list
cityNameList.append(city)
}
}
// note the async
func fetchWeather(for cityName: String) async {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&units=imperial&appid=YOURKEY") else { return }
do {
let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url))
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
// throw URLError(.badServerResponse) // todo
print(URLError(.badServerResponse))
return
}
let result = try JSONDecoder().decode(WeatherModel.self, from: data)
DispatchQueue.main.async {
self.addToList(result)
}
}
catch {
return // todo
}
}
// fetch all the latest weather info concurrently
func updateAllWeather() {
let listOfNames = cityNameList.map{[=19=].name}
Task {
await withTaskGroup(of: Void.self) { group in
for city in listOfNames {
group.addTask { await self.fetchWeather(for: city) }
}
}
}
}
}
import UIKit
class VC: UIViewController {
var arrlabelpass = [String]()
var arrimagepass = [UIImage]()
var arrTable = ["1","1","1","1","1","1"]
var arrTablelbl = ["12","14","13","11","16","17"]
let itemcell = "CCell"
let itemcell1 = "TCell"
var refresh : UIRefreshControl {
let ref = UIRefreshControl()
ref.addTarget(self, action: #selector(handler(_:)), for: .valueChanged)
return ref
}
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
collectionView.delegate = self
collectionView.dataSource = self
let nib = UINib (nibName: itemcell, bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: itemcell)
let nib1 = UINib(nibName: itemcell1, bundle: nil)
tableView.register(nib1, forCellReuseIdentifier: itemcell1)
collectionView.addSubview(refresh)
collectionView.isHidden = true
}
@objc func handler(_ control:UIRefreshControl) {
// collectionView.backgroundColor = self.randomElement()
control.endRefreshing()
}
}
extension VC : UITableViewDelegate , UITableViewDataSource , UICollectionViewDelegate , UICollectionViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrTable.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tCell = tableView.dequeueReusableCell(withIdentifier: itemcell1, for: indexPath)as! TCell
tCell.tIMG.image = UIImage(named: arrTable[indexPath.row])
tCell.LBL.text = arrTablelbl[indexPath.row]
return tCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let lblindex = arrTablelbl[indexPath.row]
let imageindex = UIImage(named: arrTable[indexPath.row])
arrlabelpass.append(lblindex)
arrimagepass.append(imageindex!)
collectionView.reloadData()
collectionView.isHidden = false
arrTablelbl[indexPath.row].removeAll()
arrTable[indexPath.row].removeAll()
tableView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrlabelpass.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let ccell = collectionView.dequeueReusableCell(withReuseIdentifier: itemcell, for: indexPath)as! CCell
ccell.cIMG.image = arrimagepass[indexPath.row]
ccell.cLBL.text = arrlabelpass[indexPath.row]
return ccell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tableView.reloadData()
arrimagepass.remove(at: indexPath.row)
arrlabelpass.remove(at: indexPath.row)
collectionView.reloadData()
}
}