keep original slider value when slider become used for another task - set

I want my swift code below to keep the slider value of the width constraint when the sliders value is used for something else. You can see what is going on the gif below. When the value of the slider is used for something else the constraint changes. The constraints should not change when the value of the slider is considered for something else.
import UIKit
class ViewController: UIViewController {
var frontBox = UIButton()
var backBox = UIButton()
var selectorB = UIButton()
var slider = UISlider()
var slidermultipliera: CGFloat = 0.6
var slidermultiplierb: CGFloat = 0.6
var selctorValue = 0
// constraint we will modify when slider is changed
var backBoxWidth: NSLayoutConstraint!
// constraints we will modify when backBox is dragged
var backBoxCenterY: NSLayoutConstraint!
var backBoxLeading: NSLayoutConstraint!
var FrontBoxWidth: NSLayoutConstraint!
// constraints we will modify when backBox is dragged
var FrontBoxCenterY: NSLayoutConstraint!
var FrontBoxLeading: NSLayoutConstraint!
var tim = 50.0
override func viewDidLoad() {
super.viewDidLoad()
[backBox,selectorB,frontBox,slider].forEach{
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = UIColor(
red: .random(in: 0.0...1),
green: .random(in: 0.9...1),
blue: .random(in: 0.7...1),
alpha: 1
)
}
selectorB.setTitle("right", for: .normal)
NSLayoutConstraint.activate([
selectorB.bottomAnchor.constraint(equalTo: view.bottomAnchor),
selectorB.leadingAnchor.constraint(equalTo: view.leadingAnchor),
selectorB.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1),
selectorB.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1),
slider.bottomAnchor.constraint(equalTo: selectorB.topAnchor),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor),
slider.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1),
slider.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1),
])
// backBox Width constraint
backBoxWidth = backBox.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.2)
// backBox CenterY constraint
backBoxCenterY = backBox.centerYAnchor.constraint(equalTo: view.centerYAnchor)
// backBox Leading constraint
backBoxLeading = backBox.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: CGFloat(200))
// backBox Width constraint
FrontBoxWidth = frontBox.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.2)
// backBox CenterY constraint
FrontBoxCenterY = frontBox.centerYAnchor.constraint(equalTo: view.centerYAnchor)
// backBox Leading constraint
FrontBoxLeading = frontBox.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: CGFloat(tim))
slider.setValue(Float(0.5), animated: false)
NSLayoutConstraint.activate([
// backBox Height is constant
backBox.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.5),
backBoxWidth,
backBoxLeading,
backBoxCenterY,
frontBox.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.3),
FrontBoxWidth,
FrontBoxCenterY,
FrontBoxLeading,
])
selectorB.addTarget(self, action: #selector(press), for: .touchDown)
slider.addTarget(self, action: #selector(increase), for: .valueChanged)
}
#objc func press(){
selctorValue = selctorValue == 0 ? 1 : 0
if selctorValue == 1{
backBoxWidth.isActive = false
selectorB.setTitle("left", for: .normal)
}
else {
FrontBoxWidth.isActive = false
backBoxWidth.isActive = true
selectorB.setTitle("right", for: .normal)
}
}
#objc func increase() {
if selctorValue == 1{
slidermultipliera = CGFloat(slider.value)
// update backBox Width constraint
FrontBoxWidth.isActive = false
FrontBoxWidth = frontBox.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: slidermultipliera)
FrontBoxWidth.isActive = true
}
else {
slidermultiplierb = CGFloat(slider.value)
// update backBox Width constraint
backBoxWidth.isActive = false
backBoxWidth = backBox.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: slidermultiplierb)
backBoxWidth.isActive = true
}
}
}

I've never messed with Swift, but it seems like when you click one of the boxes, you should be able to set the slider value based on the width of the box you just clicked before making that box active.
I'm guessing it would happen in your #objc func press() function. Try making both boxes inactive, then calling slider.setValue() and then activating the box which was just clicked.
Sorry I couldn't give you working code, but hopefully that helps.

Related

Прокрутка страницы до курсора

