UIpageViewController And Timer - swift

i have a UIPageViewController in one of My UICollectionViewCell at the top of my screen(height = frame.height/3) it contains a number of images
and it is working good but i need it to be scrolled to the next image automattically every 3 seconds what should i do?
import UIKit
class PageViewController: UIPageViewController , UIPageViewControllerDataSource{
var scrollingTimer = Timer()
let imageNames = ["Apple_Watch_Main" , "Pic2" , "Pic3"]
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
let frameViewController = FrameViewController()
frameViewController.imageName = imageNames.first
let viewControllers = [frameViewController]
setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentImageName = (viewController as! FrameViewController).imageName
let currentIndex = imageNames.index(of: currentImageName!)
if currentIndex! > 0 {
let frameViewController = FrameViewController()
frameViewController.imageName = imageNames[currentIndex! - 1]
return frameViewController
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentImageName = (viewController as! FrameViewController).imageName
let currentIndex = imageNames.index(of: currentImageName!)
if currentIndex! < imageNames.count - 1 {
let frameViewController = FrameViewController()
frameViewController.imageName = imageNames[currentIndex! + 1]
return frameViewController
}
return nil
}
}
and i added to my cell here
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.item {
case 0 :
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as!ImageCell
let pagecontroller = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
self.addChildViewController(pagecontroller)
cell.addSubview(pagecontroller.view)
pagecontroller.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/3)
return cell
case 1 :
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "filterandorganize", for: indexPath) as! FilterAndOrganize
return cell
case 2 :
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Offers", for: indexPath) as! Offers
return cell
case 3 :
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OfferedProducts", for: indexPath) as! OfferedProducts
cell.firstViewController = self
return cell
default:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Offers", for: indexPath) as! Offers
return cell
}
}
in case 0
I searched a lot and i found some questions like this but without any complete and correct answer
HERE IS THE ANSWER I FOUND but it still have one bug and that is when the user swipes it self the autoscroll is not perfect and maybe jump of one pic to another
class PageViewController: UIPageViewController , UIPageViewControllerDataSource{
var index = 0
let imageNames = ["Apple_Watch_Main" , "Pic2" , "Pic3"]
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
let frameViewController = FrameViewController()
frameViewController.imageName = imageNames[index]
index += 1
let viewControllers = [frameViewController]
setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil)
Timer.scheduledTimer(timeInterval: 6.0 ,
target: self,
selector: #selector(myFunc(_:)),
userInfo: index,
repeats: true)
}
//FIXME: needs some fixes
func myFunc(_ timer: Timer) {
if index == imageNames.count {
index = 0
}
else {
self.changePIC(index)
index += 1
}
}
func changePIC(_ i: Int) {
let frameViewController = FrameViewController()
frameViewController.imageName = imageNames[i]
let viewControllers = [frameViewController]
setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil)
}

First crate a Timer with timeInterval and option repeats seat to true.
Example:
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(scrollToNextItem), userInfo: nil, repeats: true)
Now you have Timer that will trigger scrollToNextItem method every 3 seconds.
Now read about setViewControllers(_:direction:animated:completion:) to know how to set view controllers to be displayed.
Than implement scrollToNextItem method with required logic.

Related

how to call/show action sheet for taking or choose photo from gallery on Main VC after tapped on TableViewCell Image(swift)

