how to arrange elements in UIStackView in realtime? - swift

I have a stackView with horizontal axis and I have UIView inside it, I kinda created a graph from that ,
the red one bars are the UIViews and the gray background is the stackView(referred as mainStackView in code) , Now I want to move that bar in realtime , I am trying to make a sorting visualiser but I dont know how do I do that
In UIKit (everything is programmatic in live playground), here is the source code of the main file
Main file
if (arrayToSort[j].frame.size.height > arrayToSort[j+1].frame.size.height){
// swap
var temp:UIView!
temp = arrayToSort[j]
arrayToSort[j] = arrayToSort[j+1]
arrayToSort[j+1] = temp
emptyStackView()
fillStackView(sortdArr: arrayToSort)
// delay here
}
Here is the source code for HomeViewController
import UIKit
public class HomeViewController:UIViewController{
let stackView:UIStackView = {
let st = UIStackView()
st.axis = .horizontal
st.alignment = .center
st.distribution = .fill
st.layer.shadowColor = UIColor.gray.cgColor
st.layer.shadowOffset = .zero
st.layer.shadowRadius = 5
st.layer.shadowOpacity = 1
st.spacing = 10
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let generateButton:UIButton = {
let btn = UIButton()
btn.setTitle("Generate Array", for: .normal)
btn.backgroundColor = UIColor(red: 0.92, green: 0.30, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let BubbleSort:UIButton = {
let btn = UIButton()
btn.setTitle("BubbleSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.41, green: 0.43, blue: 0.88, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let MergeSort:UIButton = {
let btn = UIButton()
btn.setTitle("MergeSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.10, green: 0.16, blue: 0.34, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let InsertionSort:UIButton = {
let btn = UIButton()
btn.setTitle("InsertionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.19, green: 0.22, blue: 0.32, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let SelectionSort:UIButton = {
let btn = UIButton()
btn.setTitle("SelectionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.51, green: 0.20, blue: 0.44, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let mainStackView:UIStackView = {
let st = UIStackView()
st.backgroundColor = .gray
st.axis = .horizontal
st.distribution = .fillEqually
st.alignment = .bottom
st.spacing = 1
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let baseView:UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.07, green: 0.54, blue: 0.65, alpha: 1.00)
vw.translatesAutoresizingMaskIntoConstraints = false
vw.layer.cornerRadius = 3
vw.layer.masksToBounds = true
vw.heightAnchor.constraint(equalToConstant: 15).isActive = true
return vw
}()
public override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(stackView)
view.addSubview(mainStackView)
view.addSubview(baseView)
edgesForExtendedLayout = []
stackView.addArrangedSubview(generateButton)
stackView.addArrangedSubview(BubbleSort)
stackView.addArrangedSubview(MergeSort)
stackView.addArrangedSubview(InsertionSort)
stackView.addArrangedSubview(SelectionSort)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
baseView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -2).isActive = true
baseView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 5).isActive = true
baseView.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -5).isActive = true
mainStackView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 5).isActive = true
mainStackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5).isActive = true
mainStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: baseView.topAnchor, constant: -5).isActive = true
setButtons()
buildRandomArray()
}
// MARK:- Actions
func setButtons(){
generateButton.addTarget(self, action: #selector(generatePressed), for: .touchUpInside)
BubbleSort.addTarget(self, action: #selector(bubbleSort), for: .touchUpInside)
MergeSort.addTarget(self, action: #selector(mergeSort), for: .touchUpInside)
InsertionSort.addTarget(self, action: #selector(insertionSort), for: .touchUpInside)
SelectionSort.addTarget(self, action: #selector(selectionSort), for: .touchUpInside)
}
func buildRandomArray(){
var randomNumber :CGFloat!
for _ in 1..<41{
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
randomNumber = CGFloat(Int.random(in: 160...600))
v.heightAnchor.constraint(equalToConstant: randomNumber).isActive = true
v.frame.size.height = randomNumber
return v
}()
mainStackView.addArrangedSubview(viewStick)
}
}
#objc func generatePressed(){
emptyStackView()
buildRandomArray()
print("Generating Array.....")
}
#objc func bubbleSort(){
let n = mainStackView.arrangedSubviews.count
var arrayToSort = mainStackView.arrangedSubviews
for i in 0..<n-1{
for j in 0..<n-i-1 {
if (arrayToSort[j].frame.size.height > arrayToSort[j+1].frame.size.height){
// swap
var temp:UIView!
temp = arrayToSort[j]
arrayToSort[j] = arrayToSort[j+1]
arrayToSort[j+1] = temp
self.emptyStackView()
self.fillStackView(sortdArr: arrayToSort)
// delay here
}
}
}
print("array sorted")
}
#objc func mergeSort(){
print("Merge Sort.....")
}
#objc func insertionSort(){
print("insertion Sort.....")
}
#objc func selectionSort(){
print("selection Sort.....")
}
func emptyStackView(){
for element in mainStackView.arrangedSubviews {
mainStackView.removeArrangedSubview(element)
}
}
func fillStackView(sortdArr:[UIView]){
for vw in sortdArr {
mainStackView.addArrangedSubview(vw)
}
}
}