There is a page with several elements:
ImageView
TextView - for the title
Button
TextView - for description
Button
All these elements are in ScrollView.
Question: how to make it so that when editing text from TextView, the page turns to where the cursor is located?
Since the size of the TextView depends on the size of the user's text, I need to disable scrolling in the TextView. And then I don't know how to scroll the page to where the cursor is.
I haven't done much yet, I can't figure out how to do it…
My Code:
import UIKit
class DreamPageViewController: UIViewController {
private let dreamTasks = DreamTasksViewController()
private let scrollView = UIScrollView()
private let contentView = UIView()
private var cancelExecutionDream = false
private let headerImage: UIImageView = {
let image = UIImageView(image: UIImage(systemName: "multiply.square.fill"))
image.clipsToBounds = true
image.layer.cornerRadius = 40
image.contentMode = .scaleAspectFill
image.backgroundColor = .blue
image.tintColor = .systemBlue
return image
}()
private let dreamName: UITextView = {
let title = UITextView()
//label.numberOfLines = 0
title.isScrollEnabled = false
title.text = "Title"
title.font = .systemFont(ofSize: 23, weight: .bold)
return title
}()
private let doneButton: UIButton = {
let button = UIButton()
button.layer.cornerRadius = 20
button.layer.borderWidth = 2.5
button.layer.borderColor = UIColor.systemGray3.cgColor
button.setTitle("Выполнить", for: .normal)
button.setTitleColor(.systemGray2, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 20.0, weight: .semibold)
button.addTarget(self, action: #selector(DoneButtonAction), for: .touchUpInside)
return button
}()
private let textDreamPage: UITextView = {
let text = UITextView()
text.font = .systemFont(ofSize: 18, weight: .medium)
text.textColor = .darkGray
text.isScrollEnabled = false
//text.numberOfLines = 0
text.text = "Lots of text... "
return text
}()
private let tasksButton: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.layer.cornerRadius = 20
button.addTarget(self, action: #selector(dreamTasksAction), for: .touchUpInside)
return button
}()
private let taskButtonTitle: UILabel = {
let label = UILabel()
label.text = "Задачи"
label.textColor = .white
label.font = .systemFont(ofSize: 23, weight: .semibold)
return label
}()
private let tasksCountButton: UIButton = {
let button = UIButton()
let taskCount = DreamTasksViewController()
button.setTitle(String(taskCount.tasks.count), for: .normal)
button.tintColor = .white
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupUI()
setupScrollView()
componentsConfigure()
}
#objc func DoneButtonAction(sender: UIButton!) {
let animation = ButtonAnimation()
if cancelExecutionDream == false {
doneButton.setTitle("Выполнено!", for: .normal)
doneButton.layer.borderWidth = 0
doneButton.backgroundColor = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
doneButton.setTitleColor(.white, for: .normal)
animation.animationButton(doneButton)
cancelExecutionDream.toggle()
} else if cancelExecutionDream == true {
doneButton.layer.borderWidth = 2.5
doneButton.layer.borderColor = UIColor.systemGray3.cgColor
doneButton.setTitle("Выполнить", for: .normal)
doneButton.backgroundColor = .none
doneButton.setTitleColor(.systemGray2, for: .normal)
animation.animationButton(doneButton)
cancelExecutionDream.toggle()
} else { return }
}
#objc func dreamTasksAction(sender: UIButton) {
dreamTasks.title = "Задачи"
navigationController?.pushViewController(dreamTasks, animated: true)
}
private func setupUI() {
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.backButtonTitle = " "
}
private func setupScrollView() {
view.addSubview(scrollView)
scrollView.addSubview(contentView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -50).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10).isActive = true
}
private func componentsConfigure() {
contentView.addSubview(headerImage)
contentView.addSubview(dreamName)
contentView.addSubview(doneButton)
contentView.addSubview(textDreamPage)
contentView.addSubview(tasksButton)
tasksButton.addSubview(taskButtonTitle)
tasksButton.addSubview(tasksCountButton)
[headerImage, dreamName, doneButton, textDreamPage, tasksButton, taskButtonTitle, tasksCountButton].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
headerImage.topAnchor.constraint(equalTo: contentView.topAnchor),
headerImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 7),
headerImage.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -7),
headerImage.heightAnchor.constraint(greaterThanOrEqualTo: view.heightAnchor, multiplier: 3.3/5),
dreamName.topAnchor.constraint(equalTo: headerImage.bottomAnchor, constant: 10),
dreamName.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
dreamName.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10),
dreamName.heightAnchor.constraint(equalToConstant: 40),
doneButton.topAnchor.constraint(equalTo: dreamName.bottomAnchor, constant: 10),
doneButton.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
doneButton.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10),
doneButton.heightAnchor.constraint(equalToConstant: 60),
textDreamPage.topAnchor.constraint(equalTo: doneButton.bottomAnchor, constant: 10),
textDreamPage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
textDreamPage.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10),
textDreamPage.bottomAnchor.constraint(equalTo: tasksButton.topAnchor, constant: -10),
tasksButton.topAnchor.constraint(equalTo: textDreamPage.bottomAnchor, constant: 25),
tasksButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
tasksButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
tasksButton.heightAnchor.constraint(equalToConstant: 70),
tasksButton.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.95/1),
taskButtonTitle.centerYAnchor.constraint(equalTo: tasksButton.centerYAnchor),
taskButtonTitle.leftAnchor.constraint(equalTo: tasksButton.leftAnchor, constant: 15),
tasksCountButton.heightAnchor.constraint(equalToConstant: 20),
tasksCountButton.centerYAnchor.constraint(equalTo: tasksButton.centerYAnchor),
tasksCountButton.rightAnchor.constraint(equalTo: tasksButton.rightAnchor, constant: -15)
])
}
}