Here I Try MVVM pattern to achieve TableView but for showing alert I face problems , it compiles successfully but not showing alert.
[Result] on the tapped on profile pic which is in tableview cell, I want to show alert
TableViewCell
import Foundation
import UIKit
class ParentsImageCell : UITableViewCell {
weak var myVC : ProfileOfParentsDetailsViewController?
var parentProfileVC = ProfileOfParentsDetailsViewController()
#IBOutlet weak var imageProfile : UIImageView!
var items : ParentProfileViewModelItem? {
didSet {
guard let items = items as? ParentProfileViewModelProfileItem else {
return
}
imageProfile?.image = UIImage(named: items.profileImg)
}
}
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
override func awakeFromNib() {
super.awakeFromNib()
imageProfile?.layer.cornerRadius = 62
imageProfile?.clipsToBounds = true
imageProfile?.contentMode = .scaleAspectFill
imageProfile?.backgroundColor = UIColor.lightGray
//Add Tapped Gesture
imageProfile.isUserInteractionEnabled = true
let gesture = UITapGestureRecognizer(
target: self,
action: #selector(didTappedChangeProfilePic))
gesture.numberOfTapsRequired = 1
gesture.numberOfTouchesRequired = 1
imageProfile.addGestureRecognizer(gesture)
}
#objc private func didTappedChangeProfilePic(){
print("tapped on imageView")
presentPhotoActionSheet()
}
override func prepareForReuse() {
super.prepareForReuse()
imageProfile?.image = nil
}
}
extension ParentsImageCell : UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
func presentPhotoActionSheet(){
let actionSheet = UIAlertController(title: "Profile Picture", message: "How would you write to select a picture", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
actionSheet.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: {[weak self] _ in
self?.presentCamera()
}))
actionSheet.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { [weak self]_ in
self?.presentPhotoPicker()
}))
myVC?.present(actionSheet , animated: true)
}
func presentCamera(){
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.delegate = self
vc.allowsEditing = true
myVC?.present(vc , animated: true)
}
func presentPhotoPicker(){
let vc = UIImagePickerController()
vc.sourceType = .photoLibrary
vc.delegate = self
vc.allowsEditing = true
myVC?.present(vc , animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:
[UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
return
}
self.imageProfile.image = selectedImage
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
ViewModel
class ParentProfileViewModel: NSObject {
var items = [ParentProfileViewModelItem]()
var reloadSections: ((_ section: Int) -> Void)?
override init() {
super.init()
guard let data = dataFromFile("ServerData"),
let profile = Profile(data: data) else {
return
}
// initialization code will go here
if let profile = profile.pictureUrl {
let profileItem = ParentProfileViewModelProfileItem(profileImg: profile)
items.append(profileItem)
}
if let name = profile.fullName {
let nameItem = ParentProfileViewModelNameItem(name: name)
items.append(nameItem)
}
if let email = profile.email {
let emailItem = ParentProfileViewModelEmailItem(email: email)
items.append(emailItem)
}
let coach = profile.coach
if !coach.isEmpty {
let coachItem = ParentProfileViewModelCoachItem(coach: coach)
items.append(coachItem)
}
let candidate = profile.candidate
if !candidate.isEmpty {
let candidateItem = ParentProfileViewModelCandidateItem(candidate: candidate)
items.append(candidateItem)
}
}
}
//MARK:- TableviewDatasource & Delegates
extension ParentProfileViewModel: UITableViewDataSource {
//Number of section
func numberOfSections(in tableView: UITableView) -> Int {
return items.count
}
//Number of RowInSection
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let item = items[section]
guard item.isCollapsible else {
return item.rowCount
}
if item.isCollapsed {
return 0
} else {
return item.rowCount
}
}
//Cell for row at indexpath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// we will configure the cells here
let item = items[indexPath.section]
switch item.type {
case .profileImg:
let vc = ProfileOfParentsDetailsViewController()
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsImageCell.identifier, for: indexPath) as? ParentsImageCell {
cell.items = item
cell.myVC = vc
return cell
}
case .fullName:
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsFulNameCell.identifier, for: indexPath) as? ParentsFulNameCell {
cell.items = item
return cell
}
case .email:
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsEmailCell.identifier, for: indexPath) as? ParentsEmailCell {
cell.items = item
return cell
}
case .candidate:
if let item = item as? ParentProfileViewModelCandidateItem, let cell = tableView.dequeueReusableCell(withIdentifier: CandidatCell.identifier, for: indexPath) as? CandidatCell {
let candidate = item.candidate[indexPath.row]
cell.item = candidate
return cell
}
case .coach:
if let item = item as? ParentProfileViewModelCoachItem, let cell = tableView.dequeueReusableCell(withIdentifier: ParentCoachCell.identifier, for: indexPath) as? ParentCoachCell {
cell.item = item.coach[indexPath.row]
return cell
}
}
return UITableViewCell()
}
}
ViewController
import Foundation
import UIKit
class ProfileOfParentsDetailsViewController: UIViewController {
let viewModel = ParentProfileViewModel()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
viewModel.reloadSections = { [weak self] (section: Int) in
self?.tableView?.beginUpdates()
self?.tableView?.reloadSections([section], with: .fade)
self?.tableView?.endUpdates()
}
tableView?.dataSource = viewModel
tableView.delegate = viewModel
tableView?.estimatedRowHeight = 250
tableView?.rowHeight = UITableView.automaticDimension
tableView?.register(ParentsImageCell.nib, forCellReuseIdentifier: ParentsImageCell.identifier)
tableView?.register(ParentsEmailCell.nib, forCellReuseIdentifier: ParentsEmailCell.identifier)
tableView?.register(ParentsFulNameCell.nib, forCellReuseIdentifier: ParentsFulNameCell.identifier)
tableView?.register(CandidatCell.nib, forCellReuseIdentifier: CandidatCell.identifier)
tableView?.register(ParentCoachCell.nib, forCellReuseIdentifier: ParentCoachCell.identifier)
tableView?.register(ParentsHeaderView.nib, forHeaderFooterViewReuseIdentifier: ParentsHeaderView.identifier)
}
I try to get called alert Sheet , but I Failed and also comment about my approach towards MVVM
I try to called the tableview data source and delegate in VM
I try to get called alert Sheet , but I Failed and also comment about my approach towards MVVM
I try to called the tableview data source and delegate in VM

