Add UIView over Navigation Bar after Push Segue - ios

I have two ViewControllers. I want to add an UIView over the navigation bar.
I could add the UIView on top of the first navigation bar by creating an UINavigationItem Outlet and adding the UIView created programatically to the UINavigationItem outlet titleView.
Code Snippet (HomeVC - Fist ViewController):
class HomeVC: UIViewController {
#IBOutlet weak var homeNavigationItem: UINavigationItem!
let navBarView = UIView()
let topNavBarLabel = UILabel()
let screenWidth = UIScreen.main.bounds.width
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navBarView.frame = CGRect(x: 0.0, y: 0.0, width: screenWidth, height: 50.0)
topNavBarLabel.text = "Hello World"
topNavBarLabel.textAlignment = NSTextAlignment.center
topNavBarLabel.textColor = UIColor.white
topNavBarLabel.frame = CGRect(x: 0.0, y: 10.0, width: screenWidth, height: 20.0)
navBarView.addSubview(topNavBarLabel)
homeNavigationItem.titleView = navBarView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Screenshot Home View:
Now incase of the SecondVC I am trying to do the same thing after the Push Segue.
Code Snippet (DetailVC - Second ViewController):
class DetailsVC: UIViewController {
let navBarView = UIView()
let screenWidth = UIScreen.main.bounds.width
let navBarTopLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navBarView.frame = CGRect(x: 0.0, y: 50.0, width: screenWidth, height: 50.0)
navBarView.backgroundColor = UIColor.black
navBarTopLabel.frame = CGRect(x: 0.0, y: 10.0, width: screenWidth, height: 20.0)
navBarTopLabel.textColor = UIColor.white
navBarTopLabel.text = "Details Hello"
navBarTopLabel.textAlignment = NSTextAlignment.center
navBarView.addSubview(navBarTopLabel)
self.view.addSubview(navBarView)
self.view.bringSubview(toFront: navBarView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Screenshot Details View:
Storyboard Screenshot:
View Hierarchy:
Note: I deliberately assigned an Y-position to the view more than 0, to be sure that the view is being created
But as I am not able to create an UINavigationItem, I am adding the programmatically created view to the view and even trying to bring the subView to the front.
Note: Yes, the size of the UINavigationBar has been increased, please refer here: Change width/height UINavigationBar embedded in a Navigation Controller

You could use the variable defined for UIViewController
public var navigationItem: UINavigationItem { get }
From the docs:
Created on-demand so that a view controller may customize its navigation appearance.
So in each subclass of UIViewController in viewDidLoad you can just do
self.navigationItem.titleView = navBarView

Related

Move UIView from ViewController to Window

Thanks for taking the time to read thus. So basically, I have a UIView in my UIViewController. I want a user to be able to press a button and then the UIView moves from my UIViewController to the my application's window so that the UIView will be above all UIViewControllers. The only thing I could think of doing was
class ViewController: UIViewController {
var window = UIApplication.shared.keyWindow!
var view = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(view)
}
func tappedAction() {
window.bringSubview(toFront: view)
}
}
but that didn't work. Does anyone have any ideas on how to accomplish this?
You cannot just bring the subview that's in your UIViewController to the front of your UIWindow.
You need to:
Remove the UIView from the UIViewController.
Add the UIView to the main UIWindow.
I chose to do this in this way:
import UIKit
class ViewController: UIViewController {
var customView: UIView!
// Load the main view of the UIViewController.
override func loadView() {
view = UIView()
}
override func viewDidLoad() {
super.viewDidLoad()
// Load the custom view that we will be transferring.
self.customView = UIView(frame: .init(x: 100, y: 250, width: 250, height: 250))
self.customView.backgroundColor = .red
view.addSubview(customView)
// Transfer the view. Call this method in your trigger function.
transfer(self.customView)
}
func transfer(_ view: UIView) {
// Remove the view from the UIViewController.
view.removeFromSuperview()
// Add the view to the UIWindow.
UIApplication.shared.windows.first!.addSubview(view)
}
}
You must set frame fro view at var view = UIView()
then you should add to window window.addSubview(view)
If your view is added on window then window.bringSubview(toFront: view) will work otherwise it will not.
If your view is added on window then you can use bringSubview(toFront:) like that:
Example:
let window = UIApplication.shared.keyWindow!
let view1 = UIView(frame: CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.width, height: window.frame.height))
window.addSubview(view1);
view1.backgroundColor = UIColor.black
let view2 = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 50))
view2.backgroundColor = UIColor.white
window.addSubview(view2)
UIApplication.shared.keyWindow!.bringSubview(toFront: view1)
So you need to add your view in window:
window.addSubview(view)

Add button overlay on UITableViewController with use static cells

