How to get correct width for view with content by systemLayoutSizeFittingSize when height gived - ios

I want to calculate view size with autolayout, but it can not get right value. Here is my code
// build views
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let posterView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 100))
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
titleLabel.text = "Title "
titleLabel.font = UIFont.systemFontOfSize(16) // label height = 19.5
view.addSubview(posterView)
view.addSubview(titleLabel)
posterView.snp_makeConstraints { (make) in
make.top.left.right.equalTo(view).offset(0)
make.width.equalTo(posterView.snp_height).multipliedBy(16.0 / 9.0)
}
titleLabel.snp_makeConstraints { (make) in
make.top.equalTo(posterView.snp_bottom).offset(0)
make.left.equalTo(view).offset(0).priority(750)
make.right.equalTo(view).offset(0).priority(750)
make.bottom.equalTo(view.snp_bottom).offset(0)
}
// calculate
view.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint = NSLayoutConstraint(item: view, height: 90+19.5)
view.addConstraint(heightConstraint)
let fittingSize = view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// the fittingSize is (40,109.5), not expect value (160, 109.5)
Please don't tell me how to calculate dynamic height for UITableViewCell. This is a opposite problem from height to width.
Thanks

Related

macOS NSScrollView Not Scrolling Vertically

I am trying to add few views to see if the NSScrollView will scroll vertically but it is not doing anything.
private func configure2() {
var yOffset = 0
let scrollView = NSScrollView(frame: NSRect(x: 0, y: 0, width: 400, height: 900))
scrollView.hasVerticalScroller = true
for _ in 1...20 {
let v = NSView(frame: NSRect(x: 0, y: 0 + yOffset, width: 50, height: 20))
v.wantsLayer = true
v.layer?.backgroundColor = NSColor.red.cgColor
scrollView.addSubview(v)
yOffset += 40
}
scrollView.backgroundColor = NSColor.green
self.addSubview(scrollView)
}
I remember in UIKit I can set the contentSize property of UIScrollView but in macOS I cannot set contentSize.
You need to set either the documentView or contentView of your NSScrollView. Then, you'll add your subviews to that view.
private func configure2() {
var yOffset = 0
let scrollView = NSScrollView(frame: NSRect(x: 0, y: 0, width: 400, height: 900))
let documentView = NSView(frame: .zero)
scrollView.hasVerticalScroller = true
for _ in 1...20 {
let v = NSView(frame: NSRect(x: 0, y: 0 + yOffset, width: 50, height: 20))
v.wantsLayer = true
v.layer?.backgroundColor = NSColor.red.cgColor
documentView.addSubview(v)
yOffset += 40
}
print(yOffset)
documentView.frame = .init(x: 0, y: 0, width: 400, height: yOffset)
scrollView.documentView = documentView
scrollView.backgroundColor = NSColor.green
self.addSubview(scrollView)
}

Reduce gap between left-view and curser in textfield

I am using below code for adding left view in textfield:
func setUI()
{
txtUserCode.leftViewMode = .always
let label = UILabel(frame: CGRect(x: 7, y: 0, width: 18, height: txtUserCode.frame.size.height))
label.text = "#"
txtUserCode.leftView?.frame = CGRect(x: 0, y: 0, width: 18, height: txtUserCode.frame.size.height)
txtUserCode.leftView = label
label.backgroundColor = UIColor.green
txtUserCode.leftView?.backgroundColor = UIColor.red
}
But the problem is there is gap between left view and curser you can see in screen shot.
See there is small gap between curser and the left view, you can see between 'premB' and '#'
Any help or suggestion will be helpful.
Update your code to below.
func setUI()
{
txtUserCode.leftViewMode = .always
let label = UILabel(frame: CGRect(x: 7, y: 0, width: 18, height: txtUserCode.frame.size.height))
label.text = "#"
label.sizeToFit()
label.frame = CGRect(x: 7, y: 0, width: label.frame.size.width, height: txtUserCode.frame.size.height)
txtUserCode.leftView?.frame = CGRect(x: 0, y: 0, width: label.frame.size.width, height: txtUserCode.frame.size.height)
txtUserCode.leftView = label
label.backgroundColor = UIColor.green
txtUserCode.leftView?.backgroundColor = UIColor.red
}
To get the exact size, first make sizeToFit for the label & instead of 18, give the width of the label.
Add below line and try again.
txtUserCode.borderStyle = .none

