Search code examples
iosxcodeuibuttonrefreshios12

UIButton not refresh when updating


I have a big problem, I create an serial UIbutton when I click manually on a button, I change the background color and fill color, and unclick color change for normal state.

but when my program select a random button, sequence is good, but the button not change on real time and don't see what is button is selected (no background color, not fill color) I don't understand why , I see on other question a possibility with setNeedsDisplay, setEnable, .... but don't work for my ...

have you resolve this refresh problem ? how I refresh my button (button.setNeedsDisplay() not work)

see my program for see, I use soundEnd boolean value when my mp3 ending play and nextSound boolean value when my button is on normal state. Sleep is use for slow loop and wait mp3 play ending , if not multiple choice not work ... I found this solution but not for background and fill color

Thanks !

//
//  ViewController.swift
//  test
//
//  Created by Thierry on 03/06/2020.
//  Copyright © 2020 Thierry  All rights reserved.
//

import UIKit
let squareSize  = 100
let borderSpace = 20

class ViewController: UIViewController {
    


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        let zone3 = UIView(frame: CGRect(x: 10, y: 10, width: view.frame.width-20, height: view.frame.height-20))
        zone3.backgroundColor = .red
        view.addSubview(squareDraw(contentView: zone3))
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
        for randomInt in 1..<13 {
        print(randomInt)
        let subview = self.view.viewWithTag(randomInt)
        let button = subview as! UIButton
        
            button.sendActions(for: .touchDown)

            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            button.sendActions(for: .touchUpInside)
            }
            
