UITableview to cell detail with image - ios

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.

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.

SwiftUI Custom UITableView Representable contentOffset is always wrong on the last elements

I made a custom UITableView to be implemented with SwiftUI, to customize the header view and section headers. Every item is written in SwiftUI, and has a set height. The table is wrapped inside a GeometryReader.
I need to save the scroll offset while navigating between pages, so everytime I tap on an item, I save the contentOffset in an #ObservableObject, and when navigating back to that view, I just pass the saved offset (I'm not using the standard NavigationLink navigation, but a custom stack, so it is not saved between pages).
The problem is that, whenever the UITableView content is loaded with a previously set contentOffset (which is (x:0; y:0) by default), the content shown is always the previous content (i.e. if I have 14 rows and I tap on row 14, the setContentOffset only shows rows up to row 8/9).
This doesn't happen if I tap on the first rows, like 5 or 6.
I've already tried different solutions, like setting a height dictionary for rows, saving their height and passing it to the delegate methods, but it doesn't work.
Also layoutIfNeeded(), applied to the UITableView during the makeUIView doesn't do anything.
I currently can't set automaticallyAdjustScrollViewInsets = false because
I would have to rewrite the entire component to fit in a UIViewController
The contentInset is already always zero, which I think is the purpose of that instruction.
What I've noticed though, is that my UITableViewRepresentable inside the GeometryReader is drawn twice. I'm not sure why, but it just happens. Only the second time, the containerSize is different than zero.
This is my code:
UITableViewRepresentable
import SwiftUI
import UIKit
struct UITableViewRepresentable: UIViewRepresentable {
var sections: [String]
var items: [Int:[AnyView]]
var tableHeaderView: AnyView? = nil
var separatorStyle: UITableViewCell.SeparatorStyle = .singleLine
var separatorInset: UIEdgeInsets?
var scrollOffset: CGPoint
var onTap: (CGPoint) -> Void
var sectionHorizontalPadding: CGFloat = 5
var sectionHeight: CGFloat = 50
var containerSize: CGSize
func makeUIView(context: Context) -> UITableView {
assert(items.count > 0)
let uiTableView = UITableView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: self.containerSize), style: .plain)
uiTableView.sizeToFit()
uiTableView.separatorStyle = self.separatorStyle
if(self.separatorStyle == .singleLine && self.separatorInset != nil) {
uiTableView.separatorInset = self.separatorInset!
}
uiTableView.automaticallyAdjustsScrollIndicatorInsets = false
uiTableView.dataSource = context.coordinator
uiTableView.delegate = context.coordinator
if(tableHeaderView != nil) {
let hostingHeader: UIHostingController = UIHostingController<AnyView>(rootView: tableHeaderView!)
uiTableView.tableHeaderView = hostingHeader.view
uiTableView.tableHeaderView!.sizeToFit()
}
uiTableView.register(HostingCell.self, forCellReuseIdentifier: "Cell")
return uiTableView
}
func updateUIView(_ uiTableView: UITableView, context: Context) {}
func makeCoordinator() -> Coordinator {
return Coordinator(self, sectionHeight: self.sectionHeight)
}
class HostingCell: UITableViewCell { // just to hold hosting controller
var host: UIHostingController<AnyView>?
}
class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource {
var parent: UITableViewRepresentable
var sectionHeight: CGFloat
var scrollOffset: CGPoint
var alreadyScrolled: Bool
init(_ parent: UITableViewRepresentable, sectionHeight: CGFloat) {
self.parent = parent
self.sectionHeight = sectionHeight
self.scrollOffset = self.parent.scrollOffset
self.alreadyScrolled = false
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.parent.items.keys.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parent.items[section]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! HostingCell
let view = self.parent.items[indexPath.section]![indexPath.row]
// create & setup hosting controller only once
if tableViewCell.host == nil {
let controller = UIHostingController(rootView: AnyView(view))
tableViewCell.host = controller
let tableCellViewContent = controller.view!
tableCellViewContent.translatesAutoresizingMaskIntoConstraints = false
tableViewCell.contentView.addSubview(tableCellViewContent)
tableCellViewContent.topAnchor.constraint(equalTo: tableViewCell.contentView.topAnchor).isActive = true
tableCellViewContent.leftAnchor.constraint(equalTo: tableViewCell.contentView.leftAnchor).isActive = true
tableCellViewContent.bottomAnchor.constraint(equalTo: tableViewCell.contentView.bottomAnchor).isActive = true
tableCellViewContent.rightAnchor.constraint(equalTo: tableViewCell.contentView.rightAnchor).isActive = true
} else {
// reused cell, so just set other SwiftUI root view
tableViewCell.host?.rootView = AnyView(view)
}
tableViewCell.layoutIfNeeded()
return tableViewCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.scrollOffset = tableView.contentOffset
self.parent.onTap(self.scrollOffset)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(sectionHeight == 0) {
return nil
}
let headerView = UIView(
frame: CGRect(
x: 0,
y: 0,
width: tableView.frame.width,
height: sectionHeight
)
)
headerView.backgroundColor = App.Colors.NumberIcon.MainColor_UI
let label = UILabel()
label.frame = CGRect.init(
x: self.parent.sectionHorizontalPadding,
y: headerView.frame.height / 2,
width: headerView.frame.width,
height: headerView.frame.height / 2
)
label.text = self.parent.sections[section].uppercased()
label.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.footnote).bold()
label.textColor = .white
headerView.addSubview(label)
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return sectionHeight
}
fileprivate var heightDictionary: [Int : CGFloat] = [:]
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
heightDictionary[indexPath.row] = cell.frame.size.height
// if the first row has been drawed, then the content is ready, and the UITableView can scroll
if let _ = tableView.indexPathsForVisibleRows?.first, self.scrollOffset.y != 0 {
if indexPath.row == 0 && !self.alreadyScrolled {
tableView.setContentOffset(self.scrollOffset, animated: false)
self.alreadyScrolled = true // to prevent further updates of redeclarations of Coordinator
}
}
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let height = heightDictionary[indexPath.row]
return height ?? UITableView.automaticDimension
}
}
}
And this is my ContentView
struct ContentView: View {
#ObservedObject var listData: ListData = ListData()
var body: some View {
GeometryReader { geometry -> AnyView in
let tableHeaderView = AnyView(Text("TableHeaderView"))
let itemHeight: CGFloat = geometry.size.height * 1/3
let items:[AnyView] = [AnyView(Text("Item 1").frame(height: itemHeight)), AnyView(Text("Item 2").frame(height: itemHeight))]
return UITableViewRepresentable(
sections: ["Section 1"],
items: [0:items],
tableHeaderView: tableHeaderView,
separatorStyle: .none,
scrollOffset: self.listData.scrollOffset,
onTap: { (scrollOffset) in
self.listData.scrollOffset = scrollOffset
// navigate to other page...
},
sectionHorizontalPadding: itemHorizontalPadding,
containerSize: CGSize(width: pageWidth, height: listHeight)
).frame(width: geometry.size.width, height: geometry.size.height * 0.9)
}
}
}
ListData just holds the scrollOffset
class ListData: ObservableObject {
#Published var scrollOffset: CGPoint = CGPoint(x:0, y:0)
}
I don't understand this behaviour, but I'm also a beginner of UIKit, so I don't know if it's intended or not. Any help is much appreciated.
In the end I had to resort to the UIScrollView.contentOffset property, which is correct 100% of the time.
Updated code:
func updateUIView(_ uiTableView: UITableView, context: Context) {
if(!context.coordinator.alreadyScrolled) {
uiTableView.layoutIfNeeded()
Utilities.Threading.UI {
// remove animations so it doesn't do the scrolling animation during the begin/endUpdates, it can be omitted if you like
UIView.performWithoutAnimation {
uiTableView.beginUpdates()
uiTableView.setContentOffset(self.scrollOffset, animated: false)
uiTableView.endUpdates()
}
context.coordinator.alreadyScrolled = true
}
}
}
and in the Coordinator
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.scrollIndex = indexPath
self.parent.onTap(indexPath, self.scrollOffset)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.scrollOffset = scrollView.contentOffset
}
I've also removed the code inside the willDisplayCell delegate method that scrolls automatically.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
heightDictionary[indexPath.row] = cell.frame.size.height
}