show data into tableview from api when category cell and store cell is selected or only one from previous controller in swift

I am creating an app in which i have a controller in which i have a tableview which will show data from previous screen when cell from c ategory section or cell from store section are selected or only one is selected then when i click the double arrow button shown in app then it should navigate to tableview screen and should show all the data from category or store or both into tableview. in tableview controller i have an API which is POST and has a body parameter of 'term_ids' which contains value as 556,574 which is comma seperated means the former one is for category and latter one is for store or both ids contains category data or store data. Means i have to pass two ids and make them comma seperated and then pass to tableview controller
lets say in category screenshot i have selected first two cells and when i tap on double arrow button the selected cell data should pass to another screen whose screenshot is as below:
api link for category data: https://api.myjson.com/bins/wggld
api link for store data: https://api.myjson.com/bins/1fc46p
api link for coupons which i need to populate into tableview based on ID from category and store api link: https://api.myjson.com/bins/1c4dip
my app screenshot for better understanding:
code for my category screen and main home view screen where i want to populate data is as below:
code for categoryViewController is as below:
class CategoryViewController: UIViewController {
//MARK: IBOutlets
#IBOutlet weak var store_bar: UIViewX!
#IBOutlet weak var store_title: UIButton!
#IBOutlet weak var category_title: UIButton!
#IBOutlet weak var category_bar: UIViewX!
#IBOutlet weak var categoryColView: UICollectionView!
var selectedBtnIndex:Int = 1
var selectedIndexPaths = [Int]()
var tempStoreIndexPaths = [Int]()
var categoryData = [ModelCategories]()
var storeData = [ModelStore]()
var arrCategoryImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
// register collectionview cell
self.categoryColView.register(UINib(nibName: "CategoryCell1", bundle: nil), forCellWithReuseIdentifier: "CategoryCell1")
self.categoryColView.register(UINib(nibName: "StoresCell", bundle: nil), forCellWithReuseIdentifier: "StoresCell")
self.store_bar.isHidden = true
self.getCategoriesList()
self.getStoreList()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
#objc func click_Category(sender: UIButton!) {
if sender.isSelected == true {
selectedIndexPaths.append(sender.tag)
sender.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
sender.isSelected = false
}else {
selectedIndexPaths = selectedIndexPaths.filter{ $0 != sender.tag }
sender.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
sender.isSelected = true
}
}
#objc func click_store(sender: UIButton!) {
if sender.isSelected == true {
tempStoreIndexPaths.append(sender.tag)
sender.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
sender.isSelected = false
}else {
tempStoreIndexPaths = tempStoreIndexPaths.filter{ $0 != sender.tag }
sender.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
sender.isSelected = true
}
}
//MARK: IBActions
#IBAction func categoriesData(_ sender: UIButton) {
selectedBtnIndex = 1
self.categoryColView.isHidden = false
self.store_bar.isHidden = true
self.category_title.setTitleColor(UIColor.black, for: .normal)
self.category_bar.isHidden = false
self.store_title.setTitleColor(UIColor(rgb: 0xAAAAAA), for: .normal)
self.categoryColView.reloadData()
}
#IBAction func storeData(_ sender: UIButton) {
selectedBtnIndex = 2
self.categoryColView.isHidden = false
self.store_bar.isHidden = false
self.store_title.setTitleColor(UIColor.black, for: .normal)
self.category_bar.isHidden = true
self.category_title.setTitleColor(UIColor(rgb: 0xAAAAAA), for: .normal)
self.categoryColView.reloadData()
}
#IBAction func showHomeScreen(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
if selectedBtnIndex == 1 {
vc.couponId = categoryData[sender.tag].ID!
}else {
vc.couponId = storeData[sender.tag].ID!
}
self.navigationController?.pushViewController(vc, animated:true)
}
#IBAction func toSearchPage(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SearchPageController") as! SearchPageController
self.navigationController?.pushViewController(vc, animated:true)
}
func getCategoriesList() {
if ApiUtillity.sharedInstance.isReachable() {
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseCategoryList>().API_GET(Url: SD_GET_CategoriesList, Params: [:], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
self.categoryData.removeAll()
let resul_array_tmp_new = modelResponse.categories! as NSArray
if resul_array_tmp_new.count > 0 {
for i in modelResponse.categories! {
if i.count != 0 {
if let image = UIImage(named: "\(i.slug!.uppercased())") {
self.arrCategoryImages.append(image)
self.categoryData.append(i)
}else {
self.arrCategoryImages.append(UIImage(named: "tickets")!)
self.categoryData.append(i)
}
}
}
}
}
else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.categoryColView.reloadData()
}) { (failed) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.view.makeToast(failed.localizedDescription)
}
}
else
{
self.view.makeToast("No Internet Connection..")
}
}
func getStoreList() {
if ApiUtillity.sharedInstance.isReachable() {
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseStoreList>().API_GET(Url: SD_GET_StoreList, Params: [:], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
self.storeData.removeAll()
let resul_array_tmp_new = modelResponse.store! as NSArray
if resul_array_tmp_new.count > 0 {
for i in modelResponse.store! {
if i.count != 0 {
self.storeData.append(i)
}
}
}
}
else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.categoryColView.reloadData()
}) { (failed) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.view.makeToast(failed.localizedDescription)
}
}
else
{
self.view.makeToast("No Internet Connection..")
}
}
}
//MARK: Delegate and Data Source Methods
extension CategoryViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if selectedBtnIndex == 1{
return categoryData.count
}else {
return storeData.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if selectedBtnIndex == 1{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCell1", for: indexPath) as! CategoryCell1
let dict = categoryData[indexPath.row]
if let catName = dict.name, catName.count != 0 {
cell.categoryName.text = catName
}
if let catOffersCount = dict.count {
if catOffersCount == 1 {
cell.catOfferCount.text = "\(catOffersCount)"+" "+"Offer"
}else {
cell.catOfferCount.text = "\(catOffersCount)"+" "+"Offers"
}
}
cell.categoryImage.image = arrCategoryImages[indexPath.row]
cell.btn_click.tag = indexPath.row
cell.btn_click.addTarget(self, action: #selector(self.click_Category), for: .touchUpInside)
if selectedIndexPaths.contains(indexPath.row) {
cell.btn_click.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
cell.btn_click.isSelected = true
}else {
cell.btn_click.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
cell.btn_click.isSelected = false
}
return cell
}else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoresCell", for: indexPath) as! StoresCell
let dict = storeData[indexPath.row]
if let storeName = dict.name, storeName.count != 0 {
cell.storeName.text = storeName
}
if let storeOfferCount = dict.count {
cell.storeOfferCount.text = "\(storeOfferCount)"+" "+"Offers"
}
cell.store_btn_click.tag = indexPath.row
cell.store_btn_click.addTarget(self, action: #selector(self.click_store), for: .touchUpInside)
if tempStoreIndexPaths.contains(indexPath.row) {
cell.store_btn_click.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
cell.store_btn_click.isSelected = true
}else {
cell.store_btn_click.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
cell.store_btn_click.isSelected = false
}
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if selectedBtnIndex == 1{
return CGSize(width: (UIScreen.main.bounds.width) / 3, height: 93)
}else {
return CGSize(width: (UIScreen.main.bounds.width) / 2, height: 48)
}
}
code for homeView COntroller is as below:
import UIKit
class HomeViewController: UIViewController {
var couponsData = [ModelCoupons]()
var couponId = Int()
#IBOutlet weak var homeTblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.homeTblView.register(UINib(nibName: "HomeCell", bundle: nil), forCellReuseIdentifier: "HomeCell")
self.post_CouponsData()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
//MARK: IBActions
#IBAction func toCategoryScreen(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func toSearchPage(_ sender: UIButtonX) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SearchPageController") as! SearchPageController
self.navigationController?.pushViewController(vc, animated: true)
}
func post_CouponsData() {
if ApiUtillity.sharedInstance.isReachable() {
var params = [String : String]()
params ["term_ids"] = "\(self.couponId)"
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseCouponsList>().API_POST(Url: SD_POST_CouponsList, Params: params as [String:AnyObject], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
ApiUtillity.sharedInstance.StopProgress(view: self.view)
let dict = modelResponse.coupons
for i in dict! {
self.couponsData.append(i)
}
}else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.homeTblView.reloadData()
}) { (failed) in
self.view.makeToast(failed.localizedDescription)
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}else {
self.view.makeToast("No internet connection...")
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return couponsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell", for: indexPath) as! HomeCell
let dict = couponsData[indexPath.row]
if let postTitle = dict.postTitle, postTitle.count != 0 {
cell.ticket_postTitle.text = postTitle
}
if let postContent = dict.postContent, postContent.count != 0 {
cell.ticket_postContent.text = postContent
}
if let storeName = dict.stores, storeName.count != 0 {
cell.storename.text = storeName
}
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd"
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "dd MMMM yyyy"
let datee = ApiUtillity.sharedInstance.ConvertStingTodate(forApp: dict.validTill!)
cell.ticket_ValidDate.text = dateFormatterPrint.string(from: datee)
cell.ticketImageView.tintColor = .random()
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 339.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 339.0
}
}

Read More and Read Less in UITextView : Ilya Puchka readMoreTextView not working

I have tested Ilya Puchka's readMoreTextView pod and on static text inside the project it works. but I am trying it with text that comes from a back end api.
Issue : the cell will not expand fully to reveal all the text. It will reveal about half of the height of the next line...meaning, if the text is 14 pix high, then the READ MORE option will only display only the top half of the text..
If I disable readmoretext options, and use the textView as a plain textView, then textview will display the entire text,... until I scroll.
when I scroll, I lose about 12 lines of text in one messages.
Is a textView just bad for lone singe strings rom a backend?
so this tells me its a tableView.reloadData() or a GCD issue. But I am lost, I don't know where to try. test either option.
I am mixing two pods, AzureBot and ReadMoreTextView. the string / text comes from the azure bot and then gets loaded into the textview.
I now realize I suck at such a simple task.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = self.messages[indexPath.row]
let sending = message.from?.id == BotClient.shared.currentUser.id
switch sending {
case true:
let cell = tableView.dequeueReusableCell(withIdentifier: "UserTableViewCell", for: indexPath) as! UserTableViewCell
cell.transform = tableView.transform
cell.messageLabel.text = message.text
return cell
case false:
let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
cell.botMessage.text = message.text
cell.botMessage.shouldTrim = !expandedCells.contains(indexPath.row)
cell.botMessage.setNeedsUpdateTrim()
cell.botMessage.layoutIfNeeded()
cell.transform = tableView.transform
return cell
}
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
cell.botMessage.onSizeChange = { [unowned tableView, unowned self] r in
let point = tableView.convert(r.bounds.origin, from: r)
guard let indexPath = tableView.indexPathForRow(at: point) else { return }
if r.shouldTrim {
self.expandedCells.remove(indexPath.row)
print("REMOVE CALLED")
} else {
self.expandedCells.insert(indexPath.row)
print("INSERT CALLED")
}
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "BotTableCell", for: indexPath) as! BotTableCell
cell.botMessage.shouldTrim = !cell.botMessage.shouldTrim
print("SHOULD TRIM CALLED")
cell.backgroundColor = .clear
}
}
Here is my TableViewController Class :
class TMNEMessageViewController: UITableViewController, UITextViewDelegate {
#IBOutlet weak var navBar: UINavigationItem!
private var observer: AnyObject?
private var needsUpdateViewOnAppearance = true
#IBOutlet var messageBar: MessageBar!
public override var inputAccessoryView: UIView? {return messageBar}
public override var canBecomeFirstResponder: Bool {return true}
private var isVisible: Bool {return isViewLoaded && view.window != nil}
var messages: SortedArray<Activity> { return BotClient.shared.messages }
var expandedCells = Set<Int>()
let readMoreTextAttributes: [NSAttributedString.Key: Any] = [
NSAttributedString.Key.foregroundColor: UIColor.red,
NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16)
]
let readLessTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.red,
NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 16)
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 300
tableView.rowHeight = UITableView.automaticDimension
registerCells()
setupObservers()
tableView.transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: 0) //flip tableview
BotClient.shared.start { r in
if let _ = r.resource {
print(r.printResponseData())
} else if let error = r.error {
print("ERROR: " + error.localizedDescription)
self.displayError(error.localizedDescription)
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if needsUpdateViewOnAppearance {
tableView.reloadData()
needsUpdateViewOnAppearance = false
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
becomeFirstResponder()
}
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if tableView.contentInset == UIEdgeInsets.zero {
updateContentInset(inset: getContentInset())
}
// tableView.reloadData()
}
func registerCells() {
self.tableView.register(UINib(nibName: "BotTableCell", bundle: nil), forCellReuseIdentifier: "BotTableCell")
self.tableView.register(UINib(nibName: "UserTableViewCell", bundle: nil), forCellReuseIdentifier: "UserTableViewCell")
}
fileprivate func setupObservers() {
// Keyboard Notifications
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(notification:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
// BotClient Notifications
NotificationCenter.default.addObserver(self, selector: #selector(handleMessageAdded(notification:)), name: .BotClientDidAddMessageNotification, object: BotClient.shared)
}
#objc
func handleKeyboardNotification(notification: Notification) {
switch notification.name {
case UIResponder.keyboardDidChangeFrameNotification:
if let rect = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
DispatchQueue.main.async {
//print("r \(rect) i \(self.tableView.safeAreaInsets)")
// print(self.tableView.contentInset)
let inset = self.tableView.contentInset
self.updateContentInset(inset: UIEdgeInsets(top: (rect.height + 10) - self.tableView.safeAreaInsets.top, left: inset.left, bottom: inset.bottom, right: inset.right))
}
}
default: return
}
}
func updateContentInset(inset: UIEdgeInsets) {
UIView.animate(withDuration: 0.15, animations: {
self.tableView.contentInset = inset
}, completion: { f in
if self.messages.count > 0 {
self.tableView.scrollToRow(at: IndexPath.init(row: 0, section: 0), at: .top, animated: true)
}
})
}
#objc func handleMessageAdded(notification: Notification) {
DispatchQueue.main.async {
if self.isVisible {
self.tableView.reloadData()
} else {
self.needsUpdateViewOnAppearance = true
}
}
}
func getContentInset() -> UIEdgeInsets {
return UIEdgeInsets(top: max(tableView.safeAreaInsets.top, messageBar.frame.height) - tableView.adjustedContentInset.top, left: 0, bottom: tableView.safeAreaInsets.bottom - tableView.adjustedContentInset.bottom, right: 0)
}
// Err
func displayError(_ message: String?) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}

