loading a xib view on orientation change in swift - ios

I'm trying to get my keybordview to switch on orientation change - I have my views within my .xib hooked up with #IBOutlet then I call them with loadInterface() inside of viewDidLoad() I was hoping that my call in viewDidLoad would update the interface but I don't think it's working quite how I thought - it doesn't break anything but it doesn't work either (though, I've made tons of progress from last week.).
I have a feeling it's something with the orientation change...
import UIKit
class KeyboardViewController: UIInputViewController {
#IBOutlet var keyboardViewPortrait: UIView!
#IBOutlet var keyboardViewLandscape: UIView!
func loadInterface(){
var keyboardNib = UINib(nibName: "keyboardView", bundle: nil)
UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
if self.interfaceOrientation.isLandscape {
self.keyboardViewLandscape = keyboardNib.instantiateWithOwner(self, options: nil)[0] as UIView
view.addSubview(self.keyboardViewLandscape)
view.backgroundColor = self.keyboardViewLandscape.backgroundColor
}
else if self.interfaceOrientation.isPortrait {
self.keyboardViewPortrait = keyboardNib.instantiateWithOwner(self, options: nil)[0] as UIView
view.addSubview(self.keyboardViewPortrait)
view.backgroundColor = self.keyboardViewPortrait.backgroundColor
}
self.nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)
}
override func viewDidLoad() {
super.viewDidLoad()
UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
loadInterface()
...
}
}
*update
I think rdelmar set me on the right path but something is still missing.
thanks!

