My swift code right now uses func addbox to append imageviews to a empty array of imageviews.
When the user taps button widthActivatorBtn it should allow the user to select on a imageview and change the width of the imageveiew. It works but only if the widthActivatorBtn was selected and selectNum is changed to 3.
I can affect imageview placed on after selectNum was changed to 3 but not the imageviews before it. Check out my gif and you can see the problem. When selectNum is changed to 3 all imageviews should be able to have their width changed via slider.
import UIKit
class ViewController: UIViewController {
var slider = UISlider()
var ht = -90
var widthSize = 80
var emptyArray = [UIImageView]()
var addImageview = UIButton()
var width = UIButton()
var currentView: UIView?
var selectNum = Int()
override func viewDidLoad() {
super.viewDidLoad()
[addImageview,slider,width].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
addImageview.setTitle("add imageview", for: .normal)
width.setTitle("change width", for: .normal)
addImageview.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 160, height: 40)
slider.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 160, height: 40)
width.frame = CGRect(x: view.center.x-115, y: view.center.y + 100, width: 160, height: 40)
addImageview.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
width.addTarget(self, action: #selector(widthActivatorBtn), for: .touchUpInside)
slider.addTarget(self, action: #selector(ji), for: .valueChanged)
slider.minimumValue = 10
slider.maximumValue = 150
}
#objc func widthActivatorBtn() {
width.backgroundColor = .systemPink
selectNum = 3
}
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
emptyArray.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(widthSize), height: 35)
subview.backgroundColor = .purple
ht += 50
emptyArray.append(subview)
if selectNum == 3{
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
}
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
#objc func ji(sender : UISlider){
widthSize = Int(slider.value)
currentView?.bounds.size.width = CGFloat(slider.value)
}
}
remove selectNum variable, it is causing the problem.
when you are creating the first image at that time selectNum is not equal to 3, so that the gesture is not added to the first imageView, but after cliking on width button selectNum set to value 3 and after that when you create any imageview then that imageView gets the gesture and you width logic works.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
emptyArray.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(widthSize), height: 35)
subview.backgroundColor = .purple
ht += 50
emptyArray.append(subview)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
#objc func widthActivatorBtn() {
width.backgroundColor = .systemPink
selectNum = 3
}
#objc func ji(sender : UISlider){
if selectNum == 3 {
widthSize = Int(slider.value)
currentView?.bounds.size.width = CGFloat(slider.value)
}
}
add the condition selectNum == 3 in ji func, to resize. and you can reset selectNum somewhere to stop resizing.
so now when widthActivatorBtn will be pressed then only width will change.
hope this will work for you.
Related
I have 3 images, I need to implement them with animation. How i can display each image separately on the screen using a loop? help me please
class ViewController: UIViewController {
var imageArray: [UIImage] = [UIImage(named: "1")!, UIImage(named: "2")!, UIImage(named: "3")!]
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(handleTimer), userInfo: nil, repeats: false)
}
private func setImageSettings(to image: UIImage?) -> UIImageView {
let pictureParams = UIImageView(image: image)
pictureParams.frame.size = CGSize(width: 400, height: 300)
pictureParams.center = view.center
pictureParams.contentMode = .scaleAspectFit
view.addSubview(pictureParams)
return pictureParams
}
func moveImages(_ targetView: UIImageView) {
UIImageView.animate(withDuration: 2, delay: 0, options: [], animations: {targetView.frame.origin = CGPoint(x: targetView.frame.origin.x + 320, y: targetView.frame.origin.y )}, completion: nil)
}
func sortImages() {
for image in imageArray{
moveImages(setImageSettings(to: image))
}
}
#objc private func handleTimer(_ sender: Timer) {
sortImages()
}
}
Assuming you want to animate one image at a time, appearing in the middle of your view controller's view, and then moving up to the top of the view, you could change your code like this:
class ViewController: UIViewController {
var imageIndex = 0
var imageArray: [UIImage] = [UIImage(named: "1")!, UIImage(named: "2")!, UIImage(named: "3")!]
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
let timer: Timer? = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(handleTimer), userInfo: nil, repeats: true)
}
private func setImageSettings(to image: UIImage?) -> UIImageView {
let pictureParams = UIImageView(image: image)
pictureParams.frame.size = CGSize(width: 400, height: 300)
pictureParams.center = view.center
pictureParams.contentMode = .scaleAspectFit
view.addSubview(pictureParams)
return pictureParams
}
func moveImages(_ targetView: UIImageView) {
UIImageView.animate(withDuration: 2, delay: 0, options: [], animations: {targetView.frame.origin = CGPoint(x: targetView.frame.origin.x + 320, y: targetView.frame.origin.y )}, completion: nil)
}
func animateImages() {
// Fetch an image from the array
let image = imageArray[imageIndex]
// Create the animation for that image
moveImages(setImageSettings(to: image))
// Move on to the next image index
imageIndex += 1
// If we are past the end of the array, stop.
if imageIndex == imagesArray.count {
timer.invalidate()
}
}
#objc private func handleTimer(_ sender: Timer) {
animateImages()
}
}
enter image description here> I make the word game, the problem is this. When the word is big, the
cells come out of the screen, I need these cells to move below the
other cells and be centered. and the cells should have a fixed width =
20. that's all in my application Help implement.
p.s. I tried to add elements to the stackview, but the space between the words did not appear in the stackview
1. TileView.swift
import UIKit
protocol TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint)
}
class TileView: UIImageView {
var letter: Character?
var isMatch = false
private var xOffset: CGFloat = 0.0
private var yOffset: CGFloat = 0.0
var dragDelegate: TileDragDelegateProtocol?
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
// super.init(frame: scale)
// let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
let image = UIImage(named: "tile")
super.init(image: image)
let scale = sideLength / (image?.size.width)!
self.frame = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
// self.frame = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
//self.layer.cornerRadius = 23
//self.clipsToBounds = true
let letterLabel = UILabel(frame: self.bounds)
letterLabel.textAlignment = .center
letterLabel.textColor = .white
letterLabel.backgroundColor = .clear
letterLabel.text = String(letter).uppercased()
letterLabel.font = .boldSystemFont(ofSize: 40.0 / 3) //.systemFont(ofSize: 78.0 / 3/*scale*/)
//letterLabel.layer.cornerRadius = 23
//letterLabel.clipsToBounds = true
// self.backgroundColor = .red
// self.textAlignment = .center
// self.textColor = .white
// self.backgroundColor = .black
// self.text = String(letter).uppercased()
// self.font = .boldSystemFont(ofSize: 50.0 / 3)
self.addSubview(letterLabel)
self.isUserInteractionEnabled = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
xOffset = point.x - self.center.x
yOffset = point.y - self.center.y
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
self.center = CGPoint(x: point.x - xOffset, y: point.y - yOffset)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchesMoved(touches, with: event)
dragDelegate?.tileView(tileView: self, didDragToPoint: self.center)
}
}
2.TargetView.swift
import UIKit
class TargetView: UILabel {
var letter: Character!
var isMatch = false
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let image = UIImage(named: "slot")
//super.init(image: image)
//let scale = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
super.init(frame: CGRect(x: 0, y: 0, width: 15, height: 30))
self.backgroundColor = .red
self.textAlignment = .center
self.font = .boldSystemFont(ofSize: 60.0 / 3)
self.text = "_"//String(letter).uppercased()
self.textColor = .white
self.lineBreakMode = .byWordWrapping
self.adjustsFontSizeToFitWidth = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
3. ViewController
import UIKit
class ViewController: UIViewController {
// let ScreenWidth = UIScreen.main.bounds.size.width
// let ScreenHeight = UIScreen.main.bounds.size.height
//frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
//var gameView = UIView()
private var tiles = [TileView]()
private var targets = [TargetView]()
let tileMargin : CGFloat = 0.0
var words = "Hellomyf rie nds?"
// lazy var stackView: UIStackView = {
// let stack = UIStackView()
// stack.axis = .horizontal
// stack.spacing = 0
// stack.distribution = .fillEqually
// stack.translatesAutoresizingMaskIntoConstraints = false
// return stack
// }()
//
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
dealRandomAnagram()
}
func dealRandomAnagram() {
let anagram1 = words
let anagram1length = anagram1.count
print("phrase1[\(anagram1length)]: \(anagram1)")
// Рассчет размера плитки //Tile size calculation
let tileSize = ceil(UIScreen.main.bounds.size.width * 0.8 / CGFloat(min(anagram1length, anagram1length))) + tileMargin // * 1
//Поиск х позиции первой плитки // Finding x position of the first tile
var xOffset = (UIScreen.main.bounds.size.width - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//let yOffset = (UIScreen.main.bounds.size.height - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//настройка центра плитки (вместо источника плитки)
xOffset += tileSize / 2.0
tiles = []
// создание плитки
for (index, letter) in anagram1.enumerated() {
if letter != " " {
let tile = TileView(letter: letter, sideLength: tileSize)
tile.center = CGPoint(x: xOffset + CGFloat(index) * (tileSize + tileMargin), y: UIScreen.main.bounds.size.height/4*3)
view.addSubview(tile)
tile.dragDelegate = self
tiles.append(tile)
}
}
targets = []
for (index,letter) in anagram1.enumerated() {
let target = TargetView(letter: letter, sideLength: 15)
if letter != " " || index > 15 {
// let target = TargetView(letter: letter, sideLength: 15)
target.center = CGPoint(x: xOffset + CGFloat(index) /* * 20 */ * (15 + tileMargin), y: UIScreen.main.bounds.size.height - 100) //100 //UIScreen.main.bounds.size.height - CGFloat(index) * 50
view.addSubview(target)
targets.append(target)
//stackView.addArrangedSubview(target)
//targets.append(target)
}
}
}
//xOffset + CGFloat(index) /* * 20 */ * (tileSize + tileMargin )
//UIScreen.main.bounds.size.height - 100
func placeTile(tileView: TileView, targetView: TargetView) {
tileView.isMatch = true
targetView.isMatch = true
tileView.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.35, delay: 0.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
tileView.center = targetView.center
tileView.backgroundColor = .clear
targetView.transform = .identity
}, completion: {
(value: Bool) in
targetView.isHidden = true
})
}
func checkValidate() {
for targetView in targets {
if !targetView.isMatch {
return
}
}
print("Valid")
}
}
extension ViewController: TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint) {
var targetView: TargetView?
for tv in targets {
if tv.frame.contains(didDragToPoint) && !tv.isMatch {
targetView = tv
break
}
}
if let targetView = targetView {
//2 check if letter matches
if targetView.letter == tileView.letter {
//3
self.placeTile(tileView: tileView, targetView: targetView)
print("Success! You should place the tile here!")
//more stuff to do on success here
self.checkValidate()
print("Check if the player has completed the phrase")
} else {
//4
UIView.animate(withDuration:0.35,
delay:0.00,
options :UIView.AnimationOptions.curveEaseOut,
animations: {
tileView.center = CGPoint(x: tileView.center.x,
y: tileView.center.y - (200))
},
completion: nil)
print("Failure. Let the player know this tile doesn't belong here")
//more stuff to do on failure here
}
}
}
}
My swift code uses a button to place imageviews on a uiviewcontroller that parent from a empty array. The problem is I dont know how to effect the size of the invidicual imageview after it is placed on the uiview controller. When a imageview is click and then when the slider is moved the imageview should change size. However what is happening is the value when the slider is changed effects the next iamgeview that is placed on the uiviewcontroller. Pitcure below is included I circled what the slider should effect. This is a video of what I am trying to do https://www.youtube.com/watch?v=ho6ID6XVEYw&feature=youtu.be.
import UIKit
class ViewController: UIViewController {
var sx = UISlider()
var count: Int = 0
var ht = -90
var ww = 80
var arrTextFields = [UIImageView]()
var b7 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
[b7,sx].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
b7.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 70, height: 40)
sx.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 70, height: 40)
b7.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
}
//func that adds imageview.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
sx.addTarget(self, action: #selector(ji), for: .valueChanged)
sx.minimumValue = 10
sx.maximumValue = 150
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(ww), height: 35)
subview.backgroundColor = .purple
subview.tag = count
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestured(_:)))
subview.addGestureRecognizer(pan)
count += 1
ht += 50
arrTextFields.append(subview)
}
#objc func handlePanGestured(_ gesture: UIPanGestureRecognizer) {
let draggedView = gesture.view!
view.bringSubviewToFront(draggedView)
let translation = gesture.translation(in: view)
draggedView.center = CGPoint(x: draggedView.center.x + translation.x, y: draggedView.center.y + translation.y)
gesture.setTranslation(.zero, in: view)
}
#objc func ji(sender : UISlider){
ww = Int(sx.value)
}}
The main idea that needs to be implemented is to add the currentView variable to find out which view we want to change.
We also need to add some functionality to select the specific view that needs to be changed.
1) Add variable currentView
class ViewController: UIViewController {
...
var currentView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
2) Add tapGestureRecognozer to func addBOx()
#objc func addBOx() {
...
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
3) Add handleTapGestured(_:)
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
4) Update func ji(sender: UISlider)
#objc func ji(sender: UISlider) {
...
currentView?.bounds.size.width = CGFloat(sx.value)
}
All code:
import UIKit
class ViewController: UIViewController {
var sx = UISlider()
var count: Int = 0
var ht = -90
var ww = 80
var arrTextFields = [UIImageView]()
var b7 = UIButton()
var currentView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
[b7,sx].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
b7.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 70, height: 40)
sx.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 70, height: 40)
b7.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
}
//func that adds imageview.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
sx.addTarget(self, action: #selector(ji), for: .valueChanged)
sx.minimumValue = 10
sx.maximumValue = 150
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(ww), height: 35)
subview.backgroundColor = .purple
subview.tag = count
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestured(_:)))
subview.addGestureRecognizer(pan)
count += 1
ht += 50
arrTextFields.append(subview)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
#objc func handlePanGestured(_ gesture: UIPanGestureRecognizer) {
let draggedView = gesture.view!
view.bringSubviewToFront(draggedView)
let translation = gesture.translation(in: view)
draggedView.center = CGPoint(x: draggedView.center.x + translation.x, y: draggedView.center.y + translation.y)
gesture.setTranslation(.zero, in: view)
}
#objc func ji(sender : UISlider){
ww = Int(sx.value)
currentView?.bounds.size.width = CGFloat(sx.value)
}
}
Alternatively, you can add a textField and write the number that the element from your array needs to change.
And please, don't use variables like sx, ht, ww, b7 in your code.
You can read API Design Guidelines here
I found this ready code that prints out an already stored array called (let dataArr = ["25","51","57","73","68"]) in rows into a label.
I have now made a text field that can insert to another array(my array = String) I want this array to be swaped with the first array.
But know when I swap to empty array that has already been populated via a text field it doesn’t appear in label.
I was hoping to swap the dataArr to an empty array called array that files up with data when inserted via the text field but for reason when I am doing that it doesn’t get shown in the label I am posting now to see what I am doing wrong.
But when I print the array it appears in the console but not in the label.
let dataArr = ["2,5","5,1","5,7"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<dataArr.count {
let element = dataArr[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
Ran your code and got the following result.
Is this what you were expecting?
UPDATE :
Here's what whipped up.
lazy var myText: UITextField = {
let input = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
input.backgroundColor = .white
input.placeholder = "Enter data here!"
return input
}()
lazy var enterButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("ENTER", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnEnter), for: .touchUpInside)
return button
}()
lazy var doneButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("Done", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnDone), for: .touchUpInside)
return button
}()
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if (!array.isEmpty) {
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
myText.removeFromSuperview()
enterButton.removeFromSuperview()
doneButton.removeFromSuperview()
self.view.addSubview(labelNum)
}
}
else
{
view.backgroundColor = .green
setUpMyText()
setUpEnterButton()
setUpDoneButton()
}
}
private func setUpMyText() {
self.view.addSubview(myText)
myText.translatesAutoresizingMaskIntoConstraints = false
myText.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
myText.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
myText.widthAnchor.constraint(equalToConstant: myText.bounds.width).isActive = true
myText.heightAnchor.constraint(equalToConstant: myText.bounds.height).isActive = true
}
private func setUpEnterButton() {
self.view.addSubview(enterButton)
enterButton.translatesAutoresizingMaskIntoConstraints = false
enterButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
enterButton.topAnchor.constraint(equalTo: myText.bottomAnchor, constant: 10).isActive = true
}
private func setUpDoneButton() {
self.view.addSubview(doneButton)
doneButton.translatesAutoresizingMaskIntoConstraints = false
doneButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
doneButton.topAnchor.constraint(equalTo: enterButton.bottomAnchor, constant: 10).isActive = true
}
#objc fileprivate func btnEnter() {
print(myText)
array.append(myText.text!)
myText.text = ""
}
#objc fileprivate func btnDone() {
print("Done")
self.viewDidLoad()
}
I have a problem updating my CollectionView after values in an array changed. I made a short gif of my problem.
As you can see I can add goals for both teams in my soccer app. When I press the game statistic button for the first time, the result (e.g. 2:1) in the statistic view sliding in from the bottom, is correct. But as the game goes on and the home team scores again, the statistics won’t change.
I have tried several ways to call reloaddata() to update my collectionView, with no success so far. So hopefully someone can get me on the right track.
Thank you very much in advance.
GameStatistics View Controller - GameStatistics.swift
import UIKit
class StatisticTitle: NSObject {
let name: String
init(name: String) {
self.name = name
}
}
class HomeTeamValue: NSObject {
var value: Int
init(value: Int) {
self.value = value
}
}
class AwayTeamValue: NSObject {
var value: Int
init(value: Int) {
self.value = value
}
}
class GameStatistics: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let blackView = UIView()
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
return cv
}()
let cellId = "cellId"
let sectionHeader = "sectionHeader"
let sectionFooter = "sectionFooter"
let cellHeight: CGFloat = 40
let headerHeight: CGFloat = 80
let footerHeight: CGFloat = 50
let cellSpacing: CGFloat = 0
let statisticTitles: [StatisticTitle] = {
return[
StatisticTitle(name: "Goals"), //Tore
StatisticTitle(name: "Shots on Target"), //Schüsse aufs Tor
StatisticTitle(name: "Shots off Target"), //Schüsse neben das Tor
StatisticTitle(name: "Free Kicks"), //Freistöße
StatisticTitle(name: "Corner Kicks"), //Eckbälle
StatisticTitle(name: "Fouls"), //Fouls
StatisticTitle(name: "Offside / Centerline"), //Abseits / Mittellinie
StatisticTitle(name: "Cautions")] //Cautions Strafen
}()
lazy var homeTeamValues: [HomeTeamValue] = {
[ HomeTeamValue(value: homeGoals),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0),
HomeTeamValue(value: 0)
]
}()
lazy var awayTeamValues: [AwayTeamValue] = {
[ AwayTeamValue(value: awayGoals),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0),
AwayTeamValue(value: 0)
]
}()
func showStatistics() {
if let window = UIApplication.shared.keyWindow {
blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
window.addSubview(blackView)
window.addSubview(collectionView)
// Dynamic Height of Collection View
let value: CGFloat = CGFloat(statisticTitles.count)
let height: CGFloat = value * cellHeight + (value - 1) * cellSpacing + headerHeight + footerHeight
let y = window.frame.height - height
blackView.frame = window.frame
collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: height)
blackView.alpha = 0
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackView.alpha = 1
self.collectionView.frame = CGRect(x: 0, y: y, width: self.collectionView.frame.width, height: self.collectionView.frame.height)
}, completion: nil)
}
}
#objc func handleDismiss() {
UIView.animate(withDuration: 0.5) {
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow {
self.collectionView.frame = CGRect(x: 0, y: window.frame.height, width: self.collectionView.frame.width, height: self.collectionView.frame.height)
}
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return statisticTitles.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! GameStatisticCell
let title = statisticTitles[indexPath.item]
cell.statisticTitle = title
let homeValue = homeTeamValues[indexPath.item]
cell.homeTeamValue = homeValue
let awayValue = awayTeamValues[indexPath.item]
cell.awayTeamValue = awayValue
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: cellHeight)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return cellSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return cellSpacing
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: sectionHeader, for: indexPath)
return supplementaryView
case UICollectionElementKindSectionFooter:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: sectionFooter, for: indexPath)
return supplementaryView
default:
fatalError("Unexpected element kind")
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: headerHeight)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: footerHeight)
}
override init() {
super.init()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(GameStatisticCell.self, forCellWithReuseIdentifier: cellId)
collectionView.register(GameStatisticHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: sectionHeader)
collectionView.register(GameStatisticFooter.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: sectionFooter)
}
}
GameStatistic Cell - GameStatisticCell.swift
import UIKit
class GameStatisticCell: BaseCell {
let statisticTitleLabel: UILabel = {
let label = UILabel()
label.text = "Shots on Goal"
label.textColor = ColorCodes.darkGray
label.textAlignment = .center
label.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
return label
}()
var statisticTitle: StatisticTitle? {
didSet { statisticTitleLabel.text = statisticTitle?.name }
}
let homeTeamStatistic: UILabel = {
let label = UILabel()
label.text = String(12)
label.textColor = ColorCodes.darkGray
label.textAlignment = .right
label.font = UIFont(name: "HelveticaNeue-CondensedBold", size: 20)
return label
}()
var valueHomeTeam: Int = 1
var homeTeamValue: HomeTeamValue? {
didSet {
homeTeamStatistic.text = homeTeamValue?.value.description
valueHomeTeam = (homeTeamValue?.value)!
print(valueHomeTeam)
}
}
let awayTeamStatistic: UILabel = {
let label = UILabel()
label.text = String(2)
label.textColor = ColorCodes.darkGray
label.textAlignment = .left
label.font = UIFont(name: "HelveticaNeue-CondensedBold", size: 20)
return label
}()
var valueAwayTeam: Int = 1
var awayTeamValue: AwayTeamValue? {
didSet {
awayTeamStatistic.text = awayTeamValue?.value.description
valueAwayTeam = (awayTeamValue?.value)!
print(valueAwayTeam)
}
}
var homeTeamStatisticBar: UIView = {
let view = UIView()
view.backgroundColor = UIColor.lightGray
return view
}()
var awayTeamStatisticBar: UIView = {
let view = UIView()
view.backgroundColor = UIColor.darkGray
return view
}()
override func setupCell() {
super.setupCell()
backgroundColor = .white
addSubview(statisticTitleLabel)
addSubview(homeTeamStatistic)
addSubview(awayTeamStatistic)
addSubview(homeTeamStatisticBar)
addSubview(awayTeamStatisticBar)
let statisticValueSum = valueHomeTeam + valueAwayTeam
print(statisticValueSum)
let barWidthHome = CGFloat((Int(pitchWidth! / 2) - 40) * valueHomeTeam / statisticValueSum)
let barWidthAway = CGFloat((Int(pitchWidth! / 2) - 40) * valueAwayTeam / statisticValueSum)
let barCenter = pitchWidth! / 2
statisticTitleLabel.anchor(top: nil, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 4, paddingRight: 0, width: 0, height: 0)
addConstraint(NSLayoutConstraint(item: statisticTitleLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
homeTeamStatisticBar.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 4, paddingLeft: 0, paddingBottom: 0, paddingRight: barCenter, width: barWidthHome, height: 16)
awayTeamStatisticBar.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 4, paddingLeft: barCenter, paddingBottom: 0, paddingRight: 0, width: barWidthAway, height: 16)
homeTeamStatistic.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
awayTeamStatistic.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 20, width: 0, height: 0)
}
}
Statistic Button - TimerBar.swift
var homeGoals: Int = 0 {
didSet {
GameStatistics().collectionView.reloadData()
}
}
var awayGoals: Int = 0 {
didSet {
GameStatistics().collectionView.reloadData()
}
}
class TimerBar: UIView {
[...] //more Code
let homeGoalsLabel: UILabel = {
let label = UILabel()
label.text = String(homeGoals)
label.textColor = UIColor.white
label.textAlignment = .right
label.font = UIFont(name: "HelveticaNeue-CondensedBold", size: 34)
return label
}()
let awayGoalsLabel: UILabel = {
let label = UILabel()
label.text = String(awayGoals)
label.textColor = UIColor.white
label.textAlignment = .left
label.font = UIFont(name: "HelveticaNeue-CondensedBold", size: 34)
return label
}()
[...] //more Code
//Handle Menu Buttons
let changeLineUp = ChangeLineUp()
var delegate: LineUpDelegate?
var pitchLayout: String = "Test"
#objc func lineUpButtonTapped() {
changeLineUp.showLineUps()
changeLineUp.delegate = self
}
let gameStatistics = GameStatistics()
#objc func statButtonTapped() {
gameStatistics.showStatistics()
}
#objc func homeTeamButtonTapped(_ sender:UIButton!) {
homeGoals = homeGoals + 1
homeGoalsLabel.text = String(homeGoals)
}
#objc func awayTeamButtonTapped(_ sender:UIButton!) {
awayGoals = awayGoals + 1
awayGoalsLabel.text = String(awayGoals)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
...
Main Pitch View - PitchViewController.swift
import UIKit
let lineup7_321: UICollectionViewLayout = LineUp7_3_2_1()
public var pitchCollectionView: UICollectionView? = {
var layout: UICollectionViewLayout = lineup7_321
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
//cv.dataSource = self
//cv.delegate = self
return cv
}()
class PitchViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId1 = "PlayersCell"
let cellId2 = "SubstituteCell"
let timerBar: TimerBar = {
let tb = TimerBar()
return tb
}()
//Just for testing
let sections: [String] = ["Players", "Substitutes"]
let players: [String] = ["player1", "player2", "player3", "player4", "player5", "player6", "player7"]
let substitutes: [String] = ["player8", "player9", "player10", "player12", "player13"]
var sectionData: [Int: [String]] = [:]
//Swap Players
var alwaysSwapWithOrigin: Bool!
var placementTimer: DispatchSourceTimer!
var longPress: UILongPressGestureRecognizer!
var movingPlayer: (origin:IndexPath?,lifted:IndexPath?,placement:IndexPath?,previous:IndexPath?)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = UIImageView(image: #imageLiteral(resourceName: "overtime"))
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = UIColor.white
setupTimerBar()
setupPitchCollectionView()
setupSwapPlayers()
}
func setupTimerBar() {
view.addSubview(timerBar)
timerBar.anchor(top: view.safeAreaLayoutGuide.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 135)
}
func setupPitchCollectionView() {
pitchCollectionView?.register(PlayersCell.self, forCellWithReuseIdentifier: cellId1)
pitchCollectionView?.register(SubstituteCell.self, forCellWithReuseIdentifier: cellId2)
pitchCollectionView?.delegate = self
pitchCollectionView?.dataSource = self
pitchCollectionView?.isScrollEnabled = false
view.addSubview(pitchCollectionView!)
pitchCollectionView?.backgroundColor = ColorCodes.lightGreen
pitchCollectionView?.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 135, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
sectionData = [0: players, 1: substitutes]
}
func setupSwapPlayers() {
alwaysSwapWithOrigin = true
longPress = UILongPressGestureRecognizer(target: self, action:#selector(swapPlayersCells))
longPress.minimumPressDuration = 0.20
pitchCollectionView?.addGestureRecognizer(longPress)
let queue = DispatchQueue(label: "com.overtime")
placementTimer = DispatchSource.makeTimerSource(flags: [],queue:queue)
placementTimer.schedule(deadline: .now(), repeating:.milliseconds(250))
placementTimer.setEventHandler(handler: playersPositionUpdate)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return sections.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (sectionData[section]?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.section {
case 0:
let playerCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId1, for: indexPath) as! PlayersCell
playerCell.playerImage.image = UIImage(named: self.players[indexPath.row])
playerCell.playerName.text = self.players[indexPath.row].capitalized
return playerCell
case 1:
let substituteCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId2, for: indexPath) as! SubstituteCell
substituteCell.substituteImage.image = UIImage(named: self.substitutes[indexPath.row])
substituteCell.substituteName.text = self.substitutes[indexPath.row].capitalized
return substituteCell
default:
fatalError("Error")
}
}
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// required for interactive movement
}
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
// return the index path of selected to prevent other cells reshuffling whilst moving cell around
return movingPlayer.lifted!
}
}
I didn't see any declaration for Home/Away values, this is a sample I hope you can get the idea from it
private var homeGoals : Int = 0 {
didSet {
collectionView.reloadData()
}
}
private var awayGoals : Int = 0 {
didSet {
collectionView.reloadData()
}
}
#objc func homeTeamButtonTapped(_ sender: UIButton) {
homeGoals = homeGoals + 1
}
As you can see here any new value for homeGoals variable collectionView will be reloaded immediately and you have to use in your cell