UICollectionView wrapped in a UIViewController - ios

I have a UICollectionView that I placed in a custom UIViewController via Storyboard and pinned its leading/trailing/top/bottom space to its superview.
Then I have a custom UICollectionViewController subclass that should use the collection view. So in the superview's UIViewController (PrimaryViewController) I have an outlet to the collection view and I instantiate my custom UICollectionViewController. I assign it the collection view and I assign the custom UICollectionViewController as delegate and dataSource for the collection view.
But when I run this, the collection view doesn't appear on the screen. It is obvious that the viewDidLoad() doesn't get called in the custom UICollectionViewController class so either I'm missing a key part or I'm approaching this the wrong way.
Can somebody tell me how to construct the connection between the collection view (which is placed via Storyboard) and the custom UICollectionViewController class (which is code only) in a way that makes this work properly?
Here's my (simplified) code so far ...
class PrimaryViewController : UIViewController {
#IBOutlet private weak var _collectionView:UICollectionView!
private var _collectionViewCtrl:CustomCollectionViewController!
override func viewDidLoad() {
super.viewDidLoad()
_collectionViewCtrl = CustomCollectionViewController(collectionView: _collectionView)
}
}
class CustomCollectionViewController : UICollectionViewController {
init(collectionView:UICollectionView) {
super.init(nibName: nil, bundle: nil)
self.collectionView = collectionView
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
required init(coder aDecoder:NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}

In IB or your Storyboard, you can use a container view and embed your custom collection view controller inside. This gives you the ability to manipulate each view controller in it's own context, because they each have their own nib, and will handle instantiating your collection view controller auto-magically.
Your PrimaryViewController can look like this:
class PrimaryViewController : UIViewController {
#IBOutlet private weak _collectionView: UIView
private var _collectionViewController: CustomCollectionViewController! {
// ???: You can also iterate through child view controllers looking for a class match if you embed other controllers.
return self.childViewControllers[0] as CustomCollectionViewController!
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Which will also call viewDidLoad() on your CustomCollectionViewController. You can hide and show the view through the _collectionView property, or directly manipulate it through _collectionViewController.
The pain comes from any logic that may be the appearance logic (viewWillAppear(_: Bool), viewWillDisappear(_: Bool), etc) because you'll have to trigger those yourself.
Your storyboard should look something like this (My container view is hidden):

Note that the object that acts as the delegate/datasource for a UICollectionView does not have to be derived from UICollectionViewController. In fact, it shouldn't be unless you dragged out a UICollectionViewController in storyboard.
The datasource/delegate class should be derived from NSObject
#interface CustomCollectionViewSupervisor : NSObject <UICollectionViewDataSource, UICollectionViewDelegate>
and must implement the datasource/delegate methods, including but not necessarily limited to
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

Related

How to add UITableviewController inside UIView

I have one view controller which is a subclass of UITableViewcontroller, that UITableViewcontroller i need show under one UIView which I need to assign Corner Radius so it will match with my design.
UITableViewcontroller is the Generic tableview class which I have used in the whole project so I couldn't make changes in the structure.
All my ViewController are created programmatically, i have not used anywhere Storyboard.
Here is my Viewconroller Code where I am implementing
headerViewController is part which i mark as white
deal and team controller is my UITableviewController which i have added in SJSegment
private func setupSegmentController() {
segmentViewController.headerViewHeight = 350
segmentViewController.headerViewController = headerViewController
segmentViewController.segmentControllers = [
dealViewController,
teamViewController]
segmentViewController.delegate = self
addChild(segmentViewController)
segmentViewController.view.frame = view.bounds
view.addSubview(segmentViewController.view)
segmentViewController.didMove(toParent: self)
}
Below in red highlighted is the area which i need to design
What I understand you want to add a view controller as child in some other view controller. You have to use ContainerView in the View Controller where you want to show that table Table View Controller. Create an outlet of that Container View then add the table view as child.
let yourTableViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourTableViewController") as! UITableViewcontroller
yourTableViewController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
yourTableViewController.view.frame = self.containerView.bounds
self.addChild(yourTableViewController)
containerView.addSubview(yourTableViewController.view)
yourTableViewController.didMove(toParent: self)
You need to subclass UITableView and view.addSubview(yourCustomClass) . It is not necessary to add UITableViewController inside your UIView
Controllers it's also a basic class that can control your view. You can add as subview tableView you your generic view and set their delegate and dataSource to the main view controller. You don't need to create tablewviewcontroller for this.
all you need is - (inside main view controller)
tableView.delegate = self
tableView.dataSource = self.
and after this you must implement protocol conformance
MainViewController: UITableViewCOntrollerDelegate {
// implementation here
}
MainViewController: UITableViewControllerDataSource {
// implementation here
}
After this you can customise your table view like view and do what you want

how to properly access a superclass view controller's IBOutlet property from its subclass?

how to properly access a superclass view controller's IBOutlet property from its subclass?
I have a DetailViewController and An AddViewController which is a subclass of the DetailViewController. In DetailVC, I have a bunch of textViews as IBOutlet properties connected from storyboard. I want to use these textViews in AddVC, but always found nil.
// These textViews are connected to storyboard's DetailViewController from DetailViewController
#IBOutlet var textViews: [KMPlaceholderTextView]!
// I'm trying to access those textViews from AddViewController which is a subclass of DetailViewController, but they are nil
class JLAddViewController: JLDetailViewController {
// MARK: - *****数据源*****
// 用来接收主控制器搜索框上的单词
var word:String?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 打开每个textView的输入功能
textViews.forEach {
$0.isUserInteractionEnabled = true;
$0.isEditable = true
}
}
}
The view controllers in the storyboard are not classes but instances. The interface and outlets you designed for an instance of DetailViewController belong to that one instance, not to some other instance and certainly not to an instance of a subclass.

Having trouble avoiding subclassing

I have an app with multiple view controllers. I am implementing a search bar to navigate a table view that is in each of these view controllers.
I have chosen to implement the search controller using a custom class, where I handle all the search logic. In order to make this possible, I am currently using a superclass from which each view controller inherits. I would like to know if there is a way for me to make this work without subclassing.
Here is the current implementation of my SearchController class:
class SearchController: NSObject, UISearchBarDelegate {
/* This is the trouble spot. If I change this to UIViewController?,
I get the compiler error "value of type UIViewController has no member tableView" */
weak var viewController: BaseViewController?
/*
... rest of SearchController implementation
includes methods that interact with view controller table views
*/
}
this is the BaseViewController class:
class BaseViewController: UIViewController {
let searchController = SearchController()
let tableView = UITableView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
/*
... rest of BaseViewController implementation
*/
}
To summarize, the issue I am having is that I have several view controllers with tableviews and I can't seem to make this work without creating a new base class that they can inherit from. Using UIViewController simply won't work because the UIViewController class does not have a tableView property built into it.
Any ideas?
You do not need to force all your viewControllers to subclasses BaseViewController. If the only requirement is for the viewController to have a tableView property then define a protocol with that requirement and make the relevant viewControllers implement that protocol.
Rewriting your example:
protocol BaseControllerProtocol: class {
var tableview: UITableView { get }
}
class SearchController: NSObject, UISearchBarDelegate {
//We store any class that implements the BaseControllerProtocol protocol
//Now you can use viewController.tableview
weak var viewController: BaseControllerProtocol?
//If you what to have UIViewcontrollers instances only use:
//weak var viewController: (UIViewController & BaseControllerProtocol)?
}
//An example of a viewcontroller that implements the BaseControllerProtocol
class ARandomViewController : UIViewController, BaseControllerProtocol {
var tableview: UITableView = UITableView()
}
I think you could still use UIViewController? if you assign its UITableView to your SearchViewController's private tableView calculated instance variable like so:
class SearchController: NSObject, UISearchBarDelegate {
weak var viewController: UIViewController?
fileprivate var _tableView: UITableView? {
if let vc = self.viewController {
for subview in vc.view.subviews {
if let tableView = subview as? UITableView {
return tableView
}
}
}
return nil
}
// Whatever methods interact with table view should now use self._tableView.
func doSomething() {
guard let tableView = self._tableView else { return }
// Do something with the tableView
}
}

Swift 3 UITableView Problems

My interface consists of two things inside my main ViewController: a label (the top half of the screen), and a table (the bottom half).
For the life of me, I cannot find a tutorial or example in Swift 3 + iOS 10 where a UITableView is successfully used, as opposed to a UITableViewController which takes up the entire screen.
What must be done to use a UITableView with dynamic cells in the bottom half of your interface?
I tried adding the UITableView, then creating a subclass of UITableViewController, but I was unable to select this in the UITableView's Custom Class -> Class dropdown. Apparently, I need to subclass UITableView, but I can find no examples of how to do this.
Use a standard UIViewController and drag a table view into the canvas.
In IB connect the table view to the IBOutlet and delegate and datasource to the controller.
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView : UITableView!
...
Unlike UITableViewController you have to implement all relevant datasource and delegate methods.
At first , the UITableView and UITableViewController are not the same thing, the TableView is a view and TableViewController is a Controller withe a tableview inside.
If you are using UITableViewController you should drag a UITableViewController, and then change its class in the third tab on the top!
If you are using a basic ViewController and drag a TableView inside, you could get The TableView in the ViewController using an IBOutlet.#John D.
You can use normal ViewController and init a UITableView in the viewDidLoad and add it to the ViewController.
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView = UITableView.init(frame: CGRect(x:0, y: 300, height: 300, width:screenWidth))
self.view.addSubview(tableView)
self.tableView.register(UINib.init(nibName: "NameListTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: nameListTableViewCellId)
// Do any additional setup after loading the view.
}
set the tableview.delegate = self and tableview.datasource = self,
using methods in the pic and lots other in the UITableViewDelegate and UITabelViewDataSource protocol to Custom your tableView!
hope this would help

Swift: Default Storyboard background Image for all ViewControllers

Is there a way to set (preferably in storyboard IB) an image, which, will serve as the background image for all ViewControllers in the whole storyboard. I don't want to have to add a background image in every ViewController or replicate that in code.
I would could create a UIViewController subclass (e.g. name it DefaultViewController) that sets a specific background color in one of the initialization methods (e.g. viewDidLoad, but don't forget if you override this in a subclass of this class to call it's super method).
Then, let all your view controllers inherit from DefaultViewController
Example code:
class DefaultViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = = UIColor.redColor()
}
}
class SomeViewController: DefaultViewController {
override func viewDidLoad() {
// this call makes the background red, you can also not override this method and it will work too
super.viewDidLoad()
}
}

Resources