UIView height constraint animation, which has anchor connection with other views

Xcode swift 4
I have some views that are added dynamically in code one below another.
Each new view top anchor is connected to previous view bottom anchor.
And each view have a button that make view to expand/collapse with animation. Here is button code :
let fullHeight : CGFloat = 240
let smallHeight : CGFloat = 44
let currentHeigth = rootView.frame.size.height //I use this to get current height and understand expanded view or not
let heighCons = rootView.constraints.filter //I use this to deactivate current height Anchor constraint
{
$0.firstAttribute == NSLayoutAttribute.height
}
NSLayoutConstraint.deactivate(heighCons)
rootView.layoutIfNeeded()
if currentHeigth == smallHeight
{
rootView.heightAnchor.constraint(equalToConstant: fullHeight).isActive = true
rootView.setNeedsLayout()
UIView.animate(withDuration: 0.5)
{
rootView.layoutIfNeeded() //animation itself
}
}
else
{
rootView.heightAnchor.constraint(equalToConstant: smallHeight).isActive = true
rootView.setNeedsLayout()
UIView.animate(withDuration: 0.5)
{
rootView.layoutIfNeeded() //animation itself
}
}
This all works perfectly but i have a problem : view that below current expanding view changes it y position immediately with no animation. Its just jumping to previous view bottom anchor, that would be active after animation finish.
So my question is :
1) what is the right way to make height constraint animation, when views are connected to each other by bottom/top animation?
2) my goal is just to make a view that would expand/collapse on button click, maybe i should do it another way?
Here's an approach using Visiblity Gone Extension
extension UIView {
func visiblity(gone: Bool, dimension: CGFloat = 0.0, attribute: NSLayoutAttribute = .height) -> Void {
if let constraint = (self.constraints.filter{$0.firstAttribute == attribute}.first) {
constraint.constant = gone ? 0.0 : dimension
self.layoutIfNeeded()
self.isHidden = gone
}
}
}
Usage
expanview.visiblity(gone: true,dimension: 0)
Example
#IBOutlet weak var msgLabel: UILabel!
#IBOutlet weak var expanview: UIView!
#IBAction func toggleCollapisbleView(_ sender: UIButton) {
if sender.isSelected{
sender.isSelected = false
expanview.visiblity(gone: false,dimension: 128)
sender.setTitle("Collapse",for: .normal)
}
else{
sender.isSelected = true
expanview.visiblity(gone: true,dimension: 0)
sender.setTitle("Expand",for: .normal)
msgLabel.text = "Visiblity gone"
}
}

