UITableView embedded in UIView, empty rows - ios

I am working on a new application and I have some problems:
I am developing everything programmatically, so I created a SCROLLVIEW and a CONTAINERVIEW for all my pages. containerView is embedded in scrollView.
Every page has a different Controller, in this case "SearchViewController".
The containerView contains the UIView "selectView" that belongs to "SearchViewController". See below:
let scrollView: UIScrollView = UIScrollView()
let containerView: UIView = UIView()
//SCROLLVIEW
scrollView.frame = CGRectMake(0, 0, view.frame.width, view.frame.height)
self.view.addSubview(scrollView)
//CONTAINERVIEW
containerView.frame = CGRectMake(menuWidth, 0, view.frame.width, view.frame.height)
containerView.backgroundColor = UIColor.whiteColor()
scrollView.addSubview(containerView)
let s: SearchViewController = SearchViewController()
s.setup(bannerHeight, containerViewWidth: containerView.frame.width, containerViewHeight: containerView.frame.height)
containerView.addSubview(s.selectView)
import UIKit
class SearchViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
let selectView: UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
}
let table: UITableView = UITableView()
var items: [String] = ["A", "B", "C"]
var filteredItems = [String]()
func setup(bannerHeight: CGFloat, containerViewWidth: CGFloat, containerViewHeight: CGFloat){
//SELECT PAGE
selectView.frame = CGRectMake(0, bannerHeight, containerViewWidth, containerViewHeight - bannerHeight)
//UITABLEVIEW
table.frame = CGRectMake(0, 0, selectView.frame.width, selectView.frame.height)
table.delegate = self
table.dataSource = self
table.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
selectView.addSubview(table)
}
func numberOfSectionsInTableView(tableView:UITableView)->Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("tableViewCOUNT")
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("tableViewMAIN")
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.textLabel!.text = items[indexPath.row]
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
}
So now i have this hierarchy: ScrollView<-containerView<-selectView<-table
The problem is that no data appear! In output I can see "tableViewCOUNT" but never "tableViewMAIN" and except for the empty rows there are no data.
Could somebody help me to understand why?
Am I using the correct way? I would like to have a mainController and for every page a subController, then I will embed the page I need inside the containerView (like an iframe in html).
Thank you in advance!

Try calling
table.reloadData()
in the setup.

Related

Continuous scrolling between tableView and scrollView

I have a parent scroll view with a uiview header and table view. I am trying to have a similar behavior to Twitter or Instagram profile page. You start scrolling the parent scroll view and as soon as the header is gone there is a continuous transition from the scroll view scrolling to the table view scrolling without having to lift my finger and replace it on the table view. Right now the current behavior is a little jank. I have to lift my finger and put it on the table view after the scroll view content offset is past the header to start swiping the table view.
MainViewController
import UIKit
import XLPagerTabStrip
class MainViewController: UIViewController {
lazy var headerViewController: UIViewController = {
let header = UIViewController()
return header
}()
lazy var bottomViewControllers: BottomPageViewController = {
let bvc = BottomPageViewController()
return bvc
}()
lazy var scrollView: UIScrollView = {
let sv = UIScrollView()
sv.delegate = self
sv.showsVerticalScrollIndicator = false
sv.bounces = true
sv.bounces = false
return sv
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(scrollView)
let f = UIScreen.main.bounds
scrollView.frame = CGRect(x: f.minX, y: f.minY, width: f.width, height: f.height)
add(headerViewController, to: scrollView, frame: CGRect(x: 0, y: 0, width: f.width, height: 150))
add(bottomViewControllers, to: scrollView, frame: CGRect(x: 0, y: headerViewController.view.bounds.height, width: f.width, height: f.height))
scrollView.contentSize = CGSize(width: f.width, height: f.height * 2)
if let vcs = bottomViewControllers.viewControllers as? [BottomViewController] {
for vc in vcs {
vc.delegate = self
}
}
}
}
extension MainViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let controllers = bottomViewControllers.viewControllers as? [BottomViewController] else { return }
let selectedController = controllers[bottomViewControllers.currentIndex]
if self.scrollView == scrollView {
selectedController.tableView.isScrollEnabled = self.scrollView.contentOffset.y >= 150
print(scrollView.contentOffset.y)
scrollView.isScrollEnabled = !selectedController.tableView.isScrollEnabled
bottomViewControllers.view.frame.origin.y = max(150, scrollView.contentOffset.y)
}
}
}
extension MainViewController: CustomScrollDelegate {
func tableViewScroll(_ viewController: BottomViewController) {
print(viewController.tableView.contentOffset.y)
viewController.tableView.isScrollEnabled = viewController.tableView.contentOffset.y > 0
}
}
BottomViewController
import UIKit
import XLPagerTabStrip
protocol CustomScrollDelegate {
func tableViewScroll(_ viewController: BottomViewController)
}
class BottomViewController: UITableViewController {
var pageTitle: String?
var pageIndex: Int = 0
var delegate: CustomScrollDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
self.tableView.isUserInteractionEnabled = false
self.tableView.bounces = true
self.tableView.showsVerticalScrollIndicator = true
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TETST")
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TETST", for: indexPath) as? UITableViewCell else { return UITableViewCell() }
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1000
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
delegate?.tableViewScroll(self)
}
init(pageTitle: String, pageIndex: Int) {
self.pageTitle = pageTitle
self.pageIndex = pageIndex
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension BottomViewController: IndicatorInfoProvider {
func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
return IndicatorInfo.init(title: pageTitle ?? "Tab \(pageIndex)")
}
}
You should simply add your header as a header to the UITableView (not a section header!) and let it scroll with the rest of the UITableView: How to scroll the header along with the UITableView?
Also you can make the UITableView link it's contentSize directly to it's height so the UITableView itself doesn't scroll at all, ever, like this: Resizing UITableView to fit content
It all kind of depends if you add rows dynamically by paging etcetera how complex your solution would be. But I think you would get there most of the time by simply setting up the UITableView header in the correct mode

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.

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
}

