How to fix iOS10 safe area and topLayoutGuide issue? - ios

I have a question about safe area.
And I write a code and build in two simulators of iOS version 10.2 and 11.4.
It shows different part of red rectangle area like following image.
What's wrong with me?
Thanks.
code here:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UINavigationController(rootViewController: ViewController())
window?.makeKeyAndVisible()
return true
}
}
class ViewController: UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "TITLE HERE"
tableView.dataSource = self
tableView.delegate = self
self.view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.left.equalTo(10)
make.top.equalTo(self.topLayoutGuide.snp.bottom)
make.right.bottom.equalTo(-10)
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "\(indexPath) TEST"
return cell
}
}

Related

iOS: RefreshControl + large title doesn't work well in UITabBarController

I have UIViewController with NavigationBar that is a part of UITabController.
Inside UIViewController I have only UITableView.
NavigationBar is transparent and blurred.
TableView top constraint is to superview, so when I scroll content it goes behind navigation bar.
I have large titles enabled:
Problem:
loadData data triggered immediately when I start to scroll down.
Right after I scroll few pixels down.
All works fine if I remove largeTitles,
but with large titles it feels like refreshControl already at position when it ready to trigger .valueChanged
Also it works fine if to remove tab bar and load navigationController directly as root. But I need tabbar.
Full code:
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
self.window = window
window.rootViewController = TabBarController()
return true
}
}
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let navigationController = UINavigationController(rootViewController: ViewController())
navigationController.navigationBar.prefersLargeTitles = true
viewControllers = [navigationController]
}
}
class ViewController: UIViewController {
private let tableView = UITableView()
private let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Test"
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
tableView.delegate = self
tableView.dataSource = self
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(loadData), for: .valueChanged)
}
#objc func loadData() {
print("loadData triggered")
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.refreshControl.endRefreshing()
}
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell
if let defaultCell = tableView.dequeueReusableCell(withIdentifier: "defaultCell") {
cell = defaultCell
} else {
cell = UITableViewCell(style: .value1, reuseIdentifier: "defaultCell")
}
cell.textLabel?.text = "Test"
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10
}
}
BUT
All works fine if it's from StoryBoard:

SearchResultsController obscures screen when used with UINavigationItem

I'm using new integrated UISearchBar available in iOS 11, the problem is as soon as I tap on the searchbar and start typing text, the SearchResultsController obscures the whole screen, including the searchbar. It is impossible to dismiss the results controller or cancel search afterwards.
To demonstrate the issue, I've configured a minimal reproducible example:
import UIKit
let reuseid = "reuseIdentifier"
class TableViewController: UITableViewController, UISearchResultsUpdating {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: reuseid)
}
// MARK: - Table view data source
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: reuseid, for: indexPath)
return cell
}
func updateSearchResults(for searchController: UISearchController) {
print(searchController.searchBar.text)
}
}
class ViewController: UIViewController {
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: TableViewController())
navigationItem.searchController = searchController
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = UIColor.white
window?.makeKeyAndVisible()
let nc = UINavigationController(rootViewController: ViewController())
window?.rootViewController = nc
return true
}
}
Initial state
Tapping on the SearchBar
The screen is obscured by the UITableView - colored in green
What could cause this bug and how can it be avoided?
Solved by adding this to the SearchResultsUpdater:
edgesForExtendedLayout = []
With default edges, the ResultsController tries to extend its view beyond the UINavigationBar and hence, obscures it:

UITableView compiling error in AppDelegate Swift

This is my Viewcontroller:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let list = ["Facebook: 2000$", "Twitter: 10000$", "Vine: 23356$", "Uber: 35000", "Adobe Systems: 400900", "Agilent Tech: 456700", "Ebay: 98899"]
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return (list.count)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.text = list[indexPath.row]
return(cell)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
and my app delegate:
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) { etc..
What am I doing wrong?
It may be missing-
override func viewDidLoad() {
super.viewDidLoad()
yourTableView.delegate = self
yourTableView.dataSource = self
}

iOS use Swift files as first view

In Xcode 6, is it possible to use a .swift file as the 1st view the user will see when they open my app?
The file below is for a table view as I prefer to use swift instead of IB (too many views makes IB look messy).
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView!
let items = ["Hello 1", "Hello 2", "Hello 3"]
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
self.tableView = UITableView(frame:self.view.frame)
self.tableView!.dataSource = self
self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(self.tableView)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.items.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel.text = "\(self.items[indexPath.row])"
return cell
}
}
var ctrl = ViewController()
According to Apple's View Controller Programming Guide, "When working with view controllers directly, you must write code that instantiates the view controller, configures it, and displays it." However it also states "You gain none of the benefits of storyboards, meaning you have to implement additional code to configure and display the new view controller." That being said if you still desire to do this, this is how you do it (in your app delegate):
var window: UIWindow?
var viewController: ViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.backgroundColor = UIColor.whiteColor()
viewController = ViewController()
// Any additional setup
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return true
}

create a UITableViewController programmatically in Swift

I'm trying to, as the title say, set up a UITableViewController programmatically. After a few hours of trying I hope someone can help me. And, yes, I hve checked out other posts on this matter:
import UIKit
class MainViewController: UITableViewController {
init(style: UITableViewStyle) {
super.init(style: style)
// Custom initialization
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// #pragma mark - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
return 1
}
override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
var cell = tableView?.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if !cell {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
}
cell!.textLabel.text = "test"
return cell
}
}
and the appDelegate looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainViewController: UITableViewController = MainViewController(style: UITableViewStyle.Plain)
let navigationController: UINavigationController = UINavigationController()
navigationController.pushViewController(mainViewController, animated: false)
self.window!.rootViewController = navigationController
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
return true
}
The program run, but as soon as it does, I get the following error:
fatal error: use of unimplemented initializer 'init(nibName:bundle:)' for class 'HelloWorld.MainViewController'
I then changes the MainViewController(style: UITableViewStyle.Plain) to MainViewController(nibName: nil, bundle: nil) but then I get the following syntax error: Extra argument 'bundle' in call
Any help would be much appreciated
I'm using a subclass of UITableViewController with no issues, using the (nibName:bundle:) form, but I've overridden that in my subclass. I tried replacing my subclass with a standard UITableViewController, and it still worked fine. Are you possibly overriding an init(...) method in your subclass?
In the AppDelegate or wherever you call the TableViewController:
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
if let window = window {
window.backgroundColor = UIColor.whiteColor()
var mainTableViewController = MainTableTableViewController(style: .Plain)
window.rootViewController = UINavigationController(rootViewController: mainTableViewController)
window.makeKeyAndVisible()
}
return true
}
In the UITableViewController (assuming no custom TableViewCell implementation):
import UIKit
class MainTableTableViewController: UITableViewController {
override init(style: UITableViewStyle){
super.init(style: style)
}
override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!){
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
// MARK: - Tableview Data Source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return [*YOUR_DATA_ARRAY].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = [*YOUR_DATA_ARRAY][indexPath.row]
}
For an full example: visit: https://github.com/ericcgu/EGStormTracker
I just removing
init(style: UITableViewStyle) {
super.init(style: style)
}
and then init like this:
let mainViewController: UITableViewController = MainViewController()

Resources