Problems setting equal spacing between views in a UIBezierPath - swift

This is my code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let amountOfViews = 3
let difference: CGFloat = 360 / CGFloat(amountOfViews)
for i in 0...amountOfViews - 1{
print((CGFloat(i) * difference))
let view2 = UIView()
view2.translatesAutoresizingMaskIntoConstraints = false
view2.backgroundColor = .red
self.view.addSubview(view2)
NSLayoutConstraint(item: view2, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: view2, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: view2, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 0.09, constant: 0).isActive = true
NSLayoutConstraint(item: view2, attribute: .height, relatedBy: .equal, toItem: self.view, attribute: .height, multiplier: 0.35, constant: 0).isActive = true
let orbit = CAKeyframeAnimation(keyPath: "position")
let circlePath = UIBezierPath(arcCenter: self.view.frame.origin, radius: CGFloat(self.view.frame.height * 0.3), startAngle: CGFloat(i) * difference, endAngle: CGFloat.pi * 2 + CGFloat(i) * difference, clockwise: true)
orbit.path = circlePath.cgPath
orbit.duration = 10
orbit.isAdditive = true
orbit.repeatCount = Float.greatestFiniteMagnitude
orbit.calculationMode = kCAAnimationPaced
orbit.rotationMode = kCAAnimationRotateAuto
view2.layer.add(orbit, forKey: "orbit")
}
}
This is the result:
This is the print:
0.0
120.0
240.0
To me the difference between the views should be correct, however it is not. The views are touching eachother while they should have equal spacing between them. When setting the amountOfViews to 4, this is the result:
That looks weird as well. How can I make it work?

This is an issue of degrees vs radians The UIBezierPath requires angle values in radians. Your i variable is in degrees.
let radians = (CGFloat(i) * difference) / 180 * CGFloat.pi
let circlePath = UIBezierPath(arcCenter: self.view.frame.origin, radius: CGFloat(self.view.frame.height * 0.3), startAngle: radians, endAngle: CGFloat.pi * 2 + radians, clockwise: true)

Related

UIButton extension addSubview not working