To update the UI in a loop, you have to give UIKit a chance to run.
For example, this:
for i in 1...200 {
someView.frame.origin.x = CGFloat(i)
}
will NOT "slide the view" to the right - it will cause the view to "jump" from x: 1 to x: 200.
So, in your loop where you're trying to visualize the sorting process, nothing on the screen will update until you have completed the loop.
To have something happen each time through, you can use a Timer.
With the previous example, you could do something like this:
var i = 1
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
someView.frame.origin.x = CGFloat(i)
i += 1
if i > 200 {
timer.invalidate()
}
}
Now the view will "slide slowly" across the screen.
So, you need to refactor your sorting code with a timer.
I made some edits to your code to let you see one approach to this task. Give it a try (it will run in a playground), and inspect the code and //comments. Changes don't start until the buildRandomArray() function:
Edit - I made a few changes to this code...
has an array of "sample values" to make it easier to re-run
added a "Reset" button to re-run with the original values
when using sample values, bars are now labels to make it clearer that the bars are being "moved"
implemented Insertion Sort
Worth noting: When running this in a playground, button taps while a sort is active are not very responsive. Works much betting with an iPad Simulator or Device.
public class SortViewController:UIViewController{
let stackView:UIStackView = {
let st = UIStackView()
st.axis = .horizontal
st.alignment = .center
st.distribution = .fillEqually
st.layer.shadowColor = UIColor.gray.cgColor
st.layer.shadowOffset = .zero
st.layer.shadowRadius = 5
st.layer.shadowOpacity = 1
st.spacing = 10
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let generateButton:UIButton = {
let btn = UIButton()
btn.setTitle("Generate", for: .normal)
btn.backgroundColor = UIColor(red: 0.92, green: 0.30, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let resetButton:UIButton = {
let btn = UIButton()
btn.setTitle("Reset", for: .normal)
btn.backgroundColor = UIColor(red: 0.25, green: 0.75, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let BubbleSort:UIButton = {
let btn = UIButton()
btn.setTitle("Bubble", for: .normal)
btn.backgroundColor = UIColor(red: 0.41, green: 0.43, blue: 0.88, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let MergeSort:UIButton = {
let btn = UIButton()
btn.setTitle("Merge", for: .normal)
btn.backgroundColor = UIColor(red: 0.10, green: 0.16, blue: 0.34, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let InsertionSort:UIButton = {
let btn = UIButton()
btn.setTitle("Insertion", for: .normal)
btn.backgroundColor = UIColor(red: 0.19, green: 0.22, blue: 0.32, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let SelectionSort:UIButton = {
let btn = UIButton()
btn.setTitle("Selection", for: .normal)
btn.backgroundColor = UIColor(red: 0.51, green: 0.20, blue: 0.44, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let mainStackView:UIStackView = {
let st = UIStackView()
st.backgroundColor = .gray
st.axis = .horizontal
st.distribution = .fillEqually
st.alignment = .bottom
st.spacing = 1
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let baseView:UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.07, green: 0.54, blue: 0.65, alpha: 1.00)
vw.translatesAutoresizingMaskIntoConstraints = false
vw.layer.cornerRadius = 3
vw.layer.masksToBounds = true
vw.heightAnchor.constraint(equalToConstant: 15).isActive = true
return vw
}()
public override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(stackView)
view.addSubview(mainStackView)
view.addSubview(baseView)
edgesForExtendedLayout = []
stackView.addArrangedSubview(generateButton)
stackView.addArrangedSubview(resetButton)
stackView.addArrangedSubview(BubbleSort)
stackView.addArrangedSubview(MergeSort)
stackView.addArrangedSubview(InsertionSort)
stackView.addArrangedSubview(SelectionSort)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
baseView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -2).isActive = true
baseView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 5).isActive = true
baseView.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -5).isActive = true
mainStackView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 5).isActive = true
mainStackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5).isActive = true
mainStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: baseView.topAnchor, constant: -5).isActive = true
setButtons()
buildRandomArray()
}
// MARK:- Actions
func setButtons(){
generateButton.addTarget(self, action: #selector(generatePressed), for: .touchUpInside)
resetButton.addTarget(self, action: #selector(resetPressed), for: .touchUpInside)
BubbleSort.addTarget(self, action: #selector(bubbleSort), for: .touchUpInside)
MergeSort.addTarget(self, action: #selector(mergeSort), for: .touchUpInside)
InsertionSort.addTarget(self, action: #selector(insertionSort), for: .touchUpInside)
SelectionSort.addTarget(self, action: #selector(selectionSort), for: .touchUpInside)
}
let sampleValues: [Int] = [
150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500
]
var currentArray: [UIView] = []
let barColor: UIColor = .cyan
let barHighlight: UIColor = .yellow
let timerInterval: TimeInterval = 0.10
func buildRandomArray(){
// we can populate the stack view much quicker by generating an array of views
// and then looping through that array to add them as arrangedSubviews
currentArray = []
// for ease during dev, use a set of predefined values
if true {
let hh = sampleValues.shuffled()
hh.forEach { h in
let viewStick: UILabel = {
let v = UILabel()
v.backgroundColor = barColor
v.text = "\(h)"
v.textAlignment = .center
v.heightAnchor.constraint(equalToConstant: CGFloat(h)).isActive = true
return v
}()
currentArray.append(viewStick)
}
} else {
var randomNumber :CGFloat!
for _ in 1..<41{
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = barColor
v.translatesAutoresizingMaskIntoConstraints = false
randomNumber = CGFloat(Int.random(in: 160...500))
v.heightAnchor.constraint(equalToConstant: randomNumber).isActive = true
return v
}()
currentArray.append(viewStick)
}
}
fillStackView(sortdArr: currentArray)
}
#objc func generatePressed(){
// stop the timer if a sort is currently running
timer?.invalidate()
print("Generating Array.....")
emptyStackView()
buildRandomArray()
}
#objc func resetPressed(){
// stop the timer if a sort is currently running
timer?.invalidate()
print("Resetting.....")
fillStackView(sortdArr: currentArray)
}
var timer: Timer?
#objc func bubbleSort(){
print("Bubble Sort....")
// if a sort is running, stop it and reset the bars
if let t = timer, t.isValid {
resetPressed()
}
var j: Int = 0
var didSwap: Bool = false
var lastBarToCheck: Int = mainStackView.arrangedSubviews.count - 1
// set current bar to first bar
var curBar = mainStackView.arrangedSubviews[0]
// set new current bar background to barHighlight
curBar.backgroundColor = barHighlight
timer = Timer.scheduledTimer(withTimeInterval: timerInterval, repeats: true) { timer in
// if we have more bars to check
if j < lastBarToCheck {
if self.mainStackView.arrangedSubviews[j].frame.height > self.mainStackView.arrangedSubviews[j+1].frame.height {
// next bar is shorter than current bar, so
// swap the bar positions
self.mainStackView.insertArrangedSubview(curBar, at: j + 1)
// set the didSwap flag
didSwap = true
} else {
// next bar is taller
// set current bar background back to barColor
curBar.backgroundColor = self.barColor
// set current bar to next bar
curBar = self.mainStackView.arrangedSubviews[j+1]
// set new current bar background to barHighlight
curBar.backgroundColor = self.barHighlight
}
j += 1
} else {
if !didSwap {
// no bars were swapped, so
// set current bar back to barColor
curBar.backgroundColor = self.barColor
// stop the looping
timer.invalidate()
print("Done!")
} else {
// at least one swap occurred, so
// decrement number of bars to check
lastBarToCheck -= 1
// reset index
j = 0
// set current bar back to barColor
curBar.backgroundColor = self.barColor
// set current bar background to first bar
curBar = self.mainStackView.arrangedSubviews[j]
// set new current bar background to barHighlight
curBar.backgroundColor = self.barHighlight
// reset swap flag
didSwap = false
}
}
}
}
#objc func mergeSort(){
print("Merge Sort.....")
}
#objc func insertionSort(){
print("Insertion Sort.....")
// if a sort is running, stop it and reset the bars
if let t = timer, t.isValid {
resetPressed()
}
var index: Int = 1
var position: Int = 1
// set current bar to index bar
var curBar = mainStackView.arrangedSubviews[index]
// set new current bar background to barHighlight
curBar.backgroundColor = barHighlight
timer = Timer.scheduledTimer(withTimeInterval: timerInterval, repeats: true) { timer in
// if we have more bars to check
if index < self.mainStackView.arrangedSubviews.count {
// if we're not at the left-most bar
if position > 0 {
// if bar-to-the-left is taller than current bar
if self.mainStackView.arrangedSubviews[position - 1].frame.height > curBar.frame.height {
// move current bar one position to the left
self.mainStackView.insertArrangedSubview(curBar, at: position - 1)
position -= 1
} else {
// bar-to-the-left is shorter than current bar
index += 1
position = index
// set current bar background back to barColor
curBar.backgroundColor = self.barColor
// if we're not finished
if index < self.mainStackView.arrangedSubviews.count {
// set current bar to next bar
curBar = self.mainStackView.arrangedSubviews[index]
// set new current bar background to barHighlight
curBar.backgroundColor = self.barHighlight
}
}
} else {
// we're at the left-most bar
// increment index
index += 1
position = index
// set current bar background back to barColor
curBar.backgroundColor = self.barColor
// if we have more bars to check
if index < self.mainStackView.arrangedSubviews.count {
// set current bar to next bar
curBar = self.mainStackView.arrangedSubviews[index]
// set new current bar background to barHighlight
curBar.backgroundColor = self.barHighlight
}
}
} else {
// we've reached the end of the array
// stop the looping
timer.invalidate()
print("Done!")
}
}
}
#objc func selectionSort(){
print("selection Sort.....")
}
func emptyStackView(){
mainStackView.arrangedSubviews.forEach {
$0.removeFromSuperview()
}
}
func fillStackView(sortdArr:[UIView]){
sortdArr.forEach { vw in
vw.backgroundColor = self.barColor
mainStackView.addArrangedSubview(vw)
}
}
}
A tip related to stack views and their arrangedSubviews... you don't have to clear and re-populate the stack view to rearrange the views.
For example, if I add 10 labels to a stack view:
// add 10 arranged subviews
for i in 0..<10 {
let v = UILabel()
v.text = "\(i)"
v.textAlignment = .center
v.backgroundColor = .green
stackView.addArrangedSubview(v)
}
it will look like this:
If I want to swap the 4th and 5th views, I can do it like this:
// (arrays are zero-based)
stackView.insertArrangedSubview(stackView.arrangedSubviews[3], at: 4)
and I get:

Related

UITableView with header section shows last cell content in retracted mode

Continuing to solve the task of UITableViewCell, almost everything is working correctly except the last header view which shows the cell contents in retracted mode as showed in green marked. This way allows a quick access to button tapped action.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = DetailViewCell(style: .default, reuseIdentifier: nil)
let vStackView = UIStackView()
vStackView.axis = .vertical
vStackView.backgroundColor = .white
vStackView.distribution = .fillEqually
vStackView.spacing = 12
vStackView.alignment = .top
var hStackView = UIStackView()
let data = sections[indexPath.section].data
for (index, item) in data.enumerated() {
let btn = UIButton()
btn.setTitle(item.title, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 12)
btn.setTitleColor(.black, for: .normal)
btn.backgroundColor = UIColor(red: 220, green: 220, blue: 220)
btn.layer.cornerRadius = 15
btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
btn.accessibilityIdentifier = item.description
hStackView.addArrangedSubview(btn)
if index % 2 == 0 {
hStackView = UIStackView()
hStackView.axis = .horizontal
hStackView.spacing = 12
hStackView.alignment = .fill
hStackView.backgroundColor = .white
hStackView.distribution = .fillEqually
hStackView.addArrangedSubview(btn)
if (index + 1) == data.count {
vStackView.addArrangedSubview(hStackView)
hStackView.leadingAnchor.constraint(equalTo: vStackView.leadingAnchor).isActive = true
hStackView.widthAnchor.constraint(equalTo: vStackView.widthAnchor, multiplier: 0.5).isActive = true
}
}
else {
hStackView.addArrangedSubview(btn)
vStackView.addArrangedSubview(hStackView)
hStackView.leadingAnchor.constraint(equalTo: vStackView.leadingAnchor).isActive = true
hStackView.trailingAnchor.constraint(equalTo: vStackView.trailingAnchor).isActive = true
}
}
// Add the stack view to the cell's contentView
cell.contentView.addSubview(vStackView)
vStackView.translatesAutoresizingMaskIntoConstraints = false
vStackView.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 8).isActive = true
vStackView.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 8).isActive = true
vStackView.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -8).isActive = true
vStackView.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -8).isActive = true
return cell
}

