Variables is nil in awakeFromNib - ios

I created a custom UIView that I instantiate with an object ConnectDetailItem.
Code of my custom view :
class InfosConnectView: UIView {
var view: UIView!
#IBOutlet weak var categorie: UILabel!
#IBOutlet weak var distance: UILabel!
#IBOutlet weak var followers: UILabel!
#IBOutlet weak var descriptionTextView: UITextView!
var connectDetailsItem:ConnectDetailsItem!
convenience init(connectDetailsItem:ConnectDetailsItem, frame:CGRect) {
self.init(frame: frame)
self.connectDetailsItem = connectDetailsItem
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
view.layer.borderWidth = 1
view.layer.borderColor = UIColor(hex: "#DDDDDD").cgColor
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "viewInfosConnect", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
override func awakeFromNib() {
super.awakeFromNib()
//Infos Connect
self.categorie.text = "\(self.connectDetailsItem.category)"
self.categorie.text = "\(self.connectDetailsItem.category)"
if (self.connectDetailsItem.distance < 1000) {
self.distance.text = "\(self.connectDetailsItem.distance) m"
} else {
let distance:NSString = NSString(format: "%.01f", Float(self.connectDetailsItem.distance)/1000)
self.distance.text = "\(distance) km"
}
if(self.connectDetailsItem.followCount < 2) {
if(self.connectDetailsItem.followCount < 1) {
self.followers.text = "0 abonné"
} else {
self.followers.text = "\(self.connectDetailsItem.followCount) abonné"
}
} else {
self.followers.text = "\(self.connectDetailsItem.followCount) abonnés"
}
self.descriptionTextView.text = self.connectDetailsItem.description
}
}
In awakeFromNib(), connectDetailItem is nil. Why ?
I instanciate my view like this : let viewInfos = InfosConnectView(connectDetailsItem: self.connectDetailsItem, frame: CGRect(x: 0, y: 9, width: self.view.frame.width, height: 200))
I set breakpoints and before entering the awakeFromNib function connectDetailItem is not nil.

I have found the solution.
I put the code in the function loadViewFromNib like this :
func loadViewFromNib() -> InfosConnectView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "viewInfosConnect", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! InfosConnectView
//Infos Connect
view.categorie.text = "\(self.connectDetailsItem.category)"
if (self.connectDetailsItem.distance < 1000) {
view.distance.text = "\(self.connectDetailsItem.distance) m"
} else {
let distance:NSString = NSString(format: "%.01f", Float(self.connectDetailsItem.distance)/1000)
view.distance.text = "\(distance) km"
}
if(self.connectDetailsItem.followCount < 2) {
if(self.connectDetailsItem.followCount < 1) {
view.followers.text = "0 abonné"
} else {
view.followers.text = "\(self.connectDetailsItem.followCount) abonné"
}
} else {
view.followers.text = "\(self.connectDetailsItem.followCount) abonnés"
}
view.descriptionTextView.text = self.connectDetailsItem.description
return view
}

Related

Adjust popOverViewController to the size of the label.text

So i have a popover yet i cant manage to configure the right size:
So this is the popover class:
final class PopOverViewController: UIViewController {
#IBOutlet weak var lbl: UILabel!
var text: String?
init(text: String) {
super.init(nibName: "PopOverViewController", bundle: nil)
self.text = text
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
lbl.text = text
//lbl.sizeToFit()
// self.view.frame = lbl.frame
}
}
The label is align to x and y center.
The invoke is :
fileprivate func showTipIfNedded() {
let optionItemListVC = PopOverViewController(text: "qewlghsflgha;lgh;lkfgj")
optionItemListVC.modalPresentationStyle = .popover
optionItemListVC.view.backgroundColor = .red
if let popover = optionItemListVC.popoverPresentationController {
popover.sourceView = self.view
popover.permittedArrowDirections = .down
//popover.containerView?.backgroundColor = .red
guard let firstTab = tabBarController?.tabBar.items?[0].value(forKey: "view") as? UIView else { return }
popover.sourceRect = CGRect(x: firstTab.frame.midX, y: (self.tabBarController?.tabBar.frame.minY)!, width: 1, height: 1)
optionItemListVC.preferredContentSize = CGSize(width: optionItemListVC.lbl.frame.width, height: optionItemListVC.lbl.frame.height)
popover.delegate = self
}
self.present(optionItemListVC, animated: true, completion: nil)
}
With the current constraint the vc is small an i cant see the whole text, with constraint thet are 50 to all side the vc is to big, more then needed.
What constraints must i build? and are there more things i should config?
In your PopoverViewController override preferredContentSize to control the size of the view controller, something like this:
import UIKit
class PopoverViewController: UIViewController
{
#IBOutlet weak var lbl: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
...
}
// Preferred content size
override var preferredContentSize: CGSize
{
get
{
// measure
let maxLabel: CGSize = CGSize.init(width: lbl.frame.size.width, height: CGFloat.greatestFiniteMagnitude)
let fittingSize: CGSize = lbl.sizeThatFits(maxLabel)
// add some margins/padding, margins = 8 horizontal = 12 vertical
return CGSize.init(width: fittingSize.width + 16, height: fittingSize.height + 24)
}
set
{
super.preferredContentSize = newValue
}
}
}
The getter measures the size of the UILabel (assuming its already populated with text), adding some vertical and horizontal padding