Trying to make a UIButton that when long pressed, exposes four subviews (UIButtons - north, east, south & west) that user can then slide finger to and lift for 4 separate actions.
extension UIButton {
func EnablePopOuts (North:Bool = true, nTitle:String, nColor:UIColor = .black, nAction: Selector) {
if North {
let northButton = UIButton(frame: self.frame)
northButton.translatesAutoresizingMaskIntoConstraints = false
let nA = NSLayoutConstraint(item: northButton, attribute: .height
, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0)
let nB = NSLayoutConstraint(item: northButton, attribute: .width
, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
let nC = NSLayoutConstraint(item: northButton, attribute: .bottom
, relatedBy: .equal, toItem: self, attribute: . top, multiplier: 1, constant: 0)
let nD = NSLayoutConstraint(item: northButton, attribute: .leading
, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0)
self.addSubview(northButton)
self.didAddSubview(northButton)
self.addConstraints([nA,nB,nC,nD])
self.bringSubviewToFront(northButton)
northButton.setTitle(nTitle, for: .normal)
northButton.backgroundColor = nColor
northButton.addTarget(Main.self, action: nAction, for: .touchUpInside)
self.layoutIfNeeded()
self.layoutSubviews()
}
}
}
EnablePopOuts runs but the northButton doesn't appear.

Programatically Created Label Within Container View Won't Expand For Text

I have a reusable view class, with the function .addDisapearingView() when added to another view displays the text in the functions parameters. Both the label and its container view are programmatically created. When there's long text in the label, I want the label, and the view to both grow in height. When there's text too long for the label, the label doesn't grow-and the text, subsequently, doesn't clip/go to next line. I'm trying to get the container view to expand programmatically based upon the text.
I've tried an extension that detects when the label is truncated. Using that extension, I used the += operator on the label and view to expand both of them with no luck.
while label.isTruncated {
print("printing while truncating in the while loop")
regView.frame.size.height += 5
label.frame.size.height += 5
}
The interesting thing with that is, I've used that code before, with the addition of adding 5 to the height constraint of the view in the storyboard to expand the size of the label for text, and it worked. That lead me to believe that my problem might reside somewhere in editing the height constraint for the regView.
I've tried countless variations of
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 3
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
label.frame.size.height = regView.frame.size.height
label.sizeToFit()
regView.layoutSubviews()
I've tried changing the frame of the view and label, changing the constaints at the top of the code, and the answers from other questions.
Code:
Truncated Label Extension:
extension UILabel {
var isTruncated: Bool {
guard let labelText = text else {
return false
}
let labelTextSize = (labelText as NSString).boundingRect(
with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: font],
context: nil).size
return labelTextSize.height > bounds.size.height
}
}
View constraint changer:
extension UIView {
func updateConstraint(attribute: NSLayoutAttribute, constant: CGFloat) -> Void {
if let constraint = (self.constraints.filter{$0.firstAttribute == attribute}.first) {
constraint.constant = constant
self.layoutIfNeeded()
}
}
}
Whole function:
func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){
regView.backgroundColor = colorView
regView.alpha = alpha
regView.frame = CGRect(x: toview.bounds.minX, y: toview.bounds.minY, width: toview.frame.size.width, height: height)
toview.addSubview(regView)
regView.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
let guide = toview.safeAreaLayoutGuide
regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
regView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
regView.heightAnchor.constraint(equalToConstant: height).isActive = true
} else {
NSLayoutConstraint(item: regView,
attribute: .top,
relatedBy: .equal,
toItem: toview, attribute: .top,
multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: regView,
attribute: .leading,
relatedBy: .equal, toItem: toview,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: regView, attribute: .trailing,
relatedBy: .equal,
toItem: toview,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: regView, attribute: NSLayoutAttribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
//regView.heightAnchor.constraint(equalToConstant: height).isActive = true
}
let label = UILabel(frame: CGRect(x: regView.frame.origin.x, y: regView.frame.origin.y, width: regView.frame.width, height: height))
label.text = text
label.font = UIFont(name: "Arial", size: 12)
label.textColor = textColor
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 3
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
label.frame.size.height = regView.frame.size.height
label.sizeToFit()
regView.layoutSubviews()
regView.addSubview(label)
print("Label Height: \(label.frame.height)")
print("Reg view height: \(regView.frame.height)")
while label.isTruncated {
print("label is truncated")
regView.frame.size.height += 5
label.frame.size.height += 5
label.updateConstraint(attribute: NSLayoutAttribute.height, constant: regView.frame.height)
label.updateConstraint(attribute: NSLayoutAttribute.width, constant: regView.frame.width)
regView.layoutSubviews()
label.sizeToFit()
print("Label Height: \(label.frame.height)")
print("Reg view height: \(regView.frame.height)")
}
//remove
Timer.scheduledTimer(withTimeInterval: 2.8, repeats: false) { (action) in
UIView.animate(withDuration: 2.8, animations: {
self.regView.removeFromSuperview()
label.removeFromSuperview()
})
}
}
which is called by: ReusableView().addDisapearingView(toview: self.view, text: "Anonymous posts will still show up in your profile page!, more text text to test in teh view that doen't work!", textColor: UIColor.white, colorView: UIColor.darkGray, alpha: 0.9, height: 20)
The interesting thing(That I tried to fix) was that even if the height is set to 40, or a value where two lines of text could fit, the label still doesn't expand/truncate, much less if the height param is 20.
Any help would be greatly appreciated!
I guess you completely need auto-layout and make regView expand according to the label's text without any height constraints
let regView = UIView()
func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){
regView.backgroundColor = colorView
regView.alpha = alpha
toview.addSubview(regView)
regView.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
let guide = toview.safeAreaLayoutGuide
NSLayoutConstraint.activate([
regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
regView.topAnchor.constraint(equalTo: guide.topAnchor),
// regView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
// regView.heightAnchor.constraint(equalToConstant: height).isActive = true
])
} else {
NSLayoutConstraint(item: regView,
attribute: .top,
relatedBy: .equal,
toItem: toview, attribute: .top,
multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: regView,
attribute: .leading,
relatedBy: .equal, toItem: toview,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: regView, attribute: .trailing,
relatedBy: .equal,
toItem: toview,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
// NSLayoutConstraint(item: regView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
//regView.heightAnchor.constraint(equalToConstant: height).isActive = true
}
let label = UILabel()
label.text = text
label.font = UIFont(name: "Arial", size: 12)
label.textColor = textColor
label.numberOfLines = 3
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
regView.addSubview(label)
NSLayoutConstraint.activate([
label.trailingAnchor.constraint(equalTo: regView.trailingAnchor),
label.leadingAnchor.constraint(equalTo: regView.leadingAnchor),
label.topAnchor.constraint(equalTo: regView.topAnchor),
label.bottomAnchor.constraint(equalTo: regView.bottomAnchor) // this is the key behind expanding
])
Timer.scheduledTimer(withTimeInterval:3, repeats: false) { (action) in
UIView.animate(withDuration: 2.8, animations: {
self.regView.removeFromSuperview()
})
}
}
Edit:
let regView = UIView()
func addDisapearingView(toview: UIView, text: String, textColor: UIColor, colorView: UIColor, alpha: CGFloat, height: CGFloat){
regView.backgroundColor = colorView
regView.alpha = alpha
toview.addSubview(regView)
regView.translatesAutoresizingMaskIntoConstraints = false
var topCon:NSLayoutConstraint!
if #available(iOS 11.0, *) {
let guide = toview.safeAreaLayoutGuide
topCon = regView.bottomAnchor.constraint(equalTo: guide.topAnchor)
topCon.isActive = true
NSLayoutConstraint.activate([
regView.trailingAnchor.constraint(equalTo: guide.trailingAnchor),
regView.leadingAnchor.constraint(equalTo: guide.leadingAnchor),
// regView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
// regView.heightAnchor.constraint(equalToConstant: height).isActive = true
])
} else {
topCon = NSLayoutConstraint(item: regView,
attribute: .bottom,
relatedBy: .equal,
toItem: toview, attribute: .top,
multiplier: 1.0, constant: 0)
topCon.isActive = true
NSLayoutConstraint(item: regView,
attribute: .leading,
relatedBy: .equal, toItem: toview,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: regView, attribute: .trailing,
relatedBy: .equal,
toItem: toview,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
// NSLayoutConstraint(item: regView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: .equal, toItem: toview, attribute: .height, multiplier: 1.0, constant: height).isActive = true
//regView.heightAnchor.constraint(equalToConstant: height).isActive = true
}
let label = UILabel()
label.text = text
label.font = UIFont(name: "Arial", size: 12)
label.textColor = textColor
label.numberOfLines = 3
label.lineBreakMode = .byWordWrapping
label.translatesAutoresizingMaskIntoConstraints = false
regView.addSubview(label)
NSLayoutConstraint.activate([
label.trailingAnchor.constraint(equalTo: regView.trailingAnchor),
label.leadingAnchor.constraint(equalTo: regView.leadingAnchor),
label.topAnchor.constraint(equalTo: regView.topAnchor),
label.bottomAnchor.constraint(equalTo: regView.bottomAnchor) // this is the key behind expanding
])
regView.layoutIfNeeded()
topCon.constant += self.regView.frame.height
UIView.animate(withDuration: 2) {
toview.layoutIfNeeded()
}
Timer.scheduledTimer(withTimeInterval:3, repeats: false) { (action) in
UIView.animate(withDuration: 2.8, animations: {
self.regView.removeFromSuperview()
})
}
}