Why does the view disappear after scrolling through the collection view?

I am trying to create a view which slides up when the keyboard appears, and within this view is a text field functioning as a search bar and collection view to hold the results of the search. The View slides up fine right above the keyboard as it is supposed to however once I tap on one of the cells to scroll horrizontally the view just disappears. What could be causing this.
Code That I Think May Be Causing The Problem
var offsetY:CGFloat = 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
#objc func keyboardFrameChangeNotification(notification: Notification) {
if let userInfo = notification.userInfo {
let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
let animationCurve = UIViewAnimationOptions(rawValue: Int(animationCurveRawValue))
if let _ = endFrame, endFrame!.intersects(self.myView.frame) {
self.offsetY = self.myView.frame.maxY - endFrame!.minY
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.myView.frame.origin.y = self.myView.frame.origin.y - self.offsetY
}, completion: nil)
} else {
if self.offsetY != 0 {
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.myView.frame.origin.y = self.myView.frame.origin.y + self.offsetY
self.offsetY = 0
}, completion: nil)
}
}
}
}
Code in its entirety
import UIKit
class SearchCollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UITextFieldDelegate, UICollectionViewDataSource {
#IBOutlet weak var searchBar: UITextField!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var myView: UIView!
var genericArray:[String] = ["A","B","C","D","E","F","G","Ab","Abc"]
var currentGenericArray:[String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
layout.itemSize = CGSize(width: (UIScreen.main.bounds.width-1)/2, height: (UIScreen.main.bounds.width-1)/2)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
layout.scrollDirection = .horizontal
self.collectionView.collectionViewLayout = layout
searchBar.delegate = self
currentGenericArray = genericArray
searchBar.addTarget(self, action: #selector(TableSearchViewController.textFieldDidChange), for: .editingChanged)
}
#objc func textFieldDidChange(){
guard(!(searchBar.text?.isEmpty)!) else{
currentGenericArray = genericArray
collectionView.reloadData()
return
}
currentGenericArray = genericArray.filter({letter -> Bool in
letter.lowercased().contains(searchBar.text!)
})
collectionView.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return currentGenericArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionCell
cell.collectionLabel.text = currentGenericArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
var offsetY:CGFloat = 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
#objc func keyboardFrameChangeNotification(notification: Notification) {
if let userInfo = notification.userInfo {
let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
let animationCurve = UIViewAnimationOptions(rawValue: UInt(animationCurveRawValue))
if let _ = endFrame, endFrame!.intersects(self.myView.frame) {
self.offsetY = self.myView.frame.maxY - endFrame!.minY
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.myView.frame.origin.y = self.myView.frame.origin.y - self.offsetY
}, completion: nil)
} else {
if self.offsetY != 0 {
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.myView.frame.origin.y = self.myView.frame.origin.y + self.offsetY
self.offsetY = 0
}, completion: nil)
}
}
}
}
}
class CollectionCell:UICollectionViewCell{
#IBOutlet weak var collectionLabel: UILabel!
override func awakeFromNib() {
collectionLabel.textAlignment = .center
}
}
Your code is a bit muddled but I don't see any textField functions except for didChange which you call from your searchBar. Try adding a shouldReturn and a didEndEditing, as well as update your slider. Here is an example of what I would do. Try it and see if it makes a difference.
Lifecycle
let keyboardSlider = KeyboardSlider()
override func viewDidLoad() {
super.viewDidLoad()
keyboardSlider.subscribeToKeyboardNotifications(view: view)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
keyboardSlider.unsubscribeFromKeyboardNotifications()
}
TextField
// MARK: TextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
// Add Done button for Keyboard Dismissal
let toolBar = UIToolbar()
toolBar.sizeToFit()
toolBar.barStyle = .default
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.didStopEditing))
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
toolBar.setItems([space, doneButton], animated: false)
textField.inputAccessoryView = toolBar
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
/// Helper to dismiss keyboard
#objc func didStopEditing() {
textFieldShouldReturn(phoneNumberTextField)
}
func textFieldDidEndEditing(_ textField: UITextField) {
UIView.setAnimationCurve(UIViewAnimationCurve.easeInOut)
UIView.animate(withDuration: 0.2) {
self.view.frame.origin.y = 0
}
}
Keyboard Slider
class KeyboardSlider: NSObject {
// variables to hold and process information from the view using this class
weak var view: UIView?
#objc func keyboardWillShow(notification: NSNotification) {
// method to move keyboard up
view?.frame.origin.y = 0 - getKeyboardHeight(notification as Notification)
}
func getKeyboardHeight(_ notification:Notification) -> CGFloat {
// get exact height of keyboard on all devices and convert to float value to return for use
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
return keyboardSize.cgRectValue.height
}
func subscribeToKeyboardNotifications(view: UIView) {
// assigning view to class' counterpart
self.view = view
// when UIKeyboardWillShow do keyboardWillShow function
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
}
func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
}
}
This answer is mainly to clean up your code
I have a feeling that your problem is in your didChange method on keyboard dismissal. Cleaning up your code and stepping through breakpoints will help locate your issue.