Not able to show border color and background as blur in custom view as popup view in Swift

I have some requirement to show popup as some customisation options.
So, I took custom view as UIView with Xib file.
class CustomAlertView : UIView {
#IBOutlet weak var customAlertView : UIView!
#IBOutlet weak var button1 : UIButton!
#IBOutlet weak var button2 : UIButton!
override init(frame: CGRect) { // for using CustomView in code
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) { // for using CustomView in IB
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("CustomAlertView", owner: self)
guard let content = customAlertView else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
}
And given outlet connections.
And I am able to load the view in viewcontroller class.
But, the issue is, its not showing as pop up view and its not showing any border color, etc even I added too.
And the present self.view (Main view from viewcontroller) still moving it has tableview, while I clicking on the buttons on custom view, nothing happening.
func someAction() {
self.view.addSubview(customAlert)
self.customAlert.layer.cornerRadius = 13
self.customAlert.layer.borderWidth = 10
self.customAlert.layer.borderColor = UIColor.gray.cgColor
self.customAlert.clipsToBounds = false
let radius: CGFloat = self.customAlert.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: self.customAlert.frame.height))
self.customAlert.layer.masksToBounds = false
self.customAlert.layer.cornerRadius = 8; // if you like rounded corners
self.customAlert.layer.shadowOffset = CGSize(width:-15, height:20);
self.customAlert.layer.shadowRadius = 5;
self.customAlert.layer.shadowOpacity = 0.5;
self.customAlert.layer.shadowPath = shadowPath.cgPath
self.customAlert.byMonthlyBtn.addTarget(self, action: #selector(button1tapped), for: .touchUpInside)
self.customAlert.byAnnuallyBtn.addTarget(self, action: #selector(button2tapped), for: .touchUpInside)
}
And its looks like below screenshot
Any suggestions?
private func commonInit() {
Bundle.main.loadNibNamed("CustomAlertView", owner: self)
guard let content = customAlertView else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
Your problem is you are using the CustomAlertView you loaded. Try adjust your code like below.
private func commonInit() {
guard let view = Bundle.main.loadNibNamed("CustomAlertView", owner: self)?.first as? CustomAlertView else {
return
}
view.frame = bounds
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(view)
}

Add view from XIB to custom UINavigationBar subclass

I followed this code to create a taller UINavigationBar:
var heightIncrease: CGFloat = 38.0
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.transform = CGAffineTransformMakeTranslation(0, -heightIncrease)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func sizeThatFits(size: CGSize) -> CGSize {
var newSize = super.sizeThatFits(size)
newSize.height += heightIncrease
return newSize
}
override func layoutSubviews() {
super.layoutSubviews()
for view in self.subviews {
if (NSStringFromClass(view.classForCoder).containsString("UINavigationBarBackground")) {
view.frame.origin.y = self.bounds.origin.y + heightIncrease - statusBarHeight
view.frame.size.height = self.bounds.size.height + statusBarHeight
}
}
}
var statusBarHeight: CGFloat {
return UIApplication.sharedApplication().statusBarFrame.size.height
}
Now I want to add a view from an XIB to that bottom part. My first thought was to do something like this:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.transform = CGAffineTransformMakeTranslation(0, -heightIncrease)
if let accessoryView = NSBundle.mainBundle()
.loadNibNamed("NavBarAccessoryView", owner: self, options: nil)
.first as? NavBarAccessoryView {
accessoryView.frame.size.width = self.bounds.size.width
accessoryView.frame.origin.y = 75
self.addSubview(accessoryView)
}
}
It looks ok, but I can't select a segment in the segmented control, it's as if it were just a picture:
Is there a better way to do this? I'm sorry if it's a silly question or if my attempt makes no sense, I'm new at this and so far I've only dealt with views and stuff from the interface builder.
i write extension :
extension UIView {
static func instanceFromNibByClassName() -> UIView {
let nibName = stringFromClass(self as AnyClass)
return NSBundle.mainBundle().loadNibNamed(nibName, owner: nil, options: nil).first! as! UIView
}
}
so i can get instance like this:
var coverTableViewCell=YQEventCoverTableViewCell.instanceFromNibByClassName() as! YQEventCoverTableViewCell

iOS custom view doesn't show image immediately

I made a simple custom view in Swift which has a background image view with a photo and some labels in front. I then added the custom view to my storyboard and it displays well, I can see the background image and labels.
But when I run my app on my device the image view doesn't show immediately, if I navigate to another view then back, it is displayed. I only have a timer which scheduled some tasks in background in my scene. Did I miss anything here?
Here is the code of my custom view
import UIKit
#IBDesignable class GaugeView: UIImageView {
#IBOutlet weak var speedLabel: UILabel!
let circlePathLayer = CAShapeLayer()
var circleRadius: CGFloat = 50.0
var speed: CGFloat {
get {
return circlePathLayer.strokeEnd
}
set {
speedLabel.text = String(format: "%.2f", newValue)
if newValue < 20.0 {
circlePathLayer.strokeColor = UIColor.blueColor().CGColor
} else if newValue >= 25.0 {
circlePathLayer.strokeColor = UIColor.redColor().CGColor
} else {
circlePathLayer.strokeColor = UIColor.yellowColor().CGColor
}
if (newValue > 50) {
circlePathLayer.strokeEnd = 1
} else if (newValue < 0) {
circlePathLayer.strokeEnd = 0
} else {
circlePathLayer.strokeEnd = newValue / 49.9
}
}
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
override func layoutSubviews() {
super.layoutSubviews()
circleRadius = bounds.width / 2 - 2.6
circlePathLayer.frame = bounds
circlePathLayer.path = circlePath().CGPath
}
// Our custom view from the XIB file
var view: UIView!
let nibName = "GaugeView"
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
// Configure speed circle layer
configure()
}
func configure() {
speed = 0.0
circlePathLayer.frame = bounds
circlePathLayer.lineWidth = 6
circlePathLayer.fillColor = UIColor.clearColor().CGColor
circlePathLayer.strokeColor = UIColor.blueColor().CGColor
layer.addSublayer(circlePathLayer)
backgroundColor = UIColor.whiteColor()
}
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
circleFrame.origin.x = CGRectGetMidX(circlePathLayer.bounds) - CGRectGetMidX(circleFrame)
circleFrame.origin.y = CGRectGetMidY(circlePathLayer.bounds) - CGRectGetMidY(circleFrame)
return circleFrame
}
func circlePath() -> UIBezierPath {
let center: CGPoint = CGPointMake(CGRectGetMidX(circlePathLayer.bounds), CGRectGetMidY(circlePathLayer.bounds))
let start = CGFloat(1.33 * M_PI_2)
let end = CGFloat( 1.64 * M_2_PI)
return UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: start, endAngle: end, clockwise: true)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Then I added the custom view to my storyboard and navigate to the scene programatically with performSegueWithIdentifier("dashboardSegue", sender: nil). I just noticed not only the custome view, but two progress bar on the scene are not displayed as well.
It's better show your code, but i am guessing your timer stuck the main UI thread. When you navigate to another view, your timer.invalidate() was called. Try to remove the NSTimer to see if it works well.