The problem is that your assigning the same view to self.keyboardViewLandscape, and self.keyboardViewPortrait (in both cases that's the view you get from keyboardNib.instantiateWithOwner(self, options: nil)[0]). One of those properties should be assigned to the object at index 1. Also, it might be better to use the new method for dealing with rotation, viewWillTransitionToSize:withTransitionCoordinator:. You also need to remove the previous view when you add the new one.
class ViewController: UIViewController {
var keyboardViewPortrait: UIView!
var keyboardViewLandscape: UIView!
var keyboardNib = UINib(nibName: "keyboardView", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
self.keyboardViewPortrait = keyboardNib.instantiateWithOwner(self, options: nil)[0] as UIView
view.addSubview(self.keyboardViewPortrait)
view.backgroundColor = self.keyboardViewPortrait.backgroundColor
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator){
if size.width > size.height {
self.keyboardViewPortrait.removeFromSuperview()
self.keyboardViewLandscape = keyboardNib.instantiateWithOwner(self, options: nil)[1] as UIView
view.addSubview(self.keyboardViewLandscape)
view.backgroundColor = self.keyboardViewLandscape.backgroundColor
}
else {
self.keyboardViewLandscape.removeFromSuperview()
self.keyboardViewPortrait = keyboardNib.instantiateWithOwner(self, options: nil)[0] as UIView
view.addSubview(self.keyboardViewPortrait)
view.backgroundColor = self.keyboardViewPortrait.backgroundColor
}
}
}

Related

Interacting with custom UIView inside view controller

I am created a UIView which I want to display in my view controller. I have created the UIView and it shows with other UI components, but the problems I have now is I con not interact with the elements of the on the UIView.
below is my code
class SliderView: CustomView {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var sliderImage: UIImageView!
#IBOutlet weak var sliderText: UILabel!
override func initialize() {
super.initialize()
let name = String(describing: type(of: self))
let nib = UINib(nibName: name, bundle: .main)
nib.instantiate(withOwner: self, options: nil)
self.addSubview(self.containerView)
self.containerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.containerView.topAnchor.constraint(equalTo: self.topAnchor),
self.containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
])
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return sliderImage.frame.contains(point)
}
#IBAction func clickme(_ sender: UIButton) {
print("SWIPPERD minmax22g")
}
}
in the viewcontroller
weak var sliderView: SliderView!
override func loadView() {
super.loadView()
let sliderView = SliderView()
self.view.addSubview(sliderView)
NSLayoutConstraint.activate([
sliderView.topAnchor.constraint(equalTo: self.view.topAnchor),
sliderView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
sliderView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
self.sliderView = sliderView
}
override func viewDidLoad() {
super.viewDidLoad()
sliderView.sliderText.text = "HOOOOO WORKS"
}
1- You shouldn't add an outlet as a subview again inside the custom view
#IBOutlet weak var containerView: UIView!
self.addSubview(self.containerView)
add this method and use it to get an instance
static func getInstance() -> SliderView {
return Bundle.main.loadNibNamed("SliderView", owner: self, options: nil)![0] as! SliderView
}
2- This will make the imageView the only active frame inside the view
return sliderImage.frame.contains(point)
3- Don 't add the subview inside loadView , add it inside viewDidLoad
let sliderView = SliderView()
to
let sliderView = SliderView.getInstance()

Custom UIView is blank when instantiated from a XIB in Swift 4

I have a custom view that I am trying to load from a custom XIB, but the view appears to be blank when loaded, even thought it has the correct sizes when debugged.
My debug statements show that the frame has the correct sizes:
commonInit()
XIB: MyCustomView
myView Frame: (0.0, 0.0, 320.0,568.0)
myView ContentSize: (320.0, 710.0)
This is my custom VC that I am using to call my Custom View
class MyCustomViewController: UIViewController {
var myView : MyCustomView!
override func viewDidLoad() {
super.viewDidLoad()
myView = MyCustomView(frame: self.view.frame)
self.view.addSubview(myView)
updateScrollViewSize()
print("myView Frame: \(myView.frame)")
print("myView ContentSize: \(myView.contentView.contentSize)")
}
func updateScrollViewSize () {
var contentRect = CGRect.zero
for view in myView.contentView.subviews {
contentRect = contentRect.union(view.frame)
}
myView.contentView.contentSize = CGSize(width: myView.contentView.frame.size.width, height: contentRect.size.height + 5)
}
}
There is a XIB that has the files owner as MyCustomView and all the outlets are hooked up correctly.
class MyCustomView: UIView {
let kCONTENT_XIB_NAME = "MyCustomView"
#IBOutlet var contentView: UIScrollView!
#IBOutlet weak var lbl_datein: UILabel!
//.. A bunch of other GUI elements for the scrollview
#IBOutlet weak var text_location: UITextField!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
print(#function)
print("XIB: \(kCONTENT_XIB_NAME)")
Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
contentView.addSubview(self)
contentView.frame = self.bounds
contentView.backgroundColor = .blue
}
}
Does anyone see what I have done wrong when trying to load the view
I'm going to post an alternative to what you've done, using an extension.
extension UIView {
#discardableResult
func fromNib<T : UIView>(_ nibName: String? = nil) -> T? {
let bundle = Bundle(for: type(of: self))
guard let view = bundle.loadNibNamed(nibName ?? String(describing: type(of: self)), owner: self, options: nil)?[0] as? T else {
return nil
}
view.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(view)
view.autoPinEdgesToSuperviewEdges()
return view
}
}
*Note that I am using PureLayout for convenient autolayout management, you could just apply the constraints manually yourself though if you aren't using PureLayout.
Using the above all you have to do is call the below from your init;
fromNib()
*Final note. The custom view name must match the nib name, otherwise you must pass the nib name in to you fromNib function.
You now have something much more reusable.
If my alternative answer is too much, let me try solve your existing issue. Instead of the below;
Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
contentView.addSubview(self)
Try;
let nibView = Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
self.addSubView(nibView)
I couldn't get this to run copy/pasting the code. Maybe there's some setup missing, but I'm having a hard time understanding how it's supposed to work. The original code in the question crashes on this line:
contentView.addSubview(self)
because when you have IBOutlets, they will always be nil if you initialize it using MyCustomView(frame: self.view.frame). It has to call the initWithCoder function.
There's a lot going on here, but this is how I would do it:
class MyCustomViewController: UIViewController {
var myView: MyCustomView!
override func viewDidLoad() {
super.viewDidLoad()
myView = Bundle.main.loadNibNamed("MyCustomView", owner: self, options: nil)?.first as? MyCustomView
self.view.addSubview(myView)
updateScrollViewSize()
print("myView Frame: \(myView.frame)")
print("myView ContentSize: \(myView.contentView.contentSize)")
}
func updateScrollViewSize () {
var contentRect = CGRect.zero
for view in myView.contentView.subviews {
contentRect = contentRect.union(view.frame)
}
myView.contentView.contentSize = CGSize(width: myView.contentView.frame.size.width, height: contentRect.size.height + 5)
}
}
class MyCustomView: UIView {
let kCONTENT_XIB_NAME = "MyCustomView"
#IBOutlet var contentView: UIScrollView!
#IBOutlet weak var lbl_datein: UILabel!
//.. A bunch of other GUI elements for the scrollview
#IBOutlet weak var text_location: UITextField!
}
I'm assuming that the top-level object in the nib is of class MyCustomView, which is going to lead to a lot of weird things. loadNibNamed will call init?(coder aDecoder: NSCoder), so ideally you'd just be calling that from your view controller in the first place, instead of from the custom view object.
With regards to the "can't add self as subview" error, I did not see that error while running, but I would expect it from this line:
contentView.addSubview(self)
since that's exactly what it does, add self as a subview of a view that's already a subview of self.

Swift Delegate is not being called

I have completed all the needed code for delegate to work. In my viewcontroller:
class ViewController: UIViewControllerCustomViewDelegate
I also have this:
override func viewDidLoad() {
super.viewDidLoad()
let myCustomView = Bundle.main.loadNibNamed("ImageHeaderView", owner: self, options: nil)?[0] as! ImageHeaderView
myCustomView.delegate = self
}
func goToNextScene() {
print("GOTOSCENE2")
}
And in my custom view I have this:
import UIKit
protocol CustomViewDelegate: class { // make this class protocol so you can create `weak` reference
func goToNextScene()
}
#available(iOS 10.0, *)
class ImageHeaderView : UIView {
#IBOutlet weak var followme: UISwitch!
#IBOutlet weak var profileImage : UIImageView!
#IBOutlet weak var backgroundImage : UIImageView!
weak var delegate: CustomViewDelegate?
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor(hex: "E0E0E0")
self.profileImage.layer.cornerRadius = self.profileImage.frame.size.height / 2
self.profileImage.clipsToBounds = true
self.profileImage.layer.borderWidth = 1
self.profileImage.layer.borderColor = UIColor.white.cgColor
//self.profileImage.setRandomDownloadImage(80, height: 80)
//self.backgroundImage.setRandomDownloadImage(Int(self.frame.size.width), height: 100)
}
#IBAction func followme(_ sender: AnyObject) {
UserDefaults.standard.set(followme.isOn, forKey: "followme")
}
#IBAction func logout(_ sender: AnyObject) {
delegate?.goToNextScene()
print("GOTOSCENE")
}
}
There is are no errors thrown but when I click/tap the button, nothing happens. It just prints "GOTOSCENE".
What I feel is
Your problem is right here
override func viewDidLoad() {
super.viewDidLoad()
let myCustomView = Bundle.main.loadNibNamed("ImageHeaderView", owner: self, options: nil)?[0] as! ImageHeaderView
myCustomView.delegate = self
}
I think you have added imageHeaderview from storyboard and in viewdidload you are creating new object of ImageHeaderView and assigning delegate to newly created object.
Try to outlet your ImageHeaderView and assign delegate to outleted object.
Hope this will fix your issue.