translatesAutoresizingMaskIntoConstraints with Charts LineChartView

I'm using LineChartView from Charts in an osx app and I add it as follows to my view:
let lineChartView = LineChartView(frame: NSRect(x: 0, y: 0, width: 300, height: 200))
let ys1 = Array(1..<10).map { x in return sin(Double(x) / 2.0 / 3.141 * 1.5) }
let ys2 = Array(1..<10).map { x in return cos(Double(x) / 2.0 / 3.141) }
let yse1 = ys1.enumerate().map { x, y in return ChartDataEntry(x: Double(x), y: y) }
let yse2 = ys2.enumerate().map { x, y in return ChartDataEntry(x: Double(x), y: y) }
let data = LineChartData()
let ds1 = LineChartDataSet(values: yse1, label: "Hello")
ds1.colors = [NSUIColor.redColor()]
data.addDataSet(ds1)
let ds2 = LineChartDataSet(values: yse2, label: "World")
ds2.colors = [NSUIColor.blueColor()]
data.addDataSet(ds2)
lineChartView.data = data
lineChartView.gridBackgroundColor = NSUIColor.whiteColor()
lineChartView.descriptionText = "Linechart Demo"
lineChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .Linear)
lineChartView.translatesAutoresizingMaskIntoConstraints = true
self.view.addSubview(lineChartView)
let horizontalConstraint = NSLayoutConstraint(item: inspectorView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 20)
self.view.addConstraint(horizontalConstraint)
let verticalConstraint = NSLayoutConstraint(item: inspectorView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: titleLabel, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
self.view.addConstraint(verticalConstraint)
self.view.addConstraint(NSLayoutConstraint(item: inspectorView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: self.view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10))
Whenever lineChartView.translatesAutoresizingMaskIntoConstraints is false the chart is not drawn. If I set it to true the chart is drawn but the runtime says it could not satisfy all constraints.
I also do the same with a standard NSButton for which .translatesAutoresizingMaskIntoConstraints = false works as expected
Why isn't it working for LineChartView and what needs to be changed?
UPDATE: as was pointed out in the comments: Adding height and width constraints solved the problem

Swift how to animate up the screen while staying centered, but also shrink in size

I want to do a simple animation where the logo moves from point A on the screen at size 1 to point B on the screen at size 2
I found
self.logoOutlet.frame = CGRect(x: x, y: y, width: 115, height: 115)
how do i get it so the x is centered no matter what size the phone is?
You either have to do math, to calculate the value of x based on the bounds of the superview of logoOutlet or use AutoLayout and just use a center X constraint (which is probably the better choice).
You can read about the specifics in the documentation: Auto Layout Guide, or use one of the many tutorials on Auto Layout you can find via Google search.
Through a combination of two different answers I found a solution that works
self.logoOutlet.frame = CGRect(x: self.view.frame.midX, y: 26, width: 115, height: 115)
self.logoOutlet.center.x = self.view.center.x
Here's an example using Auto Layout:
#IBAction func animateLogo(sender: UIButton) {
let newView = UIView()
newView.backgroundColor = .redColor()
newView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(newView)
let topConstraint = NSLayoutConstraint(item: newView, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1.0, constant: 500.0)
let centerXConstraint = NSLayoutConstraint(item: newView, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1.0, constant: 0.0)
let widthConstraint = NSLayoutConstraint(item: newView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 200)
let heightConstraint = NSLayoutConstraint(item: newView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 200)
NSLayoutConstraint.activateConstraints([topConstraint, centerXConstraint, widthConstraint, heightConstraint])
self.view.layoutIfNeeded()
// Now change the constraint for the second point
widthConstraint.constant = 50
heightConstraint.constant = 50
topConstraint.constant = 50
// Animate the move over 5 seconds
UIView.animateWithDuration(5.0) {
self.view.layoutIfNeeded()
}
}