UIPageControl custom class - found nil changing image to the dots

I need to implement a UIPageControl with custom images instead the normal dot. So I create a custom class and connect it through the storyboard.
Since ios7 the subview of UIPageControl contain UIView instead of UIImageView. The subviews of the resulting UIView(UIIpageControl subviews) doesn't contain any subviews so I receive the error:
fatal error: unexpectedly found nil while unwrapping an Optional value.
Where I might have been wrong?
class WhitePageControl:UIPageControl{
let activeImage = UIImage(named: "dot_white")
let inactiveImage = UIImage(named: "dot_white_e")
override init(frame: CGRect){
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
}
func updateDots(){
println(self.subviews.count) // 3
println(self.numberOfPages) // 3
for var index = 0; index < self.subviews.count; index++ {
println(index)
var dot:UIImageView!
var dotView:UIView = self.subviews[index] as UIView
println("1")
for subview in dotView.subviews{ // NIL HERE
println("2")
if subview.isKindOfClass(UIImageView){
println("3")
dot = subview as UIImageView
if index == self.currentPage{ dot.image = activeImage }
else{ dot.image = inactiveImage }
}
}
}
}
func setCurrentPage(value:Int){
super.currentPage = value
self.updateDots()
}
}
It's my solution:
import Foundation
class PageControl: UIPageControl {
var activeImage: UIImage!
var inactiveImage: UIImage!
override var currentPage: Int {
//willSet {
didSet { //so updates will take place after page changed
self.updateDots()
}
}
convenience init(activeImage: UIImage, inactiveImage: UIImage) {
self.init()
self.activeImage = activeImage
self.inactiveImage = inactiveImage
self.pageIndicatorTintColor = UIColor.clearColor()
self.currentPageIndicatorTintColor = UIColor.clearColor()
}
func updateDots() {
for var i = 0; i < count(subviews); i++ {
var view: UIView = subviews[i] as! UIView
if count(view.subviews) == 0 {
self.addImageViewOnDotView(view, imageSize: activeImage.size)
}
var imageView: UIImageView = view.subviews.first as! UIImageView
imageView.image = self.currentPage == i ? activeImage : inactiveImage
}
}
// MARK: - Private
func addImageViewOnDotView(view: UIView, imageSize: CGSize) {
var frame = view.frame
frame.origin = CGPointZero
frame.size = imageSize
var imageView = UIImageView(frame: frame)
imageView.contentMode = UIViewContentMode.Center
view.addSubview(imageView)
}
}
change setCurrentPage to Current Page ,bcoz that one is Obj C property
func currentPage(page: Int) {
super.currentPage = page
self.updateDots()
}
try this.

Resources