Swift: Add a xib into a UIView

I would like to add a custom UIView. The class definition of my custom view is:
class UserCoinView: UIView {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var coinView: UIView!
#IBOutlet weak var coinAmount: UILabel!
#IBOutlet weak var coinIcon: UILabel!
override func drawRect(rect: CGRect) {
let smartCoins = SmartShopperUtil.getSmartShopper().smartCoins
if smartCoins != nil && smartCoins >= 0 {
coinAmount.text = String(smartCoins!)
coinView.backgroundColor = SmartShopperUtil.getSmartCoinBackgroundColor(SmartShopperUtil.getSmartShopper().smartCoins!)
}
userName.text = SmartShopperUtil.getSmartShopperNameWithFullName(SmartShopperUtil.getSmartShopper().name)
coinIcon.text = AEVIcons.AEV_SMART_COIN
}
}
I have added a View in the ViewController I want to add this view, and I have set the custom class of this view as UserCoinView. After that, I have made a connection to the ViewController, and in this ViewController I have no idea what to do in order to display my custom UIView.
Thanks in advance for your help.
There is couple of ways you can do this.
Add as subview programmatically.
If you use autolayout, better place for that is viewDidLayoutSubviews method.
var myCustomView: UserCoinView? // declare variable inside your controller
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if myCustomView == nil { // make it only once
myCustomView = NSBundle.mainBundle().loadNibNamed("UserCoinView", owner: self, options: nil).first as? UserCoinView
myCustomView.frame = ...
self.view.addSubview(myCustomView) // you can omit 'self' here
// if your app support both Portrait and Landscape orientations
// you should add constraints here
}
}
Add as subview in InterfaceBuilder.
You simply need put an empty view to you controller inside the storyboard, and assign your class for this view in Identity Inspector. After that, you can drag-n-drop outlets to your controller classes if you need one.
As for me, I prefer the second method because you don't need to hardcode frame / create constraints programmatically, just add autolayout.
You can try This
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib ()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib ()
}
func loadViewFromNib() {
let view = UINib(nibName: "CreditCardExperyView", bundle: NSBundle(forClass: self.dynamicType)).instantiateWithOwner(self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.addSubview(view);
}
// Call subview
let creditCardView : CreditCardExperyView = CreditCardExperyView(frame: CGRect(x: 0, y: UIScreen.mainScreen().bounds.size.height - 280, width: UIScreen.mainScreen().bounds.size.width, height: 280))
selfView.addSubview(creditCardView)
Add it to a UIViewController's or UITableViewController's content view (or some other view in the view controller's view hierarchy) as a subview.
in Latest swift -> for example:
let headerView = Bundle.main.loadNibNamed("SectionHeaderView", owner:
self, options: nil)?.first as? SectionHeaderView
self.view.addSubview(headerView!)
headerView?.frame = CGRect(x:0, y: 0, width: view.frame.width, height: 50.0)
I'm pretty new myself, but this should work.
Adding:
viewControllerName.addSubview(userCoinView)
Removing:
userCoinView.removeFromSuperview()
You can also use generic function. For project use make it global
struct GenericFunctions {
static func addXIB<T>(xibName: String) -> T? {
return Bundle.main.loadNibNamed(xibName, owner: self, options: nil)?.first as? T
}
}
Use this generic function like:-
if let cell: StudentStatusTableViewCell = GenericFunctions.addXIB(xibName: "StudentStatusTableViewCell") {
return cell
} else {
return UITableViewCell()
}
Benefit of generic is you can use this function for adding View, Tableviewcell and any other element. make sure you are using type in call like let cell: StudentStatusTableViewCell otherwise compiler won't infer the type.
Happy coding :)

Create a PopUp in Swift using a custom UIView

I am trying to create a custom UIView and display it as a pop up in my main View using Swift.
My Custom UIView code is
class DatePopUpView: UIView {
var uiView:UIView?
override init() {
super.init()
self.uiView = NSBundle.mainBundle().loadNibNamed("DatePopUpView", owner: self, options: nil)[0] as? UIView
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
required override init(frame: CGRect) {
super.init(frame: frame)
}
}
And I am Calling it in my main view as:
#IBAction func date_button_pressed (sender : AnyObject?) {
var popUpView = DatePopUpView()
var centre : CGPoint = CGPoint(x: self.view.center.x, y: self.view.center.y)
popUpView.center = centre
popUpView.layer.cornerRadius = 10.0
let trans = CGAffineTransformScale(popUpView.transform, 0.01, 0.01)
popUpView.transform = trans
self.view .addSubview(popUpView)
UIView .animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
popUpView.transform = CGAffineTransformScale(popUpView.transform, 100.0, 100.0)
}, completion: {
(value: Bool) in
})
}
But popUp is not Coming. I used breakpoint and noticed that value is getting assigned to my popUpView but still it is not displayed on my main View. Please Help
Please Note: I am using StoryBoard for my mainView and custom View i have made using xib.
Without additional description on what you are attempting to do, may I suggest something like the code below? Basically, you can use .hidden feature of a view (or any other control) to show/hide the view. You can set the size and positioning of the view to be popped by using the layout editor.
import UIKit
class ViewController: UIViewController {
var popped = false
var popupBtnTitle = "Show Popup"
#IBAction func popupButton(sender: UIButton) {
popped = !popped
anotherView.hidden = !popped
popupBtnTitle = popped ? "Hide Popup" : "Show Popup"
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
}
#IBOutlet weak var popupButtonOutlet: UIButton!
#IBOutlet weak var anotherView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
popped = false
anotherView.hidden = !popped
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Resources