How can I create multiple UISwitches from an array positioned one after another?

I have a popup view, that I would like to populate with ~15 UISwitches. Now it would be stupid to do all of that manually, so in Android I have set up a for loop to create said UISwitches from an array and you are able to toggle each one on and off and so on, each having their own value. I have created one switch, but when trying to create multiple from an array, none show up and I have no idea how I would be able to position them one after another.
let mySwitch = UISwitch()
mySwitch.isOn = false
mySwitch.center = self.view.center
mySwitch.thumbTintColor = UIColor(red: 23.0/255, green: 145.0/255, blue: 255.0/255, alpha: 1.0)
mySwitch.tintColor = UIColor(red: 23.0/255, green: 145.0/255, blue: 255.0/255, alpha: 1.0)
mySwitch.onTintColor = UIColor.black
mySwitch.backgroundColor = UIColor.white
self.view.addSubview(mySwitch)
var scrol = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
scrol.frame = CGRect(x: 10, y: 0, width: self.view.frame.size.width, height: 200)
var yPos = 0.0
for i in 0...10 {
let mySwitch = UISwitch()
mySwitch.frame = CGRect(x: 10, y: yPos + 10, width: 50, height: 25)
mySwitch.isOn = false
// mySwitch.center = self.view.center
mySwitch.tag = i
mySwitch.thumbTintColor = UIColor(red: 23.0/255, green: 145.0/255, blue: 255.0/255, alpha: 1.0)
mySwitch.tintColor = UIColor(red: 23.0/255, green: 145.0/255, blue: 255.0/255, alpha: 1.0)
mySwitch.onTintColor = UIColor.black
mySwitch.backgroundColor = UIColor.white
yPos = Double(mySwitch.frame.origin.y + mySwitch.frame.size.height)
mySwitch.addTarget(self, action: #selector(onSwitchChange(_:)), for: .touchUpInside)
scrol.addSubview(mySwitch)
}
scrol.backgroundColor = .yellow
scrol.isScrollEnabled = true
self.view.addSubview(scrol)
}
func onSwitchChange(_ sender: UISwitch) {
print(" switch tapped \(sender.tag)")
}
Check out this, i have added a scrollView inside a UIView and have added multiple UISwitch as you have given in code with Frame set for UISwitch.
I'd recommend looking at UIStackView.
This allows you to easily add multiple UI elements to the screen at consistent positions without any hassle.
First you'd want to create a stack view:
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 10
add it and constrain it:
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor),
// etc, etc
])
Then you'd simply add a series of switches to the stack view:
for i in 0..<10 {
let switch = UISwitch()
// Configure switch
stackView.addArrangedSubview(switch)
}

Xcode Stopped Recognizing Global Variables - Swift

