I have a UITabBarViewController with two tabs. I want to present a viewController fullscreen in one of the tabs. I have used the following code to do so.
let navCtrl = UINavigationController(rootViewController: eventViewController)
navCtrl.modalPresentationStyle = .fullScreen
self.navigationController?.present(navCtrl, animated: true)
It works. And EventViewController is fullscreen. However, when presenting another viewController in EventViewController, EventViewController is still fullscreen. But I want it to shrink in size and stack-up as it normally do( as in the image). In order to do so, I have changed modalPresentationStyle to overCurrentContext.
let navCtrl = UINavigationController(rootViewController: eventViewController)
navCtrl.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(navCtrl, animated: true)
It does so, but it causes another problem: If I change tabs and dismiss EventViewController, the presenting viewController is black as described in this question (none of the answers was helpful).
Basically I want the EventController to be fullscreen but shrink in size when presenting another controller in it. How to do so?
Update
A simple project with the same issue.
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let ctrl = TabZeroViewController()
ctrl.tabBarItem.image = UIImage(named: "archived-task")
ctrl.tabBarItem.title = "One"
let test = TabOneViewController()
test.tabBarItem.image = UIImage(named: "Test")
test.tabBarItem.title = "Test"
let tabBarList = [ctrl, test ]
self.viewControllers = tabBarList.map {
let nav = UINavigationController(rootViewController: $0)
nav.interactivePopGestureRecognizer?.isEnabled = true
return nav
}
}
}
class TabZeroViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.backgroundColor = .white
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = ModalTableViewController()
let nav = UINavigationController(rootViewController: ctrl)
nav.modalPresentationStyle = .fullScreen
self.navigationController?.present(nav, animated: true)
}
}
class ModalTableViewController: UITableViewController {
override func viewDidLoad() {
self.view.backgroundColor = .red
let button = UIButton()
button.setTitle("Cancel", for: .normal)
button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
let item = UIBarButtonItem()
item.customView = button
self.navigationItem.leftBarButtonItem = item
self.tableView.dataSource = self
self.tableView.delegate = self
}
#objc func dismissModal() {
self.dismiss(animated: true, completion: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Event"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = EventViewController()
let nav = UINavigationController(rootViewController: ctrl)
nav.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(nav, animated: true)
}
}
class TabOneViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
class EventViewController: UITableViewController {
override func viewDidLoad() {
self.view.backgroundColor = .red
let button = UIButton()
button.setTitle("Cancel", for: .normal)
button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
let item = UIBarButtonItem()
item.customView = button
self.navigationItem.leftBarButtonItem = item
self.tableView.dataSource = self
self.tableView.delegate = self
}
#objc func dismissModal() {
self.dismiss(animated: true, completion: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Event"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = EventViewController()
let nav = UINavigationController(rootViewController: ctrl)
self.navigationController?.present(nav, animated: true)
}
}
Add this code in willConnectTo of SceneDelegate.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = TabBarController()
self.window = window
window.makeKeyAndVisible()
}
While you are on first tab, select a table cell to open the ModalTableViewController. And then change tabs and dismiss ModalTableViewController.
As for example project - presenting view over full screen hides TabBar. But I changed code a bit to propose working solution. Probably you would want to change it a bit, but I hope this will push you in good direction :)
It was actually needed to dismiss ModalTableViewController to avoid black screen.
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let ctrl = TabZeroViewController()
ctrl.tabBarItem.image = UIImage(named: "archived-task")
ctrl.tabBarItem.title = "One"
let test = TabOneViewController()
test.tabBarItem.image = UIImage(named: "Test")
test.tabBarItem.title = "Test"
let tabBarList = [ctrl, test ]
let viewControllers: [UIViewController] = tabBarList.map {
let nav = UINavigationController(rootViewController: $0)
nav.interactivePopGestureRecognizer?.isEnabled = true
nav.tabBarItem = $0.tabBarItem
return nav
}
self.setViewControllers(viewControllers, animated: false)
}
override var selectedViewController: UIViewController? {
get {return super.selectedViewController}
set {
if super.selectedViewController?.presentedViewController != nil {
super.selectedViewController?.dismiss(animated: false, completion: nil)
}
super.selectedViewController = newValue
}
}
}
class TabZeroViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.backgroundColor = .white
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = ModalTableViewController()
let nav = UINavigationController(rootViewController: ctrl)
nav.modalPresentationStyle = .currentContext
self.present(nav, animated: true)
}
}
class ModalTableViewController: UITableViewController {
override func viewDidLoad() {
self.view.backgroundColor = .red
let button = UIButton()
button.setTitle("Cancel", for: .normal)
button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
let item = UIBarButtonItem()
item.customView = button
self.navigationItem.leftBarButtonItem = item
self.tableView.dataSource = self
self.tableView.delegate = self
}
#objc func dismissModal() {
self.presentingViewController?.dismiss(animated: false, completion: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Event"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = EventViewController()
let nav = UINavigationController(rootViewController: ctrl)
nav.modalPresentationStyle = .fullScreen
self.navigationController?.present(nav, animated: true)
}
}
class TabOneViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
}
}
class EventViewController: UITableViewController {
override func viewDidLoad() {
self.view.backgroundColor = .red
let button = UIButton()
button.setTitle("Cancel", for: .normal)
button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
let item = UIBarButtonItem()
item.customView = button
self.navigationItem.leftBarButtonItem = item
self.tableView.dataSource = self
self.tableView.delegate = self
}
#objc func dismissModal() {
self.dismiss(animated: true, completion: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Event"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ctrl = EventViewController()
let nav = UINavigationController(rootViewController: ctrl)
self.navigationController?.present(nav, animated: true)
}
}
Good luck!
Try this code to present screen modally:
func getImageFromView() -> UIImage {
let layer = UIApplication.shared.keyWindow?.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer?.frame.size ?? CGSize.zero, false, scale)
if let context = UIGraphicsGetCurrentContext() {
layer?.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image ?? UIImage()
}
return UIImage()
}
/// This is the method to present screen modally
/// - parameter controller: controller instance on which screen will be presented
func presentScreenModally(controller: UIViewController, animated: Bool) {
let loginController = UIStoryboard.loadLoginViewController()//Get instance of controller form storyboard
loginController.bgTranParentImg = getImageFromView()
let bgImage = getImageFromView()
let presentationStyleViewController = UIStoryboard.loadPresentationStyleController()// This is another controller, which I am pasting below
presentationStyleViewController.bgimage = bgImage
presentationStyleViewController.loginController = loginController
presentationStyleViewController.addChild(loginController)
controller.view.window?.addSubview(presentationStyleViewController.view)
loginController.view.frame = presentationStyleViewController.containerView.bounds
presentationStyleViewController.containerView.addSubview(loginController.view)
let navigationController = UINavigationController(rootViewController: presentationStyleViewController)
navigationController.navigationBar.isHidden = true
navigationController.modalPresentationStyle = .fullScreen
controller.navigationController?.present(navigationController, animated: animated, completion: nil)
}
PresentationStyleViewController class:
class PresentationStyleViewController: UIViewController {
#IBOutlet var containerView: UIView!
#IBOutlet var containeTopConstraint: NSLayoutConstraint!
#IBOutlet var containerBottomConstraint: NSLayoutConstraint!
#IBOutlet var backgroundImage: UIImageView!
var bgimage: UIImage?
let topPadding: CGFloat = 30
var loginController: LoginViewController?
override func viewDidLoad() {
super.viewDidLoad()
self.uiSetup()
}
override func viewDidAppear(_ animated: Bool) {
restorePopup()
}
/// Initial UI setup
func uiSetup() {
containeTopConstraint.constant = self.view.frame.size.height
backgroundImage.image = bgimage
}
#IBAction func panGesture(_ sender: UIPanGestureRecognizer) {
guard let piece = sender.view else {return}
let translation = sender.translation(in: piece.superview)
containeTopConstraint.constant = translation.y >= topPadding ? translation.y : topPadding
if sender.state == .ended || sender.state == .cancelled {
if containeTopConstraint.constant > self.view.frame.size.height/4 && translation.y > 0 {
self.dismissPopup()
} else {
self.restorePopup()
}
}
}
/// Dismisses popup and controller
func dismissPopup() {
containeTopConstraint.constant = self.view.frame.size.height
UIView.animate(withDuration: 0.3,
animations: {
self.view.layoutIfNeeded()
}, completion: { (_) in
self.loginController?.btnClick_cross(UIButton())
self.dismiss(animated: false)
})
}
/// Restores popup at initial position
func restorePopup() {
containeTopConstraint.constant = topPadding
UIView.animate(withDuration: 0.3,
animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
Related
I am trying to create a ToDoList in swift UI and my deleteTask function is not working properly. I tried a lot of things and none of them worked.
import UIKit
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var toDoTasks = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title = "SAVED TASKS"
tableView.delegate = self
tableView.dataSource = self
// setup
if !UserDefaults().bool(forKey: "setup")
{
UserDefaults().set(true, forKey: "setup")
UserDefaults().set(0, forKey: "count")
}
updateTasks()
}
func updateTasks()
{
toDoTasks.removeAll()
guard let count = UserDefaults().value(forKey: "count") as? Int else
{
return
}
for x in 0..<count
{
if let task = UserDefaults().value(forKey: "task_\(x+1)") as? String
{
toDoTasks.append(task)
}
}
tableView.reloadData()
}
#IBAction func didTapAdd()
{
let viewController = storyboard?.instantiateViewController(withIdentifier: "entry") as! EntryViewController
viewController.title = "NEW TASK"
viewController.updated =
{
DispatchQueue.main.async {
self.updateTasks()
}
}
navigationController?.pushViewController(viewController, animated: true)
}
}
extension ViewController: UITableViewDelegate
{
// function to select the rows
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let viewController = storyboard?.instantiateViewController(withIdentifier: "task") as! TasksViewController
viewController.title = "NEW TASK"
viewController.task = toDoTasks[indexPath.row]
navigationController?.pushViewController(viewController, animated: true)
}
}
extension ViewController: UITableViewDataSource
{
// function which returns number of tasks
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return toDoTasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = toDoTasks[indexPath.row]
return cell
}
}
import UIKit
class TasksViewController: UIViewController {
#IBOutlet var label : UILabel!
var task : String?
var currentPosition: Int?
override func viewDidLoad() {
super.viewDidLoad()
label.text = task
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Delete", style: .done, target: self, action: #selector(deleteTask))
}
#objc func deleteTask(_ sender: UIBarButtonItem) {
guard let currentPosition = self.currentPosition else {
return
}
let count = UserDefaults.standard.integer(forKey: "count")
UserDefaults.standard.removeObject(forKey: "task_\(currentPosition+1)")
for i in currentPosition+1..<count {
let task = UserDefaults.standard.string(forKey: "task_\(i+1)")
UserDefaults.standard.setValue(task, forKey: "task_\(i)")
}
UserDefaults.standard.setValue(count-1, forKey: "count")
navigationController?.popViewController(animated: true)
}
}
When I press the Delete button, nothing happens. Could you please help me??
I want to avoid duplicate rewriting same code and create reusable UITableViewController.
I have ExerciseViewController with 3 buttons. Each button push a UITableViewController on the navigation stack. There are three UITableViewControllers: 1) CategoryUITableVC, 2) EquipmentUITableVC, 3) MusclesUITableVC.
All of these three view controllers have almost exactly same layout - cells with labels and accessory buttons. The only difference is that first view controller has got image next to title. Is it worth doing one reusable VC and instantiate it 3 times or maybe better solution create 3 separated VC (but It will be just rewriting almost same code).
I use coordinator pattern.
class ExerciseCoordinator: NSObject, Coordinator {
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
...
//unnecessary code to show
...
// *HERE I INSTANTIATE VIEW CONTROLLERS, I PRESENT THEM MODALLY BUT I WANT TO HAVE NAVIGATION BAR, SO I NEED TO CREATE NEW NAVIGATION CONTROLLERS*
lazy var equipmentVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var equipmentNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: equipmentVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
lazy var categoryVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var categoryNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: categoryVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
lazy var muscleVC: ReusableTableViewController = {
let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
vc.delegate = self
return vc
}()
lazy var muscleNavController: UINavigationController = {
let navController = UINavigationController(rootViewController: muscleVC)
navController.navigationItem.largeTitleDisplayMode = .always
return navController
}()
}
extension ExerciseCoordinator: CustomExerciseDelegate {
func selectCategory() {
navigationController.viewControllers.last?.present(categoryNavController, animated: true, completion: nil)
categoryVC.dataType = .category
}
func selectEquipment() {
navigationController.viewControllers.last?.present(equipmentNavController, animated: true, completion: nil)
equipmentVC.dataType = .equipment
}
func selectMuscles() {
navigationController.viewControllers.last?.present(muscleNavController, animated: true, completion: nil)
muscleVC.dataType = .muscle
}
}
I assign data type to know from where it comes from (CategoryVC/EquipmentVC/MuscleVC) when I will dismiss UITableVC.
Here it is my reusable UITableViewController:
import UIKit
import RealmSwift
class ExerciseCategoryTableViewController: UITableViewController {
var delegate: ExerciseSelectionCriteriaDelegate?
//I use it delegate to send data back after dismiss view
var dataType: DataType?
var data = [String]() {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData() }}
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
func getData() {
if dataType == .category {
let allCategories = RealmService.shared.realm.objects(Category.self)
data = allCategories.compactMap({$0.category})
} else if dataType == .equipment {
let allEquipment = RealmService.shared.realm.objects(Equipment.self)
data = allEquipment.compactMap({$0.equipment})
} else {
let allMuscles = RealmService.shared.realm.objects(Muscles.self)
data = allMuscles.compactMap({$0.muscles})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// below is my own shortcut for dequeue cell, it works
let cell: ExerciseSelectionTableViewCell = tableView.dequeueResuableCell(for: indexPath)
cell.category.text = data[indexPath.row]
if let image = UIImage(named: "\(data[indexPath.row].lowercased())") {
cell.categoryImage.image = image
cell.categoryImage.isHidden = false
} else {
cell.categoryImage.isHidden = true
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
#IBAction func closeViewController(_ sender: UIBarButtonItem) {
closeViewController()
}
#IBAction func saveSelectedCategories(_ sender: UIBarButtonItem) {
saveSelectedData()
}
func saveSelectedData() {
let selectedIndexes = tableView.indexPathsForSelectedRows
if let selectedData = selectedIndexes?.compactMap({data[$0.row]}) {
dismiss(animated: true) {
self.delegate?.selectedFields(for: selectedData, dataType: self.dataType)
}
} else {
dismiss(animated: true) {
self.delegate?.selectedFields(for: nil, dataType: self.dataType)
}
}
}
func closeViewController() {
guard let _ = tableView.indexPathsForSelectedRows else { return dismiss(animated: true, completion: nil)}
Alert.showAlertWithCompletion(on: self, with: "TEXT", message: "TEXT") { _ in
self.dismiss(animated: true, completion: nil)
}
}
}
I will be thankful if you tell me if this approach is correct or maybe better solution are separated view controllers or create protocol with default implementation?
I'm trying to make a note taking app, however, I'm kinda stuck on how to get my save button to work. Here's what I've got so far:
My Add "Item" View
class AddViewController: UIViewController {
#IBOutlet var addShortDescription: UITextField!
#IBOutlet var addLongDescription: UITextView!
public var completion: ((String, String) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
addShortDescription.becomeFirstResponder()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .done, target: self, action: #selector(didTapSave))
self.title = "Add New Item"
}
#IBAction func didTapSave(_ sender: Any) {
if let text = addShortDescription.text, !text.isEmpty, !addLongDescription.text.isEmpty {
completion?(text, addLongDescription.text)
}
}
}
My Main View
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
var models: [(ShortDescription: String, LongDescription: String)] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
table.delegate = self
table.dataSource = self
self.title = "Inventory"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return models.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = models[indexPath.row].ShortDescription
cell.detailTextLabel?.text = models[indexPath.row].LongDescription
return cell
}
#IBAction func addNewInventory(){
guard let vc = storyboard?.instantiateViewController(identifier: "add") as? AddViewController else {
return
}
vc.title = "Add New Item"
vc.navigationItem.largeTitleDisplayMode = .never
vc.completion = { addShortDescription, addLongDescription in
self.navigationController?.popToRootViewController(animated: true)
self.models.append((ShortDescription: addShortDescription, LongDescription: addLongDescription))
self.table.isHidden = false
self.table.reloadData()
}
navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let model = models[indexPath.row]
// Show addLongDescription controller
guard let vc = storyboard?.instantiateViewController(identifier: "inventory") as?
EditViewController else {
return
}
vc.navigationItem.largeTitleDisplayMode = .never
vc.title = "Edit Item"
vc.addShortDescription.text = model.ShortDescription
vc.addLongDescription.text = model.LongDescription
navigationController?.pushViewController(vc, animated: true)
}
}
I have another view where I plan on allowing the user to edit the added items, I'll add that if you think it may be causing some problems.
I use a custom search controller that has a tableView for showing the results,
the problem is when tapping the cancel button multiple times it dismisses the tabBarController.
But if i press it normally it acts as it should be.
class UICustomSearchController: UISearchController {
private var suggestedTableView: UITableView!
weak var suggestionDelegate: SearchSuggestionsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
suggestedTableView = UITableView(frame: CGRect(x: 0, y: searchBar.frame.maxY,
width: view.frame.width,
height: view.frame.height - 70))
suggestedTableView.backgroundColor = UIColor.clear
suggestedTableView.tableFooterView = UIView()
view.subviews.forEach {
if $0.isKind(of: UITableView.self) {
$0.removeFromSuperview()
}
}
view.addSubview(suggestedTableView)
suggestedTableView.dataSource = self
suggestedTableView.delegate = self
suggestedTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
suggestedTableView.addGestureRecognizer(tap)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
suggestedTableView.removeFromSuperview()
suggestedTableView = nil
dismiss(animated: false, completion: nil)
}
func reloadSuggestions() {
suggestedTableView.reloadData()
}
private func dismissView() {
searchBar.text = ""
suggestedTableView.removeFromSuperview()
dismiss(animated: false, completion: nil)
suggestionDelegate?.didDismissed()
}
// MARK: - Actions
#objc func tableTapped(tap:UITapGestureRecognizer) {
suggestedTableView.removeGestureRecognizer(tap)
let location = tap.location(in: suggestedTableView)
let path = suggestedTableView.indexPathForRow(at: location)
if let indexPathForRow = path {
tableView(suggestedTableView, didSelectRowAt: indexPathForRow)
} else {
dismissView()
}
}
}
extension UICustomSearchController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return suggestionDelegate?.suggestions().count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let list = suggestionDelegate?.suggestions() ?? []
cell.textLabel?.text = list[indexPath.row]
cell.textLabel?.textColor = UIColor.color(from: .blueTabBar)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let list = suggestionDelegate?.suggestions() ?? []
searchBar.text = list[indexPath.row]
searchBar.becomeFirstResponder()
suggestionDelegate?.didSelect(suggestion: list[indexPath.row])
}
}
And in the viewController that has search:
func initSearchViews() {
// Create the search controller and specify that it should present its results in this same view
searchController = UICustomSearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.barTintColor = UIColor.white
searchController.searchBar.tintColor = UIColor.color(from: .blueTabBar)
searchController.searchBar.setValue(Strings.cancel.localized, forKey:"_cancelButtonText")
searchController.suggestionDelegate = self
if let searchTextField = searchController!.searchBar.value(forKey: "searchField") as? UITextField {
searchTextField.placeholder = Strings.search.localized
}
// Make this class the delegate and present the search
searchController.searchBar.delegate = self
}
I tried putting this line in viewController but nothing happened:
definesPresentationContext = true
This is the code and the problem
There is no wrong when I did select one row before I add the function tableView(......didSelectRowatindexPath...)
So, I thought it's the root cause.
I hope somebody can help me because the wrong info was not so clear that I can understand it well.
What I want to do is change the BarItemName when I did select one row of my popover table.
SwitchA is a var in my popoverviewcontroller, it means which button is pressed.
When the button in "SecondVC" is pressed,it will pass a value to SwitchA and then the popoverviewcontroller can determine which datasource it should show.
PS:this is the popoverviewcontroller's code.
import UIKit
class PopOverView: UIViewController, UITableViewDataSource, UITableViewDelegate {
var SwitchA = 0
var ClassA = ["这个类型","那个类型","这个类型","那个类型","这个类型","那个类型","这个类型","那个类型","这个类型","那个类型"]
var TimeA = ["昨天","今天","明天","昨天","今天","明天"]
var TagA = ["动漫","音乐","游戏","音乐","游戏"]
#IBOutlet weak var TV: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
TV.dataSource = self
TV.delegate = self
self.preferredContentSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: 175)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if SwitchA == 0 {
return ClassA.count
}
if SwitchA == 1 {
return TimeA.count
}
else {
return TagA.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
if SwitchA == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = ClassA[indexPath.row]
cell.separatorInset = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
if SwitchA == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = TimeA[indexPath.row]
cell.separatorInset = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = TagA[indexPath.row]
cell.separatorInset = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 35.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: false)
if SwitchA == 0 {
let VC = self.storyboard!.instantiateViewControllerWithIdentifier("SecondVC") as! XiaoNei_HuoDong
VC.ClassName.title = ClassA[indexPath.row]
}
if SwitchA == 1 {
let VC = self.storyboard!.instantiateViewControllerWithIdentifier("SecondVC") as! XiaoNei_HuoDong
VC.TimeName.title = TimeA[indexPath.row]
}
else {
let VC = self.storyboard!.instantiateViewControllerWithIdentifier("SecondVC") as! XiaoNei_HuoDong
VC.TagName.title = TagA[indexPath.row]
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
And this is the code of "SecondVC":
import UIKit
class XiaoNei_HuoDong: UIViewController,UITableViewDelegate,UITableViewDataSource, UIPopoverPresentationControllerDelegate{
#IBOutlet weak var TagName: UIBarButtonItem!
#IBOutlet weak var TimeName: UIBarButtonItem!
#IBOutlet weak var ClassName: UIBarButtonItem!
#IBOutlet weak var huodongTV: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
huodongTV.dataSource = self
huodongTV.delegate = self
huodongTV.showsVerticalScrollIndicator = false
let options = PullToRefreshOption()
options.backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 244/255, alpha: 1)
options.indicatorColor = UIColor.blackColor()
huodongTV.addPullToRefresh(options: options, refreshCompletion: { [weak self] in
// some code
self!.huodongTV.reloadData()
self!.huodongTV.stopPullToRefresh()
})
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return 3
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 1.0
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 1.0
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
self.huodongTV.deselectRowAtIndexPath(indexPath, animated: false)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
if indexPath.row == 0 {
let cell:HuoDong_2 = tableView.dequeueReusableCellWithIdentifier("huodong2") as! HuoDong_2
cell.ClubB1.image = UIImage(named: "test")!
cell.ClubB2.image = UIImage(named: "test")!
cell.ClubS1.image = UIImage(named: "focus")!
cell.ClubS2.image = UIImage(named: "focus")!
cell.Tag1.image = UIImage(named: "更新")!
cell.Tag2.image = UIImage(named: "更新")!
cell.View1.image = UIImage(named: "view")!
cell.View2.image = UIImage(named: "view")!
cell.Newest.image = UIImage(named: "club rank")
return cell
}
else {
let cell:HuoDong = tableView.dequeueReusableCellWithIdentifier("huodong1") as! HuoDong
cell.ClubB1.image = UIImage(named: "test")!
cell.ClubB2.image = UIImage(named: "test")!
cell.ClubS1.image = UIImage(named: "focus")!
cell.ClubS2.image = UIImage(named: "focus")!
cell.Tag1.image = UIImage(named: "更新")!
cell.Tag2.image = UIImage(named: "更新")!
cell.View1.image = UIImage(named: "view")!
cell.View2.image = UIImage(named: "view")!
return cell
}
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath){
cell.layer.transform = CATransform3DMakeScale(0.1, 0.1, 1)
UIView.animateWithDuration(0.25, animations: {
cell.layer.transform = CATransform3DMakeScale(1, 1, 1)
})
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return self.view.frame.width * 240.0 / 400.0
}
else {
return self.view.frame.width * 200.0 / 400.0
}
}
// MARK: - PopOverforsegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Class1"{
let VC = segue.destinationViewController as! PopOverView
VC.SwitchA = 0
VC.modalPresentationStyle = UIModalPresentationStyle.Popover
VC.popoverPresentationController?.delegate = self
}
if segue.identifier == "Time1"{
let VC = segue.destinationViewController as! PopOverView
VC.SwitchA = 1
VC.modalPresentationStyle = UIModalPresentationStyle.Popover
VC.popoverPresentationController?.delegate = self
}
if segue.identifier == "Tag1"{
let VC = segue.destinationViewController as! PopOverView
VC.SwitchA = 2
VC.modalPresentationStyle = UIModalPresentationStyle.Popover
VC.popoverPresentationController?.delegate = self
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I think problem is timing of initialize.
Try this:
SecondVC
var tagNameStr = ""
override func viewDidLoad() {
super.viewDidLoad()
TagName.title = tagNameStr // here
...
}
FirstVC
if SwitchA == 0 {
let VC = self.storyboard!.instantiateViewControllerWithIdentifier("SecondVC") as! XiaoNei_HuoDong
VC.tagNameStr = ClassA[indexPath.row]
}
Hope this helps!
UPDATE
This is sample code.
(ViewController -|segue|-> SecondViewController)
class ViewController: UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let vc = segue.destinationViewController as? SecondViewController {
vc.buttonTitle = "IOhYES"
}
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var buttonItem: UIBarButtonItem!
var buttonTitle = ""
override func viewDidLoad() {
super.viewDidLoad()
buttonItem.title = buttonTitle
}
}
Please check IBOutlet connection.