ButtomSheet of Material Design does not show properly - swift - ios

I was trying to integrate my app with material-components called bottomSheet. When i implement that component it shown me correctly but not like what i expected.
When it shown up and all the time i scroll up that bottomSheet does not stick to bottom of view
Here it looks like
How to fix this particular issue?
Here is the code
let viewController: UIViewController = UIViewController()
viewController.view.backgroundColor = .red
let bottomSheet: MDCBottomSheetController = MDCBottomSheetController(contentViewController: viewController)
self.present(bottomSheet, animated: true, completion: nil)

Why don't add some contents of that particular viewController.
Create tableViewController
import Foundation
import UIKit
class TableViewContent: UITableViewController {
let cellId = "CellId"
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
}
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 = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
cell.textLabel?.text = "Hello World"
return cell
}
}
After created that controller
then add this in your code that you provided:
// let viewController: UIViewController = UIViewController()
//
// viewController.view.backgroundColor = .red
// let size = viewController.view.sizeThatFits(view.bounds.size)
// let viewFrame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
// viewController.view.frame = viewFrame
let viewController = TableViewContent()
let bottomSheet: MDCBottomSheetController = MDCBottomSheetController(contentViewController: viewController)
self.present(bottomSheet, animated: true, completion: nil)
Hope this will help...
The reason it not stick to bottom because the controller is empty, just my idea...

Related

TableView Collapse, why it's sticking up like this?

I'm setting up a collapsable tableView, but something strange happens on the collapsable item. When you look at the video keep an eye on the "Where are you located" line.. (I'm using a .plist for the question and answer items)
Where do I go wrong, is it somewhere in my code? I don't want to let that line stick on the top :(
Here is the code I'm using but I can't find anything strange...
class FAQViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var questionsArray = [String]()
var answersDict = Dictionary<String, [String]>() // multiple answers for a question
var collapsedArray = [Bool]()
#IBOutlet weak var tableView: UITableView!
override func viewWillAppear(_ animated: Bool) {
// Hide the navigation bar on the this view controller
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addTableStyles()
readQAFile()
tableView.delegate = self
tableView.dataSource = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
func addTableStyles(){
navigationController?.isNavigationBarHidden = false
self.tableView?.backgroundView = {
let view = UIView(frame: self.tableView.bounds)
return view
}()
tableView.estimatedRowHeight = 43.0;
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = UITableViewCell.SeparatorStyle.singleLine
}
func readQAFile(){
guard let url = Bundle.main.url(forResource: "QA", withExtension: "plist")
else { print("no QAFile found")
return
}
let QAFileData = try! Data(contentsOf: url)
let dict = try! PropertyListSerialization.propertyList(from: QAFileData, format: nil) as! Dictionary<String, Any>
// Read the questions and answers from the plist
questionsArray = dict["Questions"] as! [String]
answersDict = dict["Answers"] as! Dictionary<String, [String]>
// Initially collapse every question
for _ in 0..<questionsArray.count {
collapsedArray.append(false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return questionsArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if collapsedArray[section] {
let ansCount = answersDict[String(section)]!
return ansCount.count
}
return 0
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
// Set it to any number
return 70
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if collapsedArray[indexPath.section] {
return UITableView.automaticDimension
}
return 2
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:40))
headerView.tag = section
let headerString = UILabel(frame: CGRect(x: 10, y: 10, width: tableView.frame.size.width, height: 50)) as UILabel
headerString.text = "\(questionsArray[section])"
headerView .addSubview(headerString)
let headerTapped = UITapGestureRecognizer (target: self, action:#selector(sectionHeaderTapped(_:)))
headerView.addGestureRecognizer(headerTapped)
return headerView
}
#objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
let indexPath : IndexPath = IndexPath(row: 0, section:recognizer.view!.tag)
if (indexPath.row == 0) {
let collapsed = collapsedArray[indexPath.section]
collapsedArray[indexPath.section] = !collapsed
//reload specific section animated
let range = Range(NSRange(location: indexPath.section, length: 1))!
let sectionToReload = IndexSet(integersIn: range)
self.tableView.reloadSections(sectionToReload as IndexSet, with:UITableView.RowAnimation.fade)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cellIdentifier = "Cell"
let cell: UITableViewCell! = self.tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.numberOfLines = 0
let manyCells : Bool = collapsedArray[indexPath.section]
if (manyCells) {
let content = answersDict[String(indexPath.section)]
cell.textLabel?.text = content![indexPath.row]
}
return cell
}
override var prefersStatusBarHidden: Bool {
return true
}
}
You need to change the style of the tableView to grouped, when you initialize it:
let tableView = UITableView(frame: someFrame, style: .grouped)
or from Storyboard:
After that you will have this issue, which I solved by setting a tableHeaderView to the tableView that has CGFloat.leastNormalMagnitude as its height:
override func viewDidLoad() {
super.viewDidLoad()
var frame = CGRect.zero
frame.size.height = .leastNormalMagnitude
tableView.tableHeaderView = UIView(frame: frame)
}
Just remove your headerView from view hierarchy here
#objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
headerView.removeFromSuperview()
...
}
By the way, yes creating a openable tableview menu with using plist is one of the methods but it could be more simple. In my opinion you should refactor your code.

