I am loading a view which I created inside the interface builder like this:
let contentView = Bundle.main.loadNibnamed("ContentView", owner: nil, options: nil)?.first as! ContentView
The view contains an UIImageView and a UIButton. Both of them are connected with IBOutlets to the ContentView class file.
Now when I am loading the view I am setting the UIImageView's image which works fine. I am also trying to change the UIButton's text and backgroundColor but both won't change. Interestingly the button doesn't keep the color I set in the interface builder but the Text.
The code I am using to change the text and the color:
contentView.contentButton.backgroundColor = .red
contentView.contentButton.titleLabel?.text = "someText"
Thanks for the help.
ContentView.swift
class ContentView: UIView {
#IBOutlet weak var mainImageView: UIImageView!
#IBOutlet weak var contentImageView: UIImageView!
#IBOutlet weak var contentButton: UIButton!
}
The code I am using to create the views:
ContentScrollViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<imageArray.count {
let xPosition = Int(self.view.frame.width) * i
let contentView: ContentView = Bundle.main.loadNibNamed("ContentView", owner: nil, options: nil)?.first as! ContentView
contentView.frame.origin = CGPoint(x: xPosition, y: -Int((self.navigationController?.navigationBar.frame.height)!))
contentView.mainImageView.contentMode = .scaleAspectFill
contentView.contentImageView.image = #imageLiteral(resourceName: "stoerer_png_neu")
//Not working
contentView.specialButton.backgroundColor = .red
if let url = URL(string: imageArray[i]) {
contentView.mainImageView.af_setImage(withURL: url)
}
mainScrollView.contentSize.width = mainScrollView.frame.width * CGFloat(i + 1)
mainScrollView.addSubview(contentView)
}
}
You have to use
contentView.contentButton.setTitle("someText", for: .normal)
and
contentView.contentButton.setTitleColor(.red, for: .normal)
because you need to set those attributes for a specific UIControlState
For the background you need to use the layer:
contentView.contentButton.layer.backgroundColor = UIColor.red.cgColor
After restarting all files connected to the problem I finally managed to find the issue. Somehow the constraints of the UIButton in .xib were responsible for the issue. So if you are experiencing the same please check your constraints. :]
Related
#IBOutlet weak var result: UILabel!
#IBOutlet weak var testview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
testview.layer.shadowColor = UIColor.systemGray.cgColor
testview.layer.shadowOpacity = 0.6
testview.layer.shadowOffset = .zero
testview.layer.shadowRadius = 5
testview.layer.shadowPath = UIBezierPath(rect: testview.bounds).cgPath
testview.layer.shouldRasterize = true
testview.layer.rasterizationScale = UIScreen.main.scale
testview.addSubview(result)
}
After I add result to testview as a subview it's disappeared.
Your Storyboard already added result into the view hierarchy so when you add it again the frame stays the same but the point of reference changes since the superview is now testView so in your case it's going beyond the visible bounds. If you want the UILabel to be a subview of the testView I'd recommend making that change directly on the Storyboard, creating the UILabel programmatically instead of using Storyboards/IBOutlets or updating the frame of the label after adding it to testView.
Note: I'm pretty new working with iOS UI.
I want to create a custom view that stacks a custom view inside.
So I created the custom UIStackView
class CustomStackView: UIStackView {
func addItem(color:UIColor){
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "RowView", bundle: bundle)
let rowView = RowView();
let view = nib.instantiate(withOwner: rowView, options: nil).first as! UIView
rowView.addSubview(view)
rowView.view.backgroundColor = color;
addArrangedSubview(rowView)
}
}
class RowView :UIView{
#IBOutlet var view: UIView!
override public var intrinsicContentSize: CGSize {
return CGSize(width: view.frame.width,height:view.frame.height)
}
}
in the RowView.xib I created a simple layout for testing:
Simulated Metrics = Freeform
Height = 100
And the ViewController.swift:
class ViewController: UIViewController {
#IBOutlet weak var customStackView: CustomStackView!
#IBOutlet weak var constraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
customStackView.addItem(color: UIColor.red)
customStackView.addItem(color: UIColor.blue)
customStackView.addItem(color: UIColor.green)
}
#IBAction func click(_ sender: Any) {
constraint.constant = -customStackView.frame.height
UIView.animate(withDuration: 4, animations: {
self.view.layoutIfNeeded();
},completion:nil)
}
}
The result:
The first and second item are displayed correctly but the third is higher than expected.
In addition if I click the button (which should hide the Stackview) keep the "extra" height visible:
How can I fix that?
Edit: Tried the #KristijanDelivuk solution adding a trailing view. And didn't work. Adding cyan color to the view I got this result:
override func viewDidLoad() {
super.viewDidLoad()
customStackView.addItem(color: UIColor.red)
customStackView.addItem(color: UIColor.blue)
customStackView.addItem(color: UIColor.green)
let view = UIView();
view.heightAnchor.constraint(equalToConstant: 50).isActive = true;
view.backgroundColor = UIColor.cyan;
customStackView.addArrangedSubview(view)
}
You can try adding an empty UIView as your last element of UIStackView:
So your hierarchy should look something like this:
- STACKVIEW
-- 1ST ADDED CUSTOM VIEW
-- 2ND ADDED CUSTOM VIEW
-- 3RD ADDED CUSTOM VIEW
-- EMPTY UIVIEW
Empty UIView will take all unallocated space from 3rd view and all should be displayed correctly.
For repositioning button after hiding/showing stackview you can create for example "top constraint" and then on tap change top constraint height to (-) stackview.height or (+) stackview.height - This shouldn't be any problem.
Ive made a custom xib that I've used in my storyboard before and i want simply create an instance of the custom view adjust size and then add it as a subview to a uiscrollview. Ive tried using this block of code in the viewdidload func of my view controller
let cardView = CardView(coder: NSCoder())
cardView!.frame.size.width = 100
cardView!.frame.size.height = 100
scrollView.addSubview(cardView!)
but I'm getting this error
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -containsValueForKey: cannot be sent to an abstract object
of class NSCoder: Create a concrete instance!'
EDIT:
this is the code for the swift file connected to CardView.xib
import UIKit
class CardView: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var cornerView: UIView!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("CardView", owner: self, options: nil)
self.addSubview(view)
view.frame = self.bounds
cornerView.layer.cornerRadius = 3
cornerView.layer.masksToBounds = true
view.layer.shadowOffset = CGSizeMake(1, 5);
view.layer.shadowRadius = 2;
view.layer.shadowOpacity = 0.2;
view.layer.masksToBounds = false
}
}
instead of using auto layout i tried simply settings height and width to test adding subviews manually from these 2 lines(also just a heads up i am new to iOS development)
cardView!.frame.size.width = 100
cardView!.frame.size.height = 100
What i have used in case of using custom XIB for view initialization is below.
In the class of the view like for you its CardView the code goes like.
class CardView: UIView {
#IBOutlet weak var cornerView: UIView!
func setupWithSuperView(superView: UIView) {
self.frame.size.width = 100
self.frame.size.height = 100
superView.addSubview(self)
cornerView = UIView(frame: self.bounds)
cornerView.layer.cornerRadius = 3
cornerView.layer.masksToBounds = true
view.layer.shadowOffset = CGSizeMake(1, 5);
view.layer.shadowRadius = 2;
view.layer.shadowOpacity = 0.2;
view.layer.masksToBounds = false
}
}
and where you are calling this class for initialization, use this.
let cardView = NSBundle.mainBundle("CardView").loadNibNamed("", owner: nil, options: nil)[0] as! CardView
cardView.setupWithSuperView(scrollView)
Try this once. But make sure the first view of the xib file is of type CardView. I mean the class of the first view is CardView.
This is part of my code.
I want to show two UILabel and two UITextField on the background image: backgroundLogin.jpg .
import Foundation
import UIKit
class LoginViewController:UIViewController
{
override func viewDidLoad() {
super.viewDidLoad()
let BackGroundImage:UIImageView = UIImageView(frame: CGRectMake(0, 0, self.view.frame.width , self.view.frame.height))
let image: UIImage = UIImage(named: "backgroundLogin.jpg")!
BackGroundImage.image = image
self.view.addSubview(BackGroundImage)
//self.view.backgroundColor = UIColor(patternImage: UIImage(named: "backgroundLogin.jpg")!)
username.text = "User name"
password.text = "Password"
}
#IBOutlet weak var username: UILabel!
#IBOutlet weak var password: UILabel!
}
But when this code runs, it looks like:
I hope it can have two label on the image, but how to add that ?
Well like I stated in the comment you should try bring the UILabels to the front.
Since you are doing this programatically it can be done with bringSubviewToFront here is Apple's documentation on this and other UIView functionality you can use. Note: UILabel inherits from UIView so you can use these methods.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/doc/uid/TP40006816-CH3-SW46
The code:
override func viewDidLoad() {
super.viewDidLoad()
let BackGroundImage:UIImageView = UIImageView(frame: CGRectMake(0, 0, self.view.frame.width , self.view.frame.height))
let image: UIImage = UIImage(named: "backgroundLogin.jpg")!
BackGroundImage.image = image
self.view.addSubview(BackGroundImage)
//self.view.backgroundColor = UIColor(patternImage: UIImage(named: "backgroundLogin.jpg")!)
username.text = "User name"
password.text = "Password"
self.view.bringSubviewToFront(username)
self.view.bringSubviewToFront(password)
}
It seems you are adding the UIImageView in code and the UILabels on storyboard, then when you run the app the labels are behind the UIImageView and you can't see then.
Just check it adding BackGroundImage.hidden = true in viewDidLoad.
You can't add UILabels into a UIImageView. One solution would be add all views in code, 1st the image view and then the labels over it. Other option would be add all then in storyboard in the same order.
Like this:
You’re doing a lot here programmatically that you don’t need to do.
In Storyboard, add a UIImageView to a blank ViewController (you
can rename the view controller later if you wish)
With the new UIImageView selected, control-drag to create an outlet in your view controller named backgroundImage
With the UIImageView selected, choose the image you want it to display by going to the Attribute Inspector and from the dropdown
box, select your image. All images in your project should appear in
the dropdown box.
Now add a UILabel to the ViewController and control-drag to create an outlet in the corresponding code
In the viewDidLoad() method, bring the outlet to the front
All this requires code-wise is:
class ViewController: UIViewController {
#IBOutlet weak var backgroundImage: UIImageView!
#IBOutlet weak var username: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.view.bringSubviewToFront(username)
}
}
I am not sure why this is happening.
In my application, I have
ViewController.swift
CustomUIView.swift
CustomUIView.xib
In my ViewController.swift
var customView: CustomUIView = NSBundle.mainBundle().loadNibNamed("CustomUIView", owner: self, options: nil).first as CustomUIView;
customView.setupControl();
self.view.addSubview(customView);
In my CustomUIView.swift I tried to change the properties of a UIButton created in the CustomUIView.XIB such as this
#IBOutlet weak var button: UILabel!
func setupControl()
{
label.frame = CGRect(x: 0 , y: 30, width: 320, height: 240); //THIS DOES NOT WORK
label.text = "BLABLABLA"; //THIS WORKS
}
I can only modify the property of the UIButton from the InterfaceBuilder.
Any thoughts on why this is happening?
Are you using Auto Layout? If yes, you can't set the frame, because the constraints will override the frame setting. To change the frame, you must set the constraints.