UITextField position and size depending on screen size

When the screen size changes, the textField moves out of its place. How to attach it in the same place depending on the screen size?
Grey background of the textField for clarity.
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor),
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
plateImage.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 50),
plateImage.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
plateImage.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
plateImage.heightAnchor.constraint(equalTo: plateImage.widthAnchor, multiplier: 0.6785162287),
inputTextField.topAnchor.constraint(equalTo: plateImage.topAnchor, constant: 25),
inputTextField.leadingAnchor.constraint(equalTo: plateImage.leadingAnchor, constant: 80),
inputTextField.trailingAnchor.constraint(equalTo: plateImage.trailingAnchor, constant: -28),
])
Here is my scrollView, containerView and texField. I think all variables are fine. Aren't they?
private lazy var scrollView: UIScrollView = {
var view = UIScrollView()
view.backgroundColor = UIColor(red: 37 / 255, green: 40 / 255, blue: 47 / 255, alpha: 1)
view.showsVerticalScrollIndicator = false
view.showsHorizontalScrollIndicator = false
view.autoresizingMask = .flexibleHeight
view.setContentHuggingPriority(.defaultLow, for: .vertical)
view.clipsToBounds = true
view.bounces = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var containerView: UIView = {
var view = UIView()
view.backgroundColor = UIColor(red: 37 / 255, green: 40 / 255, blue: 47 / 255, alpha: 1)
view.clipsToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var plateImage: UIImageView = {
var view = UIImageView()
view.image = UIImage(named: "plate")
view.clipsToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
public lazy var inputTextField: UITextField = {
var view = UITextField()
view.textAlignment = .center
view.textColor = .black
view.tintColor = .clear
view.font = UIFont(name: "Avenir-Heavy", size: 155)
view.keyboardType = .numberPad
view.addButtonsToKeyboard(search: #selector(self.resignFirstResponder))
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
Here is my controller full code.
final class PlatesView: UIView {
weak var delegate: PlatesViewDelegate?
init(subscriber: PlatesViewDelegate?) {
super.init(frame: .zero)
self.delegate = subscriber
addSubView()
setupLayout()
setupButtonAction()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func addSubView() {
addSubview(scrollView)
scrollView.addSubview(containerView)
containerView.addSubview(plateImage)
containerView.addSubview(inputTextField)
}
private lazy var scrollView: UIScrollView = {
var view = UIScrollView()
view.backgroundColor = UIColor(red: 37 / 255, green: 40 / 255, blue: 47 / 255, alpha: 1)
view.showsVerticalScrollIndicator = false
view.showsHorizontalScrollIndicator = false
view.setContentHuggingPriority(.defaultLow, for: .vertical)
view.bounces = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var containerView: UIView = {
var view = UIView()
view.backgroundColor = UIColor(red: 37 / 255, green: 40 / 255, blue: 47 / 255, alpha: 1)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var plateImage: UIImageView = {
var view = UIImageView()
view.image = UIImage(named: "plate")
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
public lazy var inputTextField: UITextField = {
var view = UITextField()
view.textAlignment = .center
view.textColor = .black
view.tintColor = .clear
view.font = UIFont(name: "Avenir-Heavy", size: 155)
view.keyboardType = .numberPad
view.addButtonsToKeyboard(search: #selector(self.resignFirstResponder))
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupLayout() {
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor),
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
plateImage.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 50),
plateImage.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
plateImage.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
plateImage.heightAnchor.constraint(equalTo: plateImage.widthAnchor, multiplier: 0.6785162287),
inputTextField.topAnchor.constraint(equalTo: plateImage.topAnchor, constant: 33),
inputTextField.leadingAnchor.constraint(equalTo: plateImage.leadingAnchor, constant: 80),
inputTextField.trailingAnchor.constraint(equalTo: plateImage.trailingAnchor, constant: -28),
inputTextField.heightAnchor.constraint(equalToConstant: 130),
])
}
private func setupButtonAction() {
}
}

swift tap gesture handler not invoked

I have the following custom view implementation :
import UIKit
class ProfileTableHeaderView: UITableViewHeaderFooterView {
private var statusText : String = ""
private let fullNameLabel: UILabel = {
let view = UILabel()
view.text = "Hipster Pinguin"
view.font = UIFont.systemFont(ofSize: 18, weight: .bold)
view.textColor = .black
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let avatarImage: UIImageView = {
let view = UIImageView()
view.clipsToBounds = true
view.layer.borderWidth = 3
view.layer.borderColor = UIColor.white.cgColor
view.image = UIImage(named: "avatar")
view.contentMode = .scaleAspectFill
view.layer.cornerRadius = 100/2
view.translatesAutoresizingMaskIntoConstraints = false
// let tapGesture = UITapGestureRecognizer(target : self, action : #selector(avatarImagePressHandler))
// view.isUserInteractionEnabled = true
// view.addGestureRecognizer(tapGesture)
return view
}()
let statusLabel: UILabel = {
let view = UILabel()
view.text = "Waiting for something"
view.font = UIFont.systemFont(ofSize: 14, weight: .regular)
view.textColor = .gray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let statusTextField: UITextField = {
let view = TextFieldWithPadding()
view.placeholder = "add smth to show as status"
view.layer.cornerRadius = 12
view.layer.borderWidth = 1
view.layer.borderColor = UIColor.black.cgColor
view.backgroundColor = .white
view.font = UIFont.systemFont(ofSize: 15, weight: .regular)
view.textColor = .black
view.backgroundColor = .white.withAlphaComponent(0)
view.addTarget(self, action: #selector(statusTextChanged), for : .editingChanged)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let setStatusButton: UIButton = {
let view = UIButton()
view.setTitle("Show status", for: .normal)
view.setTitleColor(.white, for : .normal)
view.backgroundColor = UIColor(named: "myColor")
view.layer.cornerRadius = 14
view.layer.shadowRadius = 4
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.7
view.layer.shadowOffset = CGSize(width: 4, height: 4)
view.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
setupViews()
}
#objc func avatarImagePressHandler()
{
print("avatar pressed")
}
#objc func buttonPressed()
{
statusLabel.text = statusText
}
#objc func statusTextChanged(_ textField: UITextField)
{
statusText = textField.text ?? ""
}
required init?(coder: NSCoder) {
fatalError("should not be called")
}
private func setupViews()
{
contentView.addSubview(avatarImage)
contentView.addSubview(fullNameLabel)
contentView.addSubview(statusLabel)
contentView.addSubview(statusTextField)
contentView.addSubview(setStatusButton)
let tapGesture = UITapGestureRecognizer(target : self, action : #selector(avatarImagePressHandler))
avatarImage.isUserInteractionEnabled = true
avatarImage.addGestureRecognizer(tapGesture)
let constraints = [
avatarImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
avatarImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
avatarImage.widthAnchor.constraint(equalToConstant: 100),
avatarImage.heightAnchor.constraint(equalToConstant: 100),
fullNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 27),
fullNameLabel.leadingAnchor.constraint(equalTo: avatarImage.trailingAnchor, constant: 16),
fullNameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
statusLabel.topAnchor.constraint(equalTo: fullNameLabel.bottomAnchor, constant: 10),
statusLabel.leadingAnchor.constraint(equalTo: fullNameLabel.leadingAnchor),
statusLabel.trailingAnchor.constraint(equalTo: fullNameLabel.trailingAnchor),
statusTextField.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 10),
statusTextField.heightAnchor.constraint(equalToConstant: 40),
statusTextField.leadingAnchor.constraint(equalTo: statusLabel.leadingAnchor),
statusTextField.trailingAnchor.constraint(equalTo: statusLabel.trailingAnchor),
setStatusButton.topAnchor.constraint(equalTo: avatarImage.bottomAnchor, constant: 16),
setStatusButton.leadingAnchor.constraint(equalTo: avatarImage.leadingAnchor),
setStatusButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
setStatusButton.heightAnchor.constraint(equalToConstant: 50)
]
NSLayoutConstraint.activate(constraints)
}
}
If I try to setup a tap gesture recognizer inside lambda I see no print inside the console, but if I configure it inside setupViews everything is fine. Why does it work this way? What am I missing?

Elements not adding to UIStackView , programmatically?

I was trying to make a sorting Visualizer in Live playground so I created a stack view but when I try to add UIView (as the sticks in that visualiser) they do not get added in my stackView , Below is my code
It is big but your are interested in mainStackview part only because that is the stackView where I wanna add that sticks(UIView), Also buildStartingArray() function (it is used to add the UIViews)
public class HomeViewController:UIViewController{
let stackView:UIStackView = {
let st = UIStackView()
st.axis = .horizontal
st.alignment = .center
st.distribution = .fill
// st.backgroundColor = .cyan
st.layer.shadowColor = UIColor.gray.cgColor
st.layer.shadowOffset = .zero
st.layer.shadowRadius = 5
st.layer.shadowOpacity = 1
st.spacing = 10
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let generateButton:UIButton = {
let btn = UIButton()
btn.setTitle("Generate Array", for: .normal)
btn.backgroundColor = UIColor(red: 0.92, green: 0.30, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let BubbleSort:UIButton = {
let btn = UIButton()
btn.setTitle("BubbleSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.41, green: 0.43, blue: 0.88, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let MergeSort:UIButton = {
let btn = UIButton()
btn.setTitle("MergeSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.10, green: 0.16, blue: 0.34, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let InsertionSort:UIButton = {
let btn = UIButton()
btn.setTitle("InsertionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.19, green: 0.22, blue: 0.32, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let SelectionSort:UIButton = {
let btn = UIButton()
btn.setTitle("SelectionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.51, green: 0.20, blue: 0.44, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let mainStackView:UIStackView = {
let st = UIStackView()
st.backgroundColor = .gray
st.axis = .horizontal
st.distribution = .fillEqually
st.alignment = .firstBaseline
st.spacing = 1
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let baseView:UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.07, green: 0.54, blue: 0.65, alpha: 1.00)
vw.translatesAutoresizingMaskIntoConstraints = false
vw.layer.cornerRadius = 3
vw.layer.masksToBounds = true
vw.heightAnchor.constraint(equalToConstant: 15).isActive = true
return vw
}()
public override func viewDidLoad() {
view.addSubview(mainStackView)
view.addSubview(stackView)
view.addSubview(baseView)
edgesForExtendedLayout = []
stackView.addArrangedSubview(generateButton)
stackView.addArrangedSubview(BubbleSort)
stackView.addArrangedSubview(MergeSort)
stackView.addArrangedSubview(InsertionSort)
stackView.addArrangedSubview(SelectionSort)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
baseView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -2).isActive = true
baseView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 5).isActive = true
baseView.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -5).isActive = true
mainStackView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 5).isActive = true
mainStackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5).isActive = true
mainStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: baseView.topAnchor, constant: -5).isActive = true
setButtons()
builStartingArray()
}
func setButtons(){
generateButton.addTarget(self, action: #selector(generatePressed), for: .touchUpInside)
BubbleSort.addTarget(self, action: #selector(bubbleSort), for: .touchUpInside)
MergeSort.addTarget(self, action: #selector(mergeSort), for: .touchUpInside)
InsertionSort.addTarget(self, action: #selector(insertionSort), for: .touchUpInside)
SelectionSort.addTarget(self, action: #selector(selectionSort), for: .touchUpInside)
}
func builStartingArray(){
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.frame.size = CGSize(width: 50, height: 150)
return v
}()
let viewStick2:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.frame.size = CGSize(width: 50, height: 150)
return v
}()
mainStackView.addArrangedSubview(viewStick)
mainStackView.addArrangedSubview(viewStick2)
}
}
Problem is the UIView that I add in buildStartingArray() function doesn't show up ,And
for now I have added only 2 view but in future I am planning to add 30-35 in mainStackView,
I want those UIViews to look like graph bars and the mainStackView is my graph
Here is the current output
the mainStackView is the one with gray background
Make main stackView to align bottom
You can try to adding a height for mainStack subviews like
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
in
func builStartingArray(){
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
let viewStick2:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
mainStackView.addArrangedSubview(viewStick)
mainStackView.addArrangedSubview(viewStick2)
}
All code
import UIKit
class ViewController:UIViewController{
let stackView:UIStackView = {
let st = UIStackView()
st.axis = .horizontal
st.alignment = .center
st.distribution = .fill
// st.backgroundColor = .cyan
st.layer.shadowColor = UIColor.gray.cgColor
st.layer.shadowOffset = .zero
st.layer.shadowRadius = 5
st.layer.shadowOpacity = 1
st.spacing = 10
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let generateButton:UIButton = {
let btn = UIButton()
btn.setTitle("Generate Array", for: .normal)
btn.backgroundColor = UIColor(red: 0.92, green: 0.30, blue: 0.29, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let BubbleSort:UIButton = {
let btn = UIButton()
btn.setTitle("BubbleSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.41, green: 0.43, blue: 0.88, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let MergeSort:UIButton = {
let btn = UIButton()
btn.setTitle("MergeSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.10, green: 0.16, blue: 0.34, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let InsertionSort:UIButton = {
let btn = UIButton()
btn.setTitle("InsertionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.19, green: 0.22, blue: 0.32, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let SelectionSort:UIButton = {
let btn = UIButton()
btn.setTitle("SelectionSort", for: .normal)
btn.backgroundColor = UIColor(red: 0.51, green: 0.20, blue: 0.44, alpha: 1.00)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.italicSystemFont(ofSize: 20)
btn.layer.cornerRadius = 10
btn.layer.masksToBounds = true
btn.heightAnchor.constraint(equalToConstant: 38).isActive = true
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let mainStackView:UIStackView = {
let st = UIStackView()
st.backgroundColor = .gray
st.axis = .horizontal
st.distribution = .fillEqually
st.alignment = .top
st.spacing = 1
st.translatesAutoresizingMaskIntoConstraints = false
return st
}()
let baseView:UIView = {
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.07, green: 0.54, blue: 0.65, alpha: 1.00)
vw.translatesAutoresizingMaskIntoConstraints = false
vw.layer.cornerRadius = 3
vw.layer.masksToBounds = true
return vw
}()
public override func viewDidLoad() {
view.addSubview(mainStackView)
view.addSubview(stackView)
view.addSubview(baseView)
edgesForExtendedLayout = []
stackView.addArrangedSubview(generateButton)
stackView.addArrangedSubview(BubbleSort)
stackView.addArrangedSubview(MergeSort)
stackView.addArrangedSubview(InsertionSort)
stackView.addArrangedSubview(SelectionSort)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
stackView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
baseView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -2).isActive = true
baseView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 5).isActive = true
baseView.rightAnchor.constraint(equalTo: view.rightAnchor,constant: -5).isActive = true
baseView.heightAnchor.constraint(equalToConstant: 15).isActive = true
mainStackView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 5).isActive = true
mainStackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5).isActive = true
mainStackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: baseView.topAnchor, constant: -5).isActive = true
builStartingArray()
}
func builStartingArray(){
let viewStick:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
let viewStick2:UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 150).isActive = true
return v
}()
mainStackView.addArrangedSubview(viewStick)
mainStackView.addArrangedSubview(viewStick2)
}
}

var constraints not appearing when assigned to a function that creates a view

I want my swift code to use var constraints to let the objects added to the code. I have added a gif below of what I am looking for. Right now the code below compiles but the black view you can see in the gif below is not appearing in the code below. In my code below the black box is not appearing at all.
import UIKit
public class ViewController : UIViewController {
var slider = UISlider()
var image1Width2: NSLayoutConstraint!
var iHieght: NSLayoutConstraint!
public override func viewDidLoad() {
super.viewDidLoad()
slider.value = 0.5
slider.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(slider)
slider.isUserInteractionEnabled = true
slider.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
slider.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1).isActive = true
slider.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1).isActive = true
button.frame = .init(x: self.view.bounds.midX,
y: 0,
width: 100,
height: 100)
self.view.addSubview(button)
image1Width2 = view.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.06)
iHieght = view.widthAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.06)
slider.addTarget(self, action: #selector(increase), for: .allEvents)
}
private lazy var button: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.setTitleColor(.white, for: .normal)
button.setTitle("add", for: .normal)
button.addTarget(self,
action: #selector(addBlackView),
for: .touchUpInside)
return button
}()
private func getBlackView() -> UIView {
let view = UIView()
view.backgroundColor = .black
image1Width2 = view.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.06)
iHieght = view.widthAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.06)
let recognizer = UIPanGestureRecognizer(target: self, action: #selector(moveView(_:)))
view.addGestureRecognizer(recognizer)
return view
}
#objc
private func addBlackView() {
let view = getBlackView()
self.view.addSubview(view)
}
#objc
private func moveView(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
print("gesture began")
case .changed:
let translation = recognizer.translation(in: self.view)
recognizer.view!.center = .init(x: recognizer.view!.center.x + translation.x,
y: recognizer.view!.center.y + translation.y)
recognizer.setTranslation(.zero, in: self.view)
default:
break
}
}
#objc func increase() {
image1Width2.constant = CGFloat(slider.value) * view.frame.size.width * 0.10
iHieght.constant = CGFloat(slider.value) * view.frame.size.width * 0.10
}
}
You are doing couple of mistakes when writing this code.Mainly iOS basic principles
Please refer this modified code, modify it and get your result.
class sampleViewController: UIViewController {
var image1Width2: NSLayoutConstraint!
var iHieght: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(slider)
slider.translatesAutoresizingMaskIntoConstraints = false
slider.value = 0.5
slider.isUserInteractionEnabled = true
NSLayoutConstraint.activate([
slider.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor),
slider.heightAnchor.constraint(equalToConstant: 100),
slider.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1),
])
view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
button.widthAnchor.constraint(equalToConstant: 100),
button.heightAnchor.constraint(equalToConstant: 80),
])
button.addTarget(self,action: #selector(addBlackView),for: .touchUpInside)
slider.addTarget(self, action: #selector(increase), for: .allEvents)
}
let slider:UISlider = {
let slider = UISlider(frame: .zero)
return slider
}()
private lazy var button: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.setTitleColor(.white, for: .normal)
button.setTitle("add", for: .normal)
return button
}()
let blackView: UIView = {
let view = UIView()
view.backgroundColor = .black
return view
}()
#objc
private func addBlackView() {
self.view.addSubview(blackView)
blackView.translatesAutoresizingMaskIntoConstraints = false
blackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
blackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
image1Width2 = blackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.1)
image1Width2.isActive = true
iHieght = blackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1)
iHieght.isActive = true
view.layoutIfNeeded()
let recognizer = UIPanGestureRecognizer(target: self, action: #selector(moveView(_:)))
blackView.addGestureRecognizer(recognizer)
}
#objc private func moveView(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
print("gesture began")
case .changed:
let translation = recognizer.translation(in: self.view)
recognizer.view!.center = .init(x: recognizer.view!.center.x + translation.x,
y: recognizer.view!.center.y + translation.y)
recognizer.setTranslation(.zero, in: self.view)
default:
break
}
}
#objc func increase() {
image1Width2.constant = CGFloat(slider.value) * view.frame.size.width * 0.10
iHieght.constant = CGFloat(slider.value) * view.frame.size.width * 0.10
}}