I've been working on an app for over a month and have many variables defined at the top of the Swift document that came with my tabbed interface template in XCODE. I've declared various UIColors to be used globally and have made a few classes where I draw a few different icon shapes. All of a sudden today Xcode is throwing up red errors of "Use of unresolved identifier [one of my UIColor variabls]" for all of my colors used throughout my drawing classes. I've tried to clean the project and restart Xcode Any idea what could be going on?
Here are my global variables:
import Foundation
import UIKit
import QuartzCore
//----Global Variables----
var timerMode = "start"
var arrowButtonTapped = false
var timerButtonTouched = false
var currentView = "brew it"
//--------My Colors -----------
let colorGreen = UIColor(red: 0.310, green: 0.725, blue: 0.624, alpha: 1.000)
let colorLightGreen = UIColor(red: 211/255, green: 217/255, blue: 195/255, alpha: 100)
var colorRed = UIColor(red: 241/255, green: 93/255, blue: 79/255, alpha: 100)
let colorDarkBlue = UIColor(red: 27/255, green: 29/255, blue: 38/255, alpha: 1.0)
let colorOrange = UIColor(red: 241/255, green: 162/255, blue: 128/255, alpha: 1.0)
let colorTransparent = UIColor(red: 241/255, green: 162/255, blue: 128/255, alpha: 0.0)
//----Countdown times----
var countTime : NSTimeInterval = 6
var halfCountTime : NSTimeInterval = countTime * 0.5
var okCountTime : NSTimeInterval = 2
//---- End Global Variables ----
//let cup1Graphic = coffeeMugVector()
//let cup2Graphic = coffeeMugVector()
//let cup3Graphic = coffeeMugVector()
//let cup4Graphic = coffeeMugVector()
//let cup5Graphic = coffeeMugVector()
//let cup6Graphic = coffeeMugVector()
//Coffe Cups x Coffee Strength returns amount of coffee as an integer
class coffeeCalculator {
var selectedCups = 0
var cupSelect = false
let coffeeStronger = 20
var coffeeStrength = 15
let coffeeWeaker = 15
var water = 226
//var cupAnimation = CSAnimationView(type:"morph", duration:0.5, delay:0)
// What to do when a cup is selected
func cupSelected() {
if cupSelect == true{
selectedCups++
}
else if selectedCups > 0{
selectedCups--
}
println("\(selectedCups)")
}
//take coffee cups multiplied by coffee strength and return the amount as a string
//Calcualte coffee and return an attributed string
func coffeeTextOnly() ->String {
var calculatedCoffee = selectedCups * coffeeStrength
var coffeeToString = "\(calculatedCoffee)"
return coffeeToString
}
func calculateCoffee() -> (NSMutableAttributedString) {
var calculatedCoffee = selectedCups * coffeeStrength
var coffeeToString = "\(calculatedCoffee)"
//Convert the CoffeeCalculator output to an attributed string
var coffeeText = NSMutableAttributedString(string:coffeeToString)
//Part 2 set the font attributes for the lower case g
var coffeeTypeFaceAttributes = [NSFontAttributeName : UIFont.systemFontOfSize(18)]
//Part 3 create the "g" character and give it the attributes that you set up
var coffeeG = NSMutableAttributedString(string:"g", attributes:coffeeTypeFaceAttributes)
coffeeText.appendAttributedString(coffeeG)
return (coffeeText)
}
//Calculate teh amount of water needed and return it as a string
func calculateWater() -> (NSMutableAttributedString) {
var calculatedWater = water * selectedCups
var waterToString = "\(calculatedWater)"
var waterText = NSMutableAttributedString(string:waterToString)
//Part 2 set the font attributes for the lower case g
var waterTypeFaceAttributes = [NSFontAttributeName : UIFont.systemFontOfSize(18)]
//Part 3 create the "g" character and give it the attributes that you set up
var waterG = NSMutableAttributedString(string:"g", attributes:waterTypeFaceAttributes)
waterText.appendAttributedString(waterG)
return (waterText)
}
}
////----BEGIN GRAPHICS ----////
//----Main Timer (circle) Button----//
#IBDesignable
class timerButtonGraphics: UIView {
override func drawRect(rect: CGRect) {
var bounds = self.bounds
var center = CGPoint()
center.x = bounds.origin.x + bounds.size.width / 2
center.y = bounds.origin.y + bounds.size.height / 2
var radius = 31
var path:UIBezierPath = UIBezierPath()
path.addArcWithCenter(center, radius: CGFloat(radius), startAngle: CGFloat(0.0), endAngle: CGFloat(Float(M_PI) * 2.0), clockwise: true)
path.strokeWithBlendMode(kCGBlendModeNormal, alpha: 0)
path.lineWidth = 1
if timerMode == "reset" || timerMode == "ok" {
colorRed.setStroke()
colorRed.setFill()
}
else {
colorGreen.setStroke()
colorGreen.setFill()
}
if timerButtonTouched == true {
path.lineWidth = 2
path.fill()
}
path.stroke()
}
}
//------Arrow Button------//
#IBDesignable
class arrowButtonGraphic: UIView {
override func drawRect(rect: CGRect) {
var bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointMake(20.36, 2.68))
bezierPath.addLineToPoint(CGPointMake(2.69, 20.23))
bezierPath.addCurveToPoint(CGPointMake(2.69, 28.32), controlPoint1: CGPointMake(0.44, 22.46), controlPoint2: CGPointMake(0.44, 26.09))
bezierPath.addCurveToPoint(CGPointMake(10.84, 28.32), controlPoint1: CGPointMake(4.94, 30.56), controlPoint2: CGPointMake(8.59, 30.56))
bezierPath.addLineToPoint(CGPointMake(22.71, 16.53))
bezierPath.addCurveToPoint(CGPointMake(26.29, 16.53), controlPoint1: CGPointMake(23.7, 15.55), controlPoint2: CGPointMake(25.3, 15.56))
bezierPath.addLineToPoint(CGPointMake(38.16, 28.32))
bezierPath.addCurveToPoint(CGPointMake(46.31, 28.32), controlPoint1: CGPointMake(40.41, 30.56), controlPoint2: CGPointMake(44.06, 30.56))
bezierPath.addCurveToPoint(CGPointMake(46.31, 20.23), controlPoint1: CGPointMake(48.56, 26.09), controlPoint2: CGPointMake(48.56, 22.46))
bezierPath.addLineToPoint(CGPointMake(28.64, 2.68))
bezierPath.addCurveToPoint(CGPointMake(24.48, 1), controlPoint1: CGPointMake(27.49, 1.54), controlPoint2: CGPointMake(25.98, 0.98))
bezierPath.addCurveToPoint(CGPointMake(20.36, 2.68), controlPoint1: CGPointMake(22.99, 0.99), controlPoint2: CGPointMake(21.5, 1.55))
bezierPath.closePath()
bezierPath.miterLimit = 4;
colorGreen.setStroke()
bezierPath.lineWidth = 1
bezierPath.stroke()
colorGreen.setFill()
//Rotate arrow if on "weigh it" page
if arrowButtonTapped == true {
bezierPath.lineWidth = 2
bezierPath.stroke()
}
}
}
//----Timer Baground Circle ----//
#IBDesignable
class timerBackgroundCircle: UIView {
override func drawRect(rect: CGRect) {
var ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, 238, 238))
colorLightGreen.setFill()
ovalPath.fill()
}
}
//----Timer Bagkround Mask ----//
#IBDesignable
class timerMask: UIView {
override func drawRect(rect: CGRect) {
let colorGreen = UIColor(red: 0.310, green: 0.725, blue: 0.624, alpha: 1.000)
let colorRed = UIColor(red: 241/255, green: 93/255, blue: 79/255, alpha: 100)
let colorLightGreen = UIColor(red: 211/255, green: 217/255, blue: 195/255, alpha: 100)
//The shape to mask out
/*var ovalPath = UIBezierPath(ovalInRect: CGRect(x: 0, y: 0, width: 238, height: 238))
colorGreen.setFill()
ovalPath.fill()*/
//The rectangle
var bounds : CGRect = self.bounds
var maskRect = CAShapeLayer()
maskRect.frame = bounds
//maskRect.fillColor = colorLightGreen.CGColor
//The circle mask
var maskCirclePath = UIBezierPath(ovalInRect: CGRect(x: 40, y: 150, width: 238, height: 238))
maskCirclePath.appendPath(UIBezierPath(rect: bounds))
//combine appended path to rectangle path
maskRect.path = maskCirclePath.CGPath
colorRed.setFill()
maskCirclePath.fill()
maskRect.fillRule = kCAFillRuleEvenOdd
self.layer.mask = maskRect
}
}
I'm not sure if my classes are being declared correctly. I made a group called "Vectors" where I planned to make a separate class for each drawing. I'm not sure if i'm supposed to select file -> new -> file and select a Cocoa Touch Class, or if i can just create a blank Swift file and write out my class code from scratch there. This is the option I was trying to figure out when my globial variables "went bad".
What's more strange is that the app compiles just fine in the simulator, my colors appear correctly for the classes applied to my icons that use the global color variables. But Xcode is throwing a fit so my #IBDesignables won't compile in storyboard and I have a bunch of red errors.
UPDATE
Somewhere along the way here, the Swift file that I posted in my question was removed from my projects "tests" target membership. The little checkbox was unchecked. I have no idea how I could have done this, but everything was back to normal until i got an xcode error whiting out all of my text and saying that editing is currently disabled. I ended up removing all of my swift files from "tests" (unchecking the "tests" target membership for all of the files"), then creating a new Objective C file which prompted Xcode to ask me to configure a new bridging header I transferred my old bridging header code to the new file. This seems to have fixed the problem. I'm not submitting this an an answer because I don't know what the actual problem was.

Inherited control does not draw

I'm trying to create an own progress bar by subclassing NSProgressIndicator. I wrote the code using a Playground in Xcode 6 and it works fine (the content is being drawn correctly).
As soon as I put the class onto the GUI (either as type for a "Custom View" or for an "Indeterminate Progress Indicator") the control does not draw though the drawRect(dirtyRect: NSRect) method has been overridden and is being called by the framework.
Here's my code:
class AbProgressBar : NSProgressIndicator
{
let drawStep = 10
var rounded: Bool = true
var margin: CGFloat = 4.0
var barColor: NSColor = NSColor.blueColor()
var barBorderColor: NSColor = NSColor.whiteColor()
var borderColor: NSColor = NSColor.grayColor()
var backgroundColor: NSColor = NSColor.blackColor()
init(coder: NSCoder!)
{
println(__FUNCTION__)
super.init(coder: coder)
}
init(frame frameRect: NSRect)
{
println("\(__FUNCTION__) with frame \(frameRect)")
super.init(frame: frameRect)
}
override func drawRect(dirtyRect: NSRect)
{
println(__FUNCTION__)
// Here we calculate the total value area from minValue to maxValue in order to find out the percental width of the inner bar
let area = minValue < 0 && maxValue < 0 ? abs(minValue) + maxValue : abs(maxValue) + abs(minValue)
let currentPercentageFilled: Double = doubleValue >= maxValue ? maxValue : 100 / area * doubleValue
let innerWidth = (frame.width - (margin * 2)) / 100 * currentPercentageFilled
let radOuterX = rounded ? frame.height / 2 : 0
let radOuterY = rounded ? frame.width / 2 : 0
let radInnerX = rounded ? (frame.height - margin) / 2 : 0
let radInnerY = rounded ? innerWidth / 2 : 0
// The inner frame depends on the width filled by the current value
let innerFrame = NSRect(x: frame.origin.x + margin, y: frame.origin.y + margin, width: innerWidth, height: frame.height - (margin * 2))
let pathOuter: NSBezierPath = NSBezierPath(roundedRect: frame, xRadius: radOuterX, yRadius: radOuterY)
let pathInner: NSBezierPath = NSBezierPath(roundedRect: innerFrame, xRadius: radInnerX, yRadius: radInnerY)
let gradientOuter: NSGradient = NSGradient(startingColor: NSColor.whiteColor(), endingColor: backgroundColor)
let gradientInner: NSGradient = NSGradient(startingColor: NSColor.grayColor(), endingColor: barColor)
gradientOuter.drawInBezierPath(pathOuter, angle: 270.0)
if(pathInner.elementCount > 0)
{
gradientInner.drawInBezierPath(pathInner, angle: 270.0)
}
borderColor.set()
pathOuter.stroke()
barBorderColor.set()
pathInner.stroke()
}
}
Using it within a playground works fine. Setting it as type for a control placed on a UI does NOT work.
Does anybody have any clue what might be wrong?
Edit: Just to add that information: I checked the view using the new "Debug View Hierarchy" feature included in Xcode 6. Result: The control is definitely there.
I figured it out...
The problem was that I used the frame property of the super class instead of the dirtyRect parameter passed into the drawRect(...) method.
I just exchanged every access to frame with dirtyRect and now it works.
Looks a bit strange to me because (as far as I understand it) dirtyRect should refer to the same rectangle as frame.

Resources