I try to add button overlay on UITableViewController with static cells. But i get this result, button is working, but i not see result of search:
I'm trying to get this result:
I want to button was always at the bottom regardless of scrolling up or down.
In my code i use framework InstantSearch:
import UIKit
import InstantSearch
import WARangeSlider
class SearchTableViewController: UITableViewController {
#IBOutlet weak var resultButton: StatsButtonWidget!
override func viewDidLoad() {
super.viewDidLoad()
resultButton.frame = CGRect(x: 0, y: 0, width: 150, height: 60)
navigationController?.view.addSubview(resultButton)
InstantSearch.shared.registerAllWidgets(in: self.view)
LayoutHelpers.setupResultButton(button: resultButton)
resultButton.addTarget(self, action: #selector(resultButtonClicked), for: .touchUpInside)
}
}
How can i add button overlay on bottom in UITableViewController? Me need use only UITableViewController, not UIViewController with TableView.
You could directly add the button to the UITableView without AutoLayout, and make sure TableView's delegate is the controller, like:
override func viewDidLoad() {
super.viewDidLoad()
self.button.frame = CGRect(x: 0, y: self.tableView.frame.size.height - 50, width: self.tableView.frame.width, height: 50)
self.tableView.addSubview(self.button)
self.tableView.delegate = self
}
Then you are able to fix the button's position by UIScrollView delegate (UITableViewDelegate inherited from this) while TableView is scrolling:
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tableView) {
let originY = scrollView.frame.size.height - self.button.frame.size.height + scrollView.contentOffset.y
self.button.frame = CGRect(x: 0, y: originY, width: scrollView.frame.width, height: self.button.frame.size.height)
}
}
Alternatively, if you want to position the button by AutoLayout, just define a NSLayoutConstraint property, and bind it to button's bottom space constraint to its super view. Then adjust the constraint's constant value by same mechanism in scrollViewDidScroll function.
You can just add an view at the bottom of your tableview.
override func viewDidLoad() {
super.viewDidLoad()
addResultButtonView()
}
private func addResultButtonView() {
let resultButton = UIButton()
resultButton.backgroundColor = .red
resultButton.setTitle("Hello", for: .normal)
tableView.addSubview(resultButton)
// set position
resultButton.translatesAutoresizingMaskIntoConstraints = false
resultButton.leftAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.leftAnchor).isActive = true
resultButton.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor).isActive = true
resultButton.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor).isActive = true
resultButton.widthAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.widthAnchor).isActive = true
resultButton.heightAnchor.constraint(equalToConstant: 50).isActive = true // specify the height of the view
}

Subclassing and overridding UITableView

I have the following code:
private var table = TableViewController();
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.green;
table = TableViewController(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height));
}
I get an error saying no frame is overloaded? How do I fix this? TableViewController is a class I created. It inherits from UITableView.

How to place a subview in the center of parent view using .center?

I have two subviews: the purple one belongs to a main view and it works wonderful with the syntax:
sSubview.center = view.center
The orange one belongs to the purple view and the same syntax doesn't place it correctly in the center.
Could you see where my mistake is?
Here is my code:
import UIKit
class ViewController: UIViewController {
var sSubview = UIView()
var sLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor.lightGray
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLayoutSubviews() {
createSimplestSubview()
}
// First subview
func createSimplestSubview() {
sSubview = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width * 0.9, height: view.frame.height * 0.9))
sSubview.backgroundColor = UIColor.purple // just for test, to make it visible
sSubview.center = view.center // that s pretty easy!
view.addSubview(sSubview)
createSimplestLabel()
}
// Second subview
func createSimplestLabel() {
sLabel = UILabel(frame: CGRect(x: 0, y: 0, width: sSubview.frame.width * 0.3, height: sSubview.frame.height * 0.2))
sLabel.backgroundColor = UIColor.orange // just for test, to make it visible
sLabel.center = sSubview.center
sLabel.text = "This label has to be centered!"
sLabel.textAlignment = .center
sLabel.numberOfLines = 0
sSubview.addSubview(sLabel)
}
}
Here is a screen:
Try the next code for seconds subview:
sLabel.center = CGPoint(x: sSubview.frame.width / 2, y: sSubview.frame.height / 2)
You're trying to place a label in the center, but it calculated according to the firstSbuview frame, which origin is not 0.0
A better way is to use convertPoint as the problem with your code is that the coordinate spaces are sometimes different.
sSubview.center = view.superview.convert(view.center, to: sSubview.superview)
view.center is in the coordinate space of view.superview
sSubview.center is in the coordinate space of sSubview.superview

Pull to Refresh plug-in : PullToBounce Wrapper UIScrollView

I am trying to use this plugin as refresh action : https://github.com/entotsu/PullToBounce
One, issue is I can't understand his explanation.
Explanation given on the github
tableView.frame = yourFrame --> tableView is equal to scrollView.frame in my situation
yourFrame --> I have no idea what it is. The main frame ? Another Frame I have to create ?
bodyView.addSubview(tableViewWrapper) --> bodyView ? Main Frame here ? or Another frame ?
Here is my code for the scrollView for now. Any help on how to implement this plugin using a scrollView made via the storyboard.
class ProfileViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
func makeMock() {
let headerView = UIView()
headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 64)
headerView.backgroundColor = UIColor.lightBlue
self.view.addSubview(headerView)
let headerLine = UIView()
headerLine.frame = CGRect(x: 0, y: 0, width: 120, height: 8)
headerLine.layer.cornerRadius = headerLine.frame.height/2
headerLine.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.8)
headerLine.center = CGPoint(x: headerView.frame.center.x, y: 20 + 44/2)
headerView.addSubview(headerLine)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
let bodyView = UIView()
bodyView.frame = scrollView.frame
bodyView.frame.y += 20 + 44
self.view.addSubview(bodyView)
let tableViewWrapper = PullToBounceWrapper(scrollView: scrollView)
bodyView.addSubview(tableViewWrapper)
tableViewWrapper.didPullToRefresh = {
NSTimer.schedule(delay: 2) { timer in
tableViewWrapper.stopLoadingAnimation()
}
}
makeMock()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
One thing, I notice is that there is a View on top of my scrollView that disable me to view it and scroll it. Help here needed please.
Regards,
Hary
Take a look at the Example of this library.
yourFrame is nothing but your tableview class. For example if your tableView Class is named SampleTableView, then it goes like
let tableView = SampleTableView(frame: self.view.frame, style: UITableViewStyle.Plain).
You have to use another class to set up your tableView.

Resources