Swift Add UIView with subviews to titleView

I'd like to customize my navigation bar and insert a UIView with two subviews into the title view of the navigation bar.
Unfortunately the subviews aren't displayed.
Do you have any idea why?
let titleContainer = UIView()
titleContainer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
let searchIcon = UIButton()
searchIcon.setImage(UIImage(named: "search_icon"), for: UIControlState.normal)
searchIcon.layer.frame = CGRect(x: 0, y: (UIScreen.main.bounds.size.height - 28) / 2, width: 28, height: 28)
titleContainer.addSubview(searchIcon)
let titleLabel = UILabel()
titleLabel.frame = CGRect(x: 28, y: UIScreen.main.bounds.size.height, width: UIScreen.main.bounds.size.width-28, height: UIScreen.main.bounds.size.height)
titleLabel.textColor = UIColor(red:255, green:255, blue:255, alpha:1.0)
titleContainer.addSubview(self.titleLabel)
self.navigationItem.titleView = titleContainer
problem and expected solution:
Why did you use height of all the element as UIScreen.main.bounds.size.height? Please try the below code.
P.S. I have changed the color of searchIcon as i didn't have the image and changed the color of text of label and added some text so that it is visible.
let titleContainer = UIView()
titleContainer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 45)
let searchIcon = UIButton()
//searchIcon.setImage(UIImage(named: "search_icon"), for: UIControlState.normal)
searchIcon.backgroundColor = UIColor.red
searchIcon.layer.frame = CGRect(x: 0, y: 8, width: 28, height: 28)
titleContainer.addSubview(searchIcon)
let titleLabel = UILabel()
titleLabel.frame = CGRect(x: 28, y: 8, width: UIScreen.main.bounds.size.width-28, height: 30)
titleLabel.textColor = UIColor.blue//(red:255, green:255, blue:255, alpha:1.0)
titleContainer.addSubview(titleLabel)
titleLabel.text = "Sample Text"
self.navigationItem.titleView = titleContainer
Here is the screenshot of the above code:
Please change the x,y accordingly as per your requirement.
Have you considered making your let bar = UINavigationBar() programmatically and then add it with: self.view.addSubview(bar)?
So you can push all the "UIBarItems" you want..?

AutoLayout for programmatically created uiview element

When i try to create an uiview with loading text and activityindicator, even though it looks centered in iphone 6, it is not centered in iphone 5.
How can i use auto layout for this programatically created UIView ?
I am trying to center this uiview in all screen sizes
boxView = UIView(frame: CGRect(x: TableView.frame.midX - 60, y: TableView.frame.midY - 15, width: 180, height: 50))
boxView.backgroundColor = UIColor.blackColor()
boxView.alpha = 0.5
boxView.layer.cornerRadius = 10
var activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
activityView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
activityView.startAnimating()
var textLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
textLabel.textColor = UIColor.whiteColor()
textLabel.text = "Loading"
boxView.addSubview(activityView)
boxView.addSubview(textLabel)
TableView.addSubview(boxView)
EDIT: I tried this and it seems working good
var bounds: CGRect = UIScreen.mainScreen().bounds
var width:CGFloat = bounds.size.width
var height:CGFloat = bounds.size.height
boxView = UIView(frame: CGRect(x: width/2 - 90, y: height/2 - 100, width: 180, height: 50))