unable to dismiss side menu using delegate method in IOS Swift

So, basically, I implemented a SideMenu using the module side menu from pod. however, I am stuck at the last part where when I tapped on any of the options inside the menu, the side menu shall dismiss itself and display corresponding content depending on which menu option I picked.
my code for my main view controller is below:
class Profile: UIViewController, MenuControllerDelegate {
var menu: SideMenuNavigationController?
var menuController:MenuListController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
menu = SideMenuNavigationController(rootViewController: MenuListController())
menu?.leftSide = true
menu?.setNavigationBarHidden(true, animated: false)
SideMenuManager.default.leftMenuNavigationController = menu
SideMenuManager.default.addPanGestureToPresent(toView: self.view)
setupNavBaritem()
}
func handleMenuToggle(menuOption: String?) {
print("menuToggle function reached")
menu?.dismiss(animated: true, completion: nil)
}
func setupNavBaritem() {
let menuicon = UIImage(named: "menu")
let menubtn = UIButton(type: .system)
menubtn.setImage(menuicon, for: .normal)
menubtn.frame = CGRect(x: 0, y: 0, width: 35, height: 35)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: menubtn)
menubtn.addTarget(self, action: #selector(menubtntapped), for: .touchUpInside)
navigationController?.navigationBar.isTranslucent = false
}
#objc func menubtntapped(){
present(menu!,animated:true)
}
}
then this is my menu controller:
class MenuListController:UITableViewController {
var menuitems = ["1","2","3","4"]
var delegate:MenuControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(MenuCell.self, forCellReuseIdentifier: "menucell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuitems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "menucell", for: indexPath) as! MenuCell
let menuetext = menuitems[indexPath.row]
let menuicon = menuimg[indexPath.row]
cell.setmenucell(iconimg: menuicon, text: menuetext)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedMenu = menuitems[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
delegate?.handleMenuToggle(menuOption: selectedMenu)
}
}
and this is my protocol:
protocol MenuControllerDelegate {
func handleMenuToggle(menuOption:String? )
}
New updates!
with the delegate setup, i am able to reach the toggle function and print("menuToggle function reached"). but my dismiss doesnt work. i have been searching for a while and seems a lot of ppl are having trouble using the dismiss function to dismiss this sidemenu. any workaround that may work on this? i tried a few, including setting the new root controller, which didnt work
Change the frame of the centeController on delegate call. Set 0 when you want to dismiss.
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.centerNavigationController.view.frame.origin.x = self.centerNavigationController.view.frame.width - 80
}, completion: nil)
i missed the delegate in this function
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedMenu = menuitems[indexPath.row]
let temp = Profile()
tableView.deselectRow(at: indexPath, animated: true)
self.delegate = temp
delegate?.handleMenuToggle(menuOption: selectedMenu)
}
now, i can print out my menutoggle function!

