I need to put my tab bar at the top of the screen.
I've tried and I did, this is the code:
override func viewDidLoad() {
self.tabBar.frame = CGRectMake(0, 90, self.view.bounds.size.width, self.view.bounds.size.height);
self.tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth
}
the problem is I when I turn the screen of my device.
I should regenerate the layout and change in this way:
self.tabBar.frame = CGRectMake(0, 80, self.view.bounds.size.width, self.view.bounds.size.height);
How can I change this every time you turn the screen?
EDIT:
New Code:
override func viewDidLayoutSubviews()
{
//check tabBar not null
if (self.tabBar != nil)
{
//make changes in frame here according to orientation if any
self.tabBar.frame = CGRect(x: 00, y: 20, width:self.view.bounds.size.width, height: 49)
}
}
override func viewDidLoad()
{
//Make changes in frame according to your requirement
self.tabBar.frame = CGRectMake(0, 20, self.view.bounds.size.width,49);
//resizing here
self.tabBar.autoresizingMask = UIViewAutoresizing.FlexibleTopMargin;UIViewAutoresizing.FlexibleLeftMargin;UIViewAutoresizing.FlexibleWidth;UIViewAutoresizing.FlexibleRightMargin;
}
Define UITabBar in viewDidLoad
override func viewDidLoad()
{
//Make changes in frame according to your requirement
self.tabBar.frame = CGRectMake(0, 20, self.view.bounds.size.width,49);
//resizing here
self.tabBar.autoresizingMask = UIViewAutoresizing.FlexibleTopMargin;UIViewAutoresizing.FlexibleLeftMargin;UIViewAutoresizing.FlexibleWidth;UIViewAutoresizing.FlexibleRightMargin;
}
Add below method viewDidLayoutSubviews
override func viewDidLayoutSubviews()
{
//check tabBar not null
if (self.tabBar != nil)
{
//make changes in frame here according to orientation if any
self.tabBar.frame = CGRect(x: 00, y: 20, width:self.view.bounds.size.width, height: 49)
}
}
Related
I'm getting problem in size while adding child view controller
XIB veiw :
class StoreDetailView: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
func addChild(vc: UIViewController){
let v = StoreDetailView(nibName: "StoreDetailView", bundle: nil)
v.view.frame = CGRect(x: 0, y: 0, width: vc.view.frame.width, height: 80)
appendAbleView.addSubview(v.view)
vc.addChild(v)
heightOfAppendAbleView.constant = 80
_scrollView.updateContentView()
}
Output what i'm getting:
Height is not working here :
v.view.frame = CGRect(x: 0, y: 0, width: vc.view.frame.width, height: 80)
i need to show it in grey view which height 80 heightOfAppendAbleView.constant = 80
Only addChild is not enough. Let's try this extension
extension UIViewController {
// Add a child view controller, its whole view is embeded in the containerView
public func addController(controller: UIViewController, containerView: UIView) {
if let parent = controller.parent, parent == self {
return
}
addChild(controller)
controller.view.frame = CGRect.init(origin: .zero, size: containerView.frame.size)
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.addSubview(controller.view)
controller.didMove(toParent: self)
}
}
I am trying to place a textview just above the keyboard. The keyboard has two views - one default view and one custom view. A button is there to toggle between these two keyboards.
I am trying to use the following code to position the textview just above the keyboard. But it is behaving very weirdly. The keyboardWillShow notification is not getting called all the times.
Note: I wanted it to support for both portrait and landscape.
class ViewController: UIViewController {
let textView = UITextView()
let button = UIButton()
var keyboardHeight: CGFloat = 0
var keyboardView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
textView.backgroundColor = .lightGray
button.backgroundColor = .red
self.view.addSubview(textView)
self.view.addSubview(button)
}
#objc func buttonAction() {
if self.textView.inputView == nil {
self.textView.inputView = keyboardView
self.textView.inputView?.autoresizingMask = .flexibleHeight
self.textView.reloadInputViews()
textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.textView.inputView!.frame.size.height - 50, width: self.view.frame.size.width - 50, height: 50)
button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.textView.inputView!.frame.size.height - 50, width: 50, height: 50)
} else {
self.textView.inputView = nil
self.textView.reloadInputViews()
textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
}
#objc func keyboardWillShow(notification: Notification) {
if let userInfo = notification.userInfo {
if let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.keyboardHeight = keyboardFrame.size.height
textView.frame = CGRect(x: 0, y: self.view.frame.size.height - self.keyboardHeight - 50, width: self.view.frame.size.width - 50, height: 50)
button.frame = CGRect(x: self.view.frame.size.width - 50, y: self.view.frame.size.height - self.keyboardHeight - 50, width: 50, height: 50)
}
}
}
}
If you wanna get the height of Keyboard when keyboard frame changes because of you toggling between custom keyboard and system keyboard, you can achieve it many ways.
I personally dont prefer notifications they always end up giving me a discrete values, though most of the realtime cases they are good enough when you need to modify the UI as keyboard frame changes in real time (Like try dismissing keyboard on scrolling tableView like whats app where keyboard would go down with your finger as u move and u need to align views in realtime when keyboards scrolls down)
Anyway I believe the approach explained below should also help u to get accurate keyboard height when toggled
Step 1:
Create a subclass of UIView which we will be adding as input accessory view to textView/textField later
protocol KeyBoardObserverProtocol : NSObjectProtocol {
func keyboardFrameChanged(frame : CGRect)
}
class KeyboardObserverAccessoryView: UIView {
weak var keyboardDelegate:KeyBoardObserverProtocol? = nil
private var kvoContext: UInt8 = 1
override func willMove(toSuperview newSuperview: UIView?) {
if newSuperview == nil {
self.superview?.removeObserver(self, forKeyPath: "center")
}
else{
newSuperview?.addObserver(self, forKeyPath: "center", options: [NSKeyValueObservingOptions.new, NSKeyValueObservingOptions.initial], context: &kvoContext)
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let theChange = change as [NSKeyValueChangeKey : AnyObject]?{
if theChange[NSKeyValueChangeKey.newKey] != nil{
if self.keyboardDelegate != nil && self.superview?.frame != nil {
self.keyboardDelegate?.keyboardFrameChanged(frame: (self.superview?.frame)!)
}
}
}
}
}
Though code looks big and messy whats inside is pretty easy to understand. All it does is it start obseving the parent view frame using KVO once it receives the call willMove(toSuperview newSuperview: UIView?) because thats when you know ur view is moved to parent and u know that now u need to monitor the parent's frame.
And every time your KVO triggers the new value u inform it to the interred party using the delegate
How to use it?
keyBoardObserverAccessoryView = KeyboardObserverAccessoryView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
keyBoardObserverAccessoryView.keyboardDelegate = self
self.textView.inputAccessoryView = keyBoardObserverAccessoryView
Thats it :) Now if you wanna provide your custom input accessory view in future just make sure u extend from KeyboardObserverAccessoryView n enjoy the benefits
Hope it helps :)
I am using this code in Xcode 9, iOS 11.
var boolName: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if boolName == true {
self.designTextField()
self.view.layoutIfNeeded()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if boolName == false {
self.designTextField()
boolName = true
}
self.view.layoutIfNeeded()
}
func designTextField() {
//Set the horizontal line in bottom of text field
nameLayer.frame = CGRect(x: 0, y: self.tfName.bounds.size.height, width: self.tfName.bounds.size.width, height: 1)
nameLayer.backgroundColor = UIColor.lightGray.cgColor
tfName.layer.addSublayer(nameLayer)
//Set the horizontal line in bottom of text field
phoneLayer.frame = CGRect(x: 0, y: self.tfPhone.bounds.size.height, width: self.tfPhone.bounds.size.width, height: 1)
phoneLayer.backgroundColor = UIColor.lightGray.cgColor
tfPhone.layer.addSublayer(phoneLayer)
//Set the horizontal line in bottom of text field
emailLayer.frame = CGRect(x: 0, y: self.tfEmail.bounds.size.height, width: self.tfEmail.bounds.size.width, height: 1)
emailLayer.backgroundColor = UIColor.lightGray.cgColor
tfEmail.layer.addSublayer(emailLayer)
}
When using that code and testing in iPad. And the issue is when i rotate the iPad in Landscape Mode, then the horizontal line of text fields(in bottom) are conflicting.
Can somebody plzz help ?
Case if boolName == false stops the redrawing on landscape mode, remove it. And in method designTextField, set the line layers' names, then you are able to get and update them.
let kLineName = "nameLine"
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.designTextField()
}
func designTextField()
{
//Set the horizontal line in bottom of text field
if let index = tfName.layer.sublayers?.index(where: { (layer) -> Bool in
return layer.name == kLineName
}) {
//Update line's frame if it's existed.
let nameLayer = tfName.layer.sublayers![index]
nameLayer.frame = CGRect(x: 0, y: self.tfName.bounds.size.height, width: self.tfName.bounds.size.width, height: 1)
}
else{
//Add layer if it's not existed.
nameLayer.frame = CGRect(x: 0, y: self.tfName.bounds.size.height, width: self.tfName.bounds.size.width, height: 1)
nameLayer.backgroundColor = UIColor.lightGray.cgColor
nameLayer.name = kLineName
tfName.layer.addSublayer(nameLayer)
}
//Same to the phoneLayer and emailLayer ......
}
In my tableHeaderView I have a UILabel that is resizing based on its text. With some text it works, with other text it does not.
Not working example: There's no twelve
Working example: Everything there from one to fifteen
Here's the code I use:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.testLabel.preferredMaxLayoutWidth = self.tableView.frame.width - 30.0
self.headerView = self.tableView.tableHeaderView
self.tableView.tableHeaderView = nil
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
guard self.tableView.tableHeaderView == nil else { return }
self.headerView.setNeedsUpdateConstraints()
self.headerView.updateConstraintsIfNeeded()
self.headerView.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: CGFloat.greatestFiniteMagnitude)
var newFrame = self.headerView.frame
self.headerView.setNeedsLayout()
self.headerView.layoutIfNeeded()
let newSize = self.headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
newFrame.size.height = newSize.height
self.tableHeaderHeight = newSize.height
self.headerView.frame = newFrame
self.tableView.tableHeaderView = self.headerView
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = CGFloat(84)
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: height)
}
This code simply inserts space above the titleView. A custom titleView at point (0,0) has ~20 points of space above it. A height >40 starts to run off the navBar.
You can subclass UINavigationBar :
class CustomNavigationBar: UINavigationBar {
override func sizeThatFits(_ size: CGSize) -> CGSize {
let newSize :CGSize = CGSize(width: self.frame.size.width,height: 84)
return newSize
}
}
Then create the navigation controller and use the initialiser to use your custom navigation bar class.
let nav = UINavigationController(navigationBarClass:CustomNavigationBar.self,toolbarClass: nil)
All existing behavior for UINavigationBar is preserved and your custom height is adopted.
OR
Like you already tried :
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let height: CGFloat = 84 //whatever height you want
let bounds = self.navigationController!.navigationBar.bounds
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height + height)
}
OR :
You can try this solution Changing the height of the Navigation bar iOS Swift
you can use a custom view to replace the navigation bar.This is more easy and flexible. hide the navi bar and implement a custom view.
class ViewController : UIViewController {
var navBar: UINavigationBar = UINavigationBar()
override func viewDidLoad() {
super.viewDidLoad()
self.setCustomNavBarView()
}
func setCustomNavBarView() {
self.navBar.frame = CGRect(x: 0, y: 0, width: 350, height: 50) // Set you custom width and Height
self.navBar.backgroundColor = UIColor.gray
self.view.addSubview(navBar)
}
}
A simple tutorial on how to do that:
Hope this helps!!
class ViewController: UIViewController {
var navBar: UINavigationBar = UINavigationBar()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.setCustomNavBarView()
}
`func setCustomNavBarView() {
self.navBar.frame = CGRect(x: 0, y: 0, width: 350, height: 100) // Set you custom width and Height
self.navBar.backgroundColor = UIColor.gray
self.view.addSubview(navBar)
}
`
swift 3 updated code here