UiView fixed on top of UiTableViewController

I need to put an UIView fixed on top of UITableViewController (like a header). I've tried this:
override func scrollViewDidScroll (scrollView: UIScrollView) {
var fixedFrame: CGRect = self.uiTopView.frame;
fixedFrame.origin.y = scrollView.contentOffset.y;
self.uiTopView.frame = fixedFrame;
}
But it does not work and I don't know why. Someone have any idea?
This can not be done, one way to accomplish this is to add the UITableViewController insideUIContainerView
So the structure will be as follows:
ViewController1 contains aUIContainerView this container view has embedded segue
to your tableViewController.
Then you can add the view to the ViewController1.
Why do you actually use UITableViewController instead of UIViewController with a tableView inside?
Maybe you should add your header view first then add you tableview depending on the header's frame.
for example: `import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var fixedLabel : UILabel!
var tableView : UITableView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tableView.frame = CGRectMake(0, self.fixedLabel.frame.maxY, self.view.frame.width, self.view.frame.height-70)
self.fixedLabel.frame = CGRectMake(0,0,self.view.bounds.width,70)
}
override func viewDidLoad() {
super.viewDidLoad()
self.fixedLabel = UILabel()
self.fixedLabel.backgroundColor = UIColor.blueColor()
self.fixedLabel.text = "This is a fixedLabel"
self.fixedLabel.textAlignment = .Center
self.tableView = UITableView()
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.addSubview(fixedLabel)
self.view.addSubview(tableView)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell?.textLabel?.text = "Your text"
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
}
`

Swift: UIView appear in UITableView cell

Im having an issue putting a UIView that I created in a specific UITableView cell. Here is my code:
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
//MARK : Properties
var tableView = UITableView()
var items: [String] = ["Age", "Gender", "Smoking Hx", "Occup. -Ag", "Family Hx", "Chronic Lung Disease Radiology", "Chronic Lung Disease Hx", "Nodule Border", "Nodule Location", "Satellite Lesions", "Nodule Pattern Cavity", "Nodule Size"]
var navigationBar = NavigationBar()
var gender = GenderView()
var maleIcon = MaleIconView()
override func viewDidLoad() {
super.viewDidLoad()
//Create TableView
tableView.frame = CGRectMake(0, self.view.bounds.height * 0.097, self.view.bounds.width,
self.view.bounds.height - self.view.bounds.height * 0.097);
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
//Create Navigation Bar with custom class
self.navigationBar = NavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height * 0.097))
self.view.addSubview(navigationBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
//Cell wont turn grey when selected
cell.selectionStyle = UITableViewCellSelectionStyle.None
//Want to add UIView male Icon in first row
if(indexPath.row == 0){
maleIcon = MaleIconView(frame: CGRect(x: 0, y: 0, width: 55, height: 55))
maleIcon.center.x = cell.center.x + cell.center.x * 0.5
maleIcon.center.y = cell.contentView.center.y
maleIcon.layer.cornerRadius = 0.5 * maleIcon.bounds.size.width
//maleIcon.layer.borderWidth = 3.0
cell.addSubview(maleIcon)
}
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.view.bounds.height * 0.15
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
}
Maybe the issue exists within the MaleIconView()? Here is the code to that:
class MaleIconView: UIView {
var maleView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
self.frame = frame
setUpView()
}
func setUpView(){
maleView.frame = CGRectMake(0, 0, self.bounds.width, self.bounds.height)
maleView.alpha = 1
maleView.backgroundColor = UIColor.blackColor()
maleView.layer.cornerRadius = 0.5 * maleView.bounds.size.width
self.addSubview(maleView)
}
func hide(){
self.removeFromSuperview()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Im trying to get the UIView to appear on the right side of the cell 0. There is also this issue where the indexPath's are all off, i think this could be of some issue to why the UIView appears in multiple cells. Thank you in advance!
Here is the code for what should help you with your issues. I made a few assumptions about how you may be trying to implement. But this should be a great start for you.
https://www.dropbox.com/sh/2ilyfnc1pqurjfd/AAC2rU-zlvUtjdKYV33JrQJQa?dl=0
I also highly recommend that you use auto layout for your various view dimensions rather than hard coding weird offsets. It may be difficult to start with. But it definitely pays off in the long run!
It's kinda strange that maleIcon is UIViewController property in your code.
Did you try to put in cellForRowAtIndexPath?
like that:
//Want to add UIView male Icon in first row
if(indexPath.row == 0){
let maleIcon = MaleIconView(frame: CGRect(x: 0, y: 0, width: 55, height: 55))
I'm not sure it will help with reusable cells though. What will help (but there is slightly more work) is to create your own cell class, add maleIcon as property, register this class with your table and put this in your cellForRowAtIndexPath like that:
if (indexPath.row == 0) {
cell.maleIcon.hidden = false}
else {
cell.maleIcon.hidden = true}

Resources