            sleep(3)
        
        }
        }
    }
        
        func squareDraw(contentView : UIView) ->UIView {
                
                    let widthScreen: Int = Int(contentView.bounds.width)
                    let heightScreen: Int  = Int(contentView.bounds.height)
                
                    let scaleFactorX = (widthScreen*100/((3 * squareSize) + (4 * borderSpace)))
                    let scaleFactorY = (heightScreen*100/((4 * squareSize) + (5 * borderSpace)))
                
                    let squareSizeScaleX = (squareSize * scaleFactorX)/100
                    let squareSizeScaleY = (squareSize * scaleFactorY)/100
                    
                    let borderSpaceScaleX = (borderSpace * scaleFactorX)/100
                    let borderSpaceScaleY = (borderSpace * scaleFactorY)/100
                
                
                let originY = 0
                var Tag = 0
                for yCoord in 1...4 {
                    for xCoord in 1...3 {
                        Tag = Tag + 1
                        let k = button(CGRect(x: xCoord * (squareSizeScaleX + borderSpaceScaleX) - squareSizeScaleX, y: originY + (yCoord * (squareSizeScaleY + borderSpaceScaleY) - squareSizeScaleY), width: squareSizeScaleX, height: squareSizeScaleY), tag: Tag)
                        contentView.addSubview(k)

                    }
                }
                return contentView

            }
            
        func button(_ rect: CGRect, tag: Int) ->UIView {

                let myButton = UIButton(type: .system)
                myButton.frame = CGRect(x:CGFloat(rect.minX), y:CGFloat(rect.minY), width:CGFloat(rect.width), height:CGFloat(rect.height))
                myButton.tag = tag
                myButton.backgroundColor = .white
                myButton.layer.borderWidth = 5
                myButton.layer.borderColor = UIColor.white.cgColor
                myButton.addTarget(self, action: #selector(buttonSelected), for: .touchUpInside)
                myButton.addTarget(self, action: #selector(buttonReleased), for: .touchDown )
                return myButton
                
        }
        
      
    @objc func buttonSelected(sender: UIButton) {
                let button = sender
                
                if button.isSelected == true {
                   
                } else {
             
                      button.layer.borderWidth = 5
                      button.layer.borderColor = UIColor.white.cgColor
                               
                }
            
            }
        
    @objc func buttonReleased(sender: UIButton) {
              
                let button = sender
             
                if button.isEnabled == true {

                    button.layer.borderWidth = 5
                    button.layer.borderColor = UIColor.black.cgColor
          
                } else {
                    
                }
            }

 
        
  


}


Solution

  • First you never want to use sleep(2) - it freezes your program for 2 seconds, and nothing else can happen. There are rare exceptions, but you definitely do not want that here.

    It's still a bit confusing what you really want to do. Your question says "soundEnd boolean value when my mp3 ending play"?

    So, here is an example - using some of your code.

    • on viewDidLoad()
      • draw a grid of 12 white buttons on a red background
    • on viewDidAppear()
      • start a sound playing
      • set the border of the first button to black
    • when the sound stops
      • set the button border back to white
      • start the second sound
      • set the border of the second button to black

    This will loop through the number of sound clips you have:

    class SoundTestViewController: UIViewController, AVAudioPlayerDelegate {
    
        let squareSize  = 100
        let borderSpace = 20
    
        var myPlayer: AVAudioPlayer = AVAudioPlayer()
    
        // start at -1 so first call to "play next" will increment it to 0
        var soundNumber: Int = -1
    
        // replace with your mp3 file names
        let mp3FileNames: [String] = [
            "clip1",
            "clip2",
            "clip3",
            "clip4",
        ]
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            let zone3 = UIView(frame: CGRect(x: 10, y: 10, width:   view.frame.width-20, height: view.frame.height-20))
            zone3.backgroundColor = .red
            view.addSubview(squareDraw(contentView: zone3))
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            playNextSoundFile()
        }
    
        func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
            player.stop()
            if let subview = self.view.viewWithTag(soundNumber + 1) as? UIButton {
                subview.layer.borderColor = UIColor.white.cgColor
            }
            playNextSoundFile()
        }
    
        func playNextSoundFile() {
            soundNumber += 1
            if soundNumber > mp3FileNames.count - 1 {
                soundNumber = 0
            }
    
            guard let url = Bundle.main.url(forResource: mp3FileNames[soundNumber], withExtension: ".mp3") else {
                // mp3 file not found in bundle
                return
            }
    
            do {
                if let subview = self.view.viewWithTag(soundNumber + 1) as? UIButton {
                    subview.layer.borderColor = UIColor.black.cgColor
                }
    
                let sound = try AVAudioPlayer(contentsOf: url)
    
                self.myPlayer = sound
    
                // set the audio player delegate to self
                sound.delegate = self
    
                sound.numberOfLoops = 0
                sound.prepareToPlay()
                sound.play()
            } catch {
                print("error initializing audio player")
            }
        }
    
    
        func squareDraw(contentView : UIView) ->UIView {
    
            let widthScreen: Int = Int(contentView.bounds.width)
            let heightScreen: Int  = Int(contentView.bounds.height)
    
            let scaleFactorX = (widthScreen*100/((3 * squareSize) + (4 * borderSpace)))
            let scaleFactorY = (heightScreen*100/((4 * squareSize) + (5 * borderSpace)))
    
            let squareSizeScaleX = (squareSize * scaleFactorX)/100
            let squareSizeScaleY = (squareSize * scaleFactorY)/100
    
            let borderSpaceScaleX = (borderSpace * scaleFactorX)/100
            let borderSpaceScaleY = (borderSpace * scaleFactorY)/100
    
            let originY = 0
            var Tag = 0
            for yCoord in 1...4 {
                for xCoord in 1...3 {
                    Tag = Tag + 1
                    let k = button(CGRect(x: xCoord * (squareSizeScaleX + borderSpaceScaleX) - squareSizeScaleX, y: originY + (yCoord * (squareSizeScaleY + borderSpaceScaleY) - squareSizeScaleY), width: squareSizeScaleX, height: squareSizeScaleY), tag: Tag)
                    contentView.addSubview(k)
    
                }
            }
    
            return contentView
        }
    
        func button(_ rect: CGRect, tag: Int) ->UIView {
    
            let myButton = UIButton(type: .system)
            myButton.frame = CGRect(x:CGFloat(rect.minX), y:CGFloat(rect.minY), width:CGFloat(rect.width), height:CGFloat(rect.height))
            myButton.tag = tag
            myButton.backgroundColor = .white
            myButton.layer.borderWidth = 5
            myButton.layer.borderColor = UIColor.white.cgColor
    
            return myButton
        }
    
    }
    

    If that is not really what you are trying to do, maybe it will at least get you in the right direction.