IOS swift expandable view [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I would like to expand an view when I switch a switch to on, and to collapse when I switch the switch to off.
At the same time all the other elements I have in my design have to move down or up.
Here is how the layout looks like when the switches are OFF
And here is how the layout looks like when the switches are ON:
I hope you understand what I am trying to do.
And the question... How do I do that???
It's much easier to do with AutoLayout and inside InterfaceBuilder (with a xib or storyboard), so foremost familiarize yourself with them if needed.
Wrap a container UIView around the UISwitches and make sure to set it to Clip Subviews.
Add a constraint for the container view's height and set it to 0.
Drag that constraint into your class declaration to generate an IBOutlet property.
Drag a new outlet from your UISwitch 'Value Changed' event to the class to generate an IBAction method.
Make sure to implement that method so that when the value changes, based on the change you toggle-animate the height constraint (the IBOutlet)
self.firstHeightConstraint.constant = on ? 200.0 : 0.0
self.view.setNeedsUpdateConstraints()
UIView.animateWithDuration( ...
options:.BeginFromCurrentState,
animations: { self.view.layoutIfNeeded() } ...
)
Using UIView, it's not a good way. You should use UITableView instead of views.
Using TableView, you can add UISwitch with title according to the first image, in UITableView's header and return required number of rows in changed section in TableView on state ON and return the number of rows 0 on state OFF.
Still an issue, please let me know I'll help you.
I know my code isnt the cleanest, but it bothers me when answers tell the questioner its not a good way or do it this way instead. I am offering a solution NOT using table views or constraints:
In your example, you can use tags for each "level" that needs to be moved. So starting with switch 2 and all views below that, you would have a tag for that level (the second hidden collapsable view would have a tag of 2 as well), then switch 3 would have a tag of 3.
For the labels hidden, you are adding them to a subview i call insideView1 or insideView2. The frames of those inside views should have the proper minX, minY and width, but have a height of 0 to start. Also importantly they have layer.masksToBounds = false, so their subviews dont show when their height is 0. We then animate the height changing to the proper height (expanding), as well as all subviews under changing position.
Lastly i made a dictionary to keep track of when a section is expanded so you can use the same function to expand/collapse other areas while one is already expanded.
import UIKit
class ExpandViewController: UIViewController {
var insideView1 = UIView()
var insideView2 = UIView()
var expand = [1:true,2:true]
#objc func expandCollapse(_ sender : UIButton) {
var heightChange = CGFloat(0)
switch sender.tag {
case 1:
heightChange = 90
default:
heightChange = 90
}
var viewsToExpand = [UIView(),insideView1,insideView2]
UIView.animate(withDuration: 1.0) { [self] in
let expandMe = viewsToExpand[sender.tag]
if expand[sender.tag] == true {
expandMe.frame.size.height = heightChange
for v in view.subviews {
if v.tag > sender.tag {
v.center.y += heightChange
}
}
} else {
expandMe.frame.size.height = 0
for v in view.subviews {
if v.tag > sender.tag {
v.center.y -= heightChange
}
}
}
expand[sender.tag] = !expand[sender.tag]!
}
}
override func viewDidLoad() {
super.viewDidLoad()
let switcher1 = UISwitch()
switcher1.tag = 1
switcher1.isOn = false
switcher1.frame = CGRect(x: view.bounds.width - 150, y: 100, width: 40, height: 30)
switcher1.addTarget(self, action: #selector(expandCollapse(_:)), for: .allTouchEvents)
view.addSubview(switcher1)
let switchLabel1 = UILabel()
switchLabel1.tag = 1
switchLabel1.text = "Switch 1"
switchLabel1.frame = CGRect(x: 30, y: 0, width: view.bounds.width, height: 30)
switchLabel1.center.y = switcher1.center.y
view.addSubview(switchLabel1)
let switcher2 = UISwitch()
switcher2.tag = 2
switcher2.isOn = false
switcher2.frame = CGRect(x: view.bounds.width - 150, y: 140, width: 40, height: 30)
switcher2.addTarget(self, action: #selector(expandCollapse(_:)), for: .allTouchEvents)
view.addSubview(switcher2)
let switchLabel2 = UILabel()
switchLabel2.tag = 2
switchLabel2.text = "Switch 2"
switchLabel2.frame = CGRect(x: 30, y: 0, width: view.bounds.width, height: 30)
switchLabel2.center.y = switcher2.center.y
view.addSubview(switchLabel2)
let switcher3 = UISwitch()
switcher3.tag = 3
switcher3.isOn = false
switcher3.frame = CGRect(x: view.bounds.width - 150, y: 180, width: 40, height: 30)
// switcher3.addTarget(self, action: #selector(expandCollapse(_:)), for: .allTouchEvents)
view.addSubview(switcher3)
let switchLabel3 = UILabel()
switchLabel3.tag = 3
switchLabel3.text = "Switch 3"
switchLabel3.frame = CGRect(x: 30, y: 0, width: view.bounds.width, height: 30)
switchLabel3.center.y = switcher3.center.y
view.addSubview(switchLabel3)
insideView1.frame = CGRect(x: 0, y: switcher1.frame.maxY + 5, width: view.bounds.width, height: 0)
insideView1.layer.backgroundColor = UIColor.lightGray.cgColor
insideView1.layer.masksToBounds = true
insideView1.tag = 1
view.addSubview(insideView1)
insideView2.frame = CGRect(x: 0, y: switcher2.frame.maxY + 5, width: view.bounds.width, height: 0)
insideView2.layer.backgroundColor = UIColor.lightGray.cgColor
insideView2.layer.masksToBounds = true
insideView2.tag = 2
view.addSubview(insideView2)
let insideLabel1 = UILabel()
insideLabel1.text = "Label"
insideLabel1.frame = CGRect(x: 60, y: 10, width: view.bounds.width, height: 30)
insideView1.addSubview(insideLabel1)
let insideTextField1 = UITextField()
insideTextField1.frame = CGRect(x: 200, y: 0, width: view.bounds.width - 240, height: 30)
insideTextField1.center.y = insideLabel1.center.y
insideTextField1.layer.backgroundColor = UIColor.white.cgColor
insideView1.addSubview(insideTextField1)
let insideLabel2 = UILabel()
insideLabel2.text = "Label"
insideLabel2.frame = CGRect(x: 60, y: 50, width: view.bounds.width, height: 30)
insideView1.addSubview(insideLabel2)
let insideTextField2 = UITextField()
insideTextField2.frame = CGRect(x: 200, y: 0, width: view.bounds.width - 240, height: 30)
insideTextField2.center.y = insideLabel2.center.y
insideTextField2.layer.backgroundColor = UIColor.white.cgColor
insideView1.addSubview(insideTextField2)
let insideLabel3 = UILabel()
insideLabel3.text = "Label"
insideLabel3.frame = CGRect(x: 60, y: 10, width: view.bounds.width, height: 30)
insideView2.addSubview(insideLabel3)
let insideTextField3 = UITextField()
insideTextField3.frame = CGRect(x: 200, y: 0, width: view.bounds.width - 240, height: 30)
insideTextField3.center.y = insideLabel3.center.y
insideTextField3.layer.backgroundColor = UIColor.white.cgColor
insideView2.addSubview(insideTextField3)
let insideLabel4 = UILabel()
insideLabel4.text = "Label"
insideLabel4.frame = CGRect(x: 60, y: 50, width: view.bounds.width, height: 30)
insideView2.addSubview(insideLabel4)
let insideTextField4 = UITextField()
insideTextField4.frame = CGRect(x: 200, y: 0, width: view.bounds.width - 240, height: 30)
insideTextField4.center.y = insideLabel4.center.y
insideTextField4.layer.backgroundColor = UIColor.white.cgColor
insideView2.addSubview(insideTextField4)
}
}

Resources