Swift : Adding Constraints to UILabel Programmatically

So I had a break from iOS dev for 4 months and its seems I have forgotten everything. All I am trying to do is place a Label programmatically at 0,0, size 200,50. I hear there is a few changes in iOS8 which I don't remember
let x : CGFloat = 0.0
let y : CGFloat = 0.0
let width : CGFloat = 200.0
let height : CGFloat = 50.0
self.label = UILabel(frame: CGRect(x: x, y: y, width: width, height: height))
self.label.text = "SIMON"
self.label.textColor = UIColor.whiteColor()
self.label.font = UIFont(name: "HelveticaNeue-UltraLight", size: 24)
self.label.textAlignment = NSTextAlignment.Center
self.label.backgroundColor = UIColor.redColor()
self.label.layer.masksToBounds = true;
self.label.layer.cornerRadius = 8.0;
self.label.adjustsFontSizeToFitWidth = true;
self.label.translatesAutoresizingMaskIntoConstraints = false
widthConstraint = NSLayoutConstraint(item: self.label, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: width)
heightConstraint = NSLayoutConstraint(item: self.label, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: height)
leftConstraint = NSLayoutConstraint(item: self.label, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1, constant: x)
topConstraint = NSLayoutConstraint(item: self.label, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: y)
self.view.addSubview(self.label)
NSLayoutConstraint.activateConstraints([leftConstraint,topConstraint, widthConstraint, heightConstraint] )
It appears I was being dump!
It was the event I was calling it from, not the code. Moved to viewWillAppear