Call function from UICollectionViewCell to use in UICollectionView

I have a UICollectionViewCell that creates a bunch of text fields and a function (handleNewJob) that looks at all the textfields created in the cell and writes them to firebase.
However, what I want is for a button that I have created in my UICollectionView to call the function (handleNewJob) from the UICollectionViewCell.
Is this possible? I have tried having the function inside the UICollectionView but I can't seem to reference all the textfields.text?
Here is my function inside UICollectionViewCell (I haven't included all the textfield generation as it's quite long):
// HANDLE NEW JOB
func handleNewJob(){
let newJobBrand = jobBrand.text!
let newJobName = jobName.text!
let newDirectorName = directorName.text!
let newAgencyName = agencyName.text!
let newProdCoName = prodCoName.text!
// WHERE TO PUT IN DATABASE
let reference = Database.database().reference().child("jobInfo")
let childRef = reference.childByAutoId()
// REFERENCING DICTIONARY
let jobBrandValue = ["jobBrand": newJobBrand]
let jobNameValue = ["jobName": newJobName]
let jobDirectorValue = ["directorName": newDirectorName]
let jobAgencyNameValue = ["agencyName": newAgencyName]
let jobProdCoValue = ["prodCoName": newProdCoName]
// WRITE TO DATABASE
childRef.updateChildValues(jobBrandValue)
childRef.updateChildValues(jobNameValue)
childRef.updateChildValues(jobDirectorValue)
childRef.updateChildValues(jobAgencyNameValue)
childRef.updateChildValues(jobProdCoValue)
}
Here is my code for the UICollectionView - I want to call the function under the handleNext button:
import UIKit
import Firebase
class page_newJobSwipingController : UICollectionViewController, UICollectionViewDelegateFlowLayout, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// VARIABLES
var ref:DatabaseReference?
// BOTTOM BUTTONS
private let previousButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Previous", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.setTitleColor(.gray, for: .normal)
button.addTarget(self, action: #selector(handlePrev), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let nextButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Next", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
let pinkColour = UIColor(red: 232/255, green: 68/266, blue: 133/255, alpha: 1)
button.setTitleColor(.mainPink, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(handleNext), for: .touchUpInside)
return button
}()
// SET UP NEXT AND PREVIOUS BUTTONS TO HAVE A FUNCTION
#IBAction func handlePrev(sender : UIButton) {
let prevIndex = max(pageControl.currentPage - 1, 0)
pageControl.currentPage = prevIndex
let indexPath = IndexPath(item: prevIndex, section: 0)
collectionView?.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
#IBAction func handleNext(sender : UIButton) {
let nextIndex = pageControl.currentPage + 1
pageControl.currentPage = nextIndex
if nextIndex == 1 {
print ("move to page 2")
} else {
print ("send alert message")
newJobCellGeneral.handleNewJob()
storyboardAlert()
}
let indexPath = IndexPath(item: 1, section: 0)
collectionView?.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
// HANDLE UPLOAD STORYBOARD OPTIONS
#IBAction func storyboardAlert() {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
// ACTION SHEET FOR ADDING NEW ATTACHMENT
let alert = UIAlertController(title: "Job Created", message: "Do you want to upload storyboard cells now?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Now", style: .default, handler: { (action:UIAlertAction) in
let storyboardUpload = page_newJobStoryboardUpload()
self.show(storyboardUpload, sender: self)
}))
alert.addAction(UIAlertAction(title: "Later", style: .default, handler: { (action:UIAlertAction) in
let jobList = page_jobList()
self.show(jobList, sender: self)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// PAGE CONTROL
private let pageControl: UIPageControl = {
let pc = UIPageControl()
pc.numberOfPages = 2
pc.currentPageIndicatorTintColor = .mainPink
pc.pageIndicatorTintColor = UIColor(red: 249/255, green: 207/266, blue: 224/255, alpha: 1)
return pc
}()
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let x = targetContentOffset.pointee.x
pageControl.currentPage = Int(x / view.frame.width)
}
// CONSTRAINTS OF BOTTOM CONTROLS
fileprivate func setupBottomControls(){
let bottomControlsStackView = UIStackView(arrangedSubviews: [previousButton, pageControl, nextButton])
bottomControlsStackView.translatesAutoresizingMaskIntoConstraints = false
bottomControlsStackView.distribution = .fillEqually
view.addSubview(bottomControlsStackView)
NSLayoutConstraint.activate([
bottomControlsStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
bottomControlsStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
bottomControlsStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
bottomControlsStackView.heightAnchor.constraint(equalToConstant: 50)
])
}
// SUPER VIEW DID LOAD
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.register(newJobCellGeneral.self, forCellWithReuseIdentifier: "newJobCellGeneral")
collectionView?.register(newJobCellTechnical.self, forCellWithReuseIdentifier: "newJobCellTechnical")
collectionView?.isPagingEnabled = true
setupBottomControls()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newJobCellGeneral", for: indexPath) as! newJobCellGeneral
navigationItem.title = "General Info"
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newJobCellTechnical", for: indexPath) as! newJobCellTechnical
navigationItem.title = "Technical Specs"
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
}
The flow is inversed but yes, the easiest way is via notifications
in you collection view
Put this in your collectionView button pressed method
NotificationCenter.default.post(name: Notification.Name("handleNewJob"), object: nil)
Add observer in you collection view cell (init or awakeFromNib depends)
NotificationCenter.default.addObserver(self, selector: #selector(handleNewJob, name: NSNotification.Name(rawValue: "handleNewJob"), object: nil)
Notification Center is one solution, but the easier way is to be able to call a function on your collection view controller directly from the cell.
To do that, you need to be able to reference your parent view controller. so add this UIView extension:
Create a swift file named UIView.swift and paste this:
import UIKit
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if parentResponder is UIViewController {
return parentResponder as! UIViewController!
}
}
return nil
}
}
then from your cell, for example when a button is clicked:
#IBAction func someButtonAction(sender : UIButton) {
let parent = self.parentViewController as! page_newJobSwipingController
parent.whateverFunction()
}