iOS - stack fullscreen viewController when presenting another viewController

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)
}
}

UITableview to cell detail with image

I currently have a UITabelview that displays a list of medications, each connecting to its own scene with its own image view.
Is it possible to connect the UITableview to only one scene and just change the image based on what the user picks within the table?
This is the link to the image to view my storyboards:
https://ibb.co/6FcDySW
Code is also displayed.
class MedicationsController: UITableViewController {
var RXnames = [String] ()
var RXidentities = [String] ()
var RXdetail = [String] ()
#IBAction func home(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
RXnames = ["Acetaminophen", "Activated Charcoal","Adenosine","Albuterol", "Amiodarone", "Aspirin","Atropine Sulfate",
"Calcium Chloride","Dextrose","Diltiazem","Diphenhydramine","Dopamine","Epinephrine","Etomidate","Fentanyl","Furosemide",
"Glucagon","Glucose (Oral)","Ibuprofen","Ipratropium Bromide","Ketamine Hydrochloride","Ketoralac","Lidocaine","Lorazepam",
"Magnesium Sulfate","Methylprednisolone","Metoprolol","Midazolam","Morphine Sulfate","Naloxone","Nitroglycerin",
"Nitrous Oxide","Norepinephrine","Ondansetron","Oxygen","Promethazine","Racemic Epinephrine","Rocuronium","Sodium Bicarbonate",
"Succinylcholine","Transexamic Acid","Vecuronium"]
RXidentities = ["1","2","3","4","5","6","7","8","9","10",
"11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","25","26","27","28","29","30",
"31","32","33","34","35","36","37","38","39","40","41","42","43"]
RXdetail = ["Tylenol", "CharcoAid","Adenocard","Ventolin", "Cordarone", "Bayer","Atropen",
"CaCl","D50W","Cardizem","Benadryl","Intropin","Adrenalin","Amidate","Sublimaze","Lasix",
"Glucagon","Glucose (Oral)","Motrin","Atrovent","Ketalar","Toradol","Lidocaine","Ativan",
"Mag","Solu-Medrol","Lopressor","Versed","Duramorph","Narcan","Nitrostat",
"Nitrous","Levophed","Zofran","O2","Phenergan","Rac Epi","Zemuron","Bicarb",
"Anectine","TXA","Norcuron"]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return RXnames.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RXcell")
cell?.textLabel!.text = RXnames[indexPath.row]
cell?.detailTextLabel!.text = RXdetail[indexPath.row]
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vcName = RXidentities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: (vcName))
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
Short of creating a whole model class, you could do something like this where I've combined your RXDetail and RXNames so as to keep the data together and lessen the chance of errors should you change the order or add/remove items. As requested I have updated this to include an array of images. I hope this helps.
class MedicationsController: UITableViewController {
var RXItems : [(name:String, detail:String, images:[UIImage])]!
override func viewDidLoad() {
RXItems = [("Acetaminophen", "Tylenol", [#imageLiteral(resourceName: "example-image"), #imageLiteral(resourceName: "example-image")]),
("Activated Charcoal", "CharcoAid", [#imageLiteral(resourceName: "example-image")])] //etc
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return RXItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RXcell")
cell?.textLabel?.text = RXItems[indexPath.row].name
cell?.detailTextLabel?.text = RXItems[indexPath.row].detail
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showDetailsSegue", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "showDetailsSegue") {
let viewController = segue.destination as! DetailsViewController
viewController.images = RXItems[sender as! Int].images
viewController.title = RXItems[sender as! Int].name
}
}
}
It appears you haven't set the delegate correctly in the storyboard, however I have improved my code to both set this in code, and set the size of the images to be constrained to, at most, the width of the root view (self.view) whilst maintaining the aspect ratio:
import UIKit
import AVKit
class DetailsViewController: UIViewController, UIScrollViewDelegate {
var images : [UIImage]?
var imageViews = [UIImageView]()
#IBOutlet private weak var scrollView: UIScrollView!
private var _contentView : UIView?
var contentView: UIView {
if(_contentView == nil) {
_contentView = UIView.init(frame: CGRect.zero)
self.scrollView.addSubview(_contentView!)
}
return _contentView!
}
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.delegate = self
if let images = self.images {
var contentSize = CGSize(width: self.view.frame.size.width, height: 0)
for img in images {
let size = CGSize(width: self.view.frame.size.width, height: CGRect.infinite.height)
let rect = CGRect(origin: CGPoint.zero, size: size)
let iv = UIImageView.init(frame: CGRect(origin: CGPoint(x:0, y:contentSize.height), size: AVMakeRect(aspectRatio: img.size, insideRect: rect).size))
contentSize.height += iv.frame.size.height
iv.image = img
self.contentView.addSubview(iv)
self.imageViews.append(iv)
}
self.contentView.frame.size = contentSize
self.scrollView.contentSize = contentSize
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
var contentSize = CGSize(width: self.view.frame.size.width, height: 0)
for iv in self.imageViews {
let size = CGSize(width: size.width, height: CGRect.infinite.height)
let rect = CGRect(origin: CGPoint.zero, size: size)
iv.frame = CGRect(origin: CGPoint(x:0, y:contentSize.height), size: AVMakeRect(aspectRatio: iv.image!.size, insideRect: rect).size)
contentSize.height += iv.frame.size.height
}
self.contentView.frame.size = contentSize
self.scrollView.contentSize = contentSize
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.contentView
}
}
Then set your storyboard up like:
Only replace the UIImageView with a UIScrollView, setting the delegate and outlets accordingly.

UITableView delegate methods not being called. Created from another class

I'm trying to add UITableView from another class but the delegate methods are not being called. Only the numberOfRowsInSection method is being called. I know I can do this in the main ViewController, but I would like to do it from another class. Is it possible? This code is fully functional, just copy and paste into a project. Thank you!
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let t = Table()
t.create()
}
}
class Table: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let myArray: NSArray = ["First","Second","Third"]
func create() {
let barHeight = UIApplication.shared.statusBarFrame.size.height
let displayWidth = UIScreen.main.bounds.width
let displayHeight = UIScreen.main.bounds.height
let myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
UIApplication.shared.delegate?.window??.rootViewController?.view.addSubview(myTableView)
myTableView.dataSource = self
myTableView.delegate = self
myTableView.backgroundColor = UIColor.red
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Num: \(indexPath.row)")
print("Value: \(myArray[indexPath.row])")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("numberOfRowsInSection")
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cellForRowAt")
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = "\(myArray[indexPath.row])"
return cell
}
}
When you run this:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let t = Table()
t.create()
}
}
You have created a local variable t. As soon as you leave the viewDidLoad() function, t no longer exists - so there are no delegate methods to call.
Instead, create a class-level variable that will stick around:
class ViewController: UIViewController {
let t = Table()
override func viewDidLoad() {
super.viewDidLoad()
t.create()
}
}
I think it is not called due to it Tablview not added to self.view or else. so you need to add this line after setting of tableview.
func create() {
let barHeight = UIApplication.shared.statusBarFrame.size.height
let displayWidth = UIScreen.main.bounds.width
let displayHeight = UIScreen.main.bounds.height
let myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
UIApplication.shared.delegate?.window??.rootViewController?.view.addSubview(myTableView)
myTableView.dataSource = self
myTableView.delegate = self
myTableView.backgroundColor = UIColor.red
self.view.addSubview(myTableView) //add this line
}

Resources