ButtomSheet of Material Design does not show properly - swift

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...

How To Share Same UIView Between Multiple UITableView Cells

Objective
When the user clicks on any of the 3 blue buttons, all buttons change to the same color.
Note: this is an abstraction of a shared progress view problem, it's therefore important that only one UIView is shared (or mimicked) across my three rows
Here is a compilable Swift project:
import UIKit
class ToggleButton: UIButton {
var connectedView: UIView?
func onPress() {
self.isHidden = true
self.connectedView?.isHidden = false
}
}
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var myView: UIView? = nil
var toggleBtn: ToggleButton? = nil
override func viewDidLoad() {
self.setupTableView()
}
fileprivate func setupTableView() {
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.backgroundColor = UIColor.white
self.tableView.isOpaque = true
self.view.addSubview(self.tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "CellIdentifier")
let frame = CGRect(x: 10, y: 10, width: 30, height: 30)
if let view = self.myView, let btn = self.toggleBtn {
cell.addSubview(view)
cell.addSubview(btn)
} else {
let myView = UIView(frame: frame)
myView.backgroundColor = UIColor.green
myView.isHidden = true
cell.addSubview(myView)
let toggleBtn = ToggleButton(frame: frame)
toggleBtn.backgroundColor = UIColor.blue
toggleBtn.addTarget(self, action: #selector(onPress), for: .touchUpInside)
toggleBtn.connectedView = myView
cell.addSubview(toggleBtn)
}
return cell
}
#objc func onPress(_ sender: Any) {
if let button = sender as? ToggleButton {
button.onPress()
}
}
}
Any help appreciated.
The concept of UITableViewCell is made to be very independent each other.
So the only thing you can do it having a bool flag in your ViewController, then you init your 3 cells with this flags.
And finally each time the button is pressed you toggle the flag en reload your tableView.

Are there some optional wrong here?

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.

Resources