Swift: How to change views' background from other views

本小妞迷上赌 提交于 2020-01-03 03:06:49

问题


My task is to create an app where I can change and save the background. I wanted to do something more elaborate, so I decided to create a color menu that allows me to change all of the views' backgrounds. Now, I have the menu, and I know how to set and save pictures/ colours in the background. But I don't know how to do it from a view controller to another. Right now my code changes its own view's background. This is my code (I know it's a lot...):

First of all I have 2 extensions that allows me to 1) save the UIColor with user defaults; 2) use rgb colours:

//MARK: - Extension for rgb
extension UIColor {
    convenience init(red: Int, green: Int, blue: Int) {
        assert(red >= 0 && red <= 255, "Invalid red component")
        assert(green >= 0 && green <= 255, "Invalid green component")
        assert(blue >= 0 && blue <= 255, "Invalid blue component")

        self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
    }

    convenience init(rgb: Int) {
        self.init(
            red: (rgb >> 16) & 0xFF,
            green: (rgb >> 8) & 0xFF,
            blue: rgb & 0xFF
        )
    }
}


//MARK: - Extension to save colors
extension UserDefaults {
    func setColor(color: UIColor?, forKey key: String) {
        var colorData: NSData?
        if let color = color {
            do {
                colorData = try NSKeyedArchiver.archivedData(withRootObject: color, requiringSecureCoding: false) as NSData?
                set(colorData, forKey: key)
            } catch let error {
                print("error archiving color data", error)
            }
        }
    }

    func colorForKey(key: String) -> UIColor? {
        var color: UIColor?
        if let colorData = data(forKey: "Background") {
            do{
                color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: colorData)
            } catch let error {
                print("error unarchivig color data", error)
            }
        }
        return color
    }

}

My viewDidLoad:

var defaults = UserDefaults.standard
private let backgroundKey = "backg"
 override func viewDidLoad() {
        super.viewDidLoad()


        //MARK: - Background Settings


        let color = defaults.colorForKey(key: backgroundKey)
        view.backgroundColor = color

        if let backgroundImage = self.getSavedBackgroundImage() {
            self.backgroundImageView.image = backgroundImage
        }
}

Code that allows me to set a picture as background

@IBOutlet weak var backgroundImageView: UIImageView!
//I KNOW THIS HAS TO BE PUT IN THE VC WHERE I WANT THE BACKGROUND TO BE CHANGED
 @IBAction func pictureButton(_ sender: Any) {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        imagePicker.allowsEditing = false
        present(imagePicker, animated: true, completion: nil)
    }
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            backgroundImageView.image = image
            let _ = self.saveBackgroundImage(image: image)

        }

        self.dismiss(animated: true, completion: nil)

    }
    func saveBackgroundImage(image: UIImage) -> Bool {
        guard let data = image.pngData() ?? backgroundImageView.image?.pngData() else {
            return false
        }
        guard let directory = FileManager.default.urls(for: .documentDirectory,
                                                       in: .userDomainMask).first else {
                                                        return false
        }
        do {
            try data.write(to: directory.appendingPathComponent("MainBackgroound.png"))
            return true
        } catch {
            print(error.localizedDescription)
            return false
        }
    }

    func getSavedBackgroundImage() -> UIImage? {
        if let dir = FileManager.default.urls(for: .documentDirectory,
                                              in: .userDomainMask).first {
            return UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent("MainBackgroound.png").path)
        }
        return nil
    }

    func deleteImage() {
        let fileManager = FileManager.default
        let yourProjectImagesPath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("MainBackgroound.png")
        if fileManager.fileExists(atPath: yourProjectImagesPath) {
            try! fileManager.removeItem(atPath: yourProjectImagesPath)
        }
        let yourProjectDirectoryPath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("MainBackgroound.png")
        if fileManager.fileExists(atPath: yourProjectDirectoryPath) {
            try! fileManager.removeItem(atPath: yourProjectDirectoryPath)
        }
    }

Code that allows me to change background's color

@IBAction func lightPinkButton(_ sender: Any) {
        self.deleteImage()
        let lightPink = UIColor(red: 255, green: 215, blue: 214).withAlphaComponent(1)
        defaults.setColor(color: lightPink, forKey: backgroundKey)
        view.backgroundColor = lightPink
    }

回答1:


How about you create a base view controller, something like ColorViewController and in there you have a reference to the background color and then just inherit from that and update it wherever you need.

Like this

ColorViewController

class ColorViewController: UIViewController {

    var myBackgroundColor: UIColor = .white

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

ViewControllerOne

class ViewControllerOne: ColorViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        view.backgroundColor = myBackgroundColor
    }

    @IBAction func blueButtonTapped(_ sender: Any) {
        myBackgroundColor = .blue
        view.backgroundColor = myBackgroundColor
    }

}

ViewControllerTwo

class ViewControllerTwo: ColorViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        view.backgroundColor = myBackgroundColor
    }

    @IBAction func purpleButton(_ sender: Any) {
        myBackgroundColor = .purple
        view.backgroundColor = myBackgroundColor
    }

}



回答2:


You should make a Notification for when your background color changes and for when your background image changes. Any ViewController that is supposed to be themed needs to listen for these notifications and update itself accordingly:

//Make your custom notification
extension Notification.Name {
    static let backgroundColorUpdated = Notification.Name("backgroundColorUpdated")
}

//Post the notification when you update backgroundColor
NotificationCenter.default.post(Notification(name: .backgroundColorUpdated, object: nil, userInfo: ["backgroundColor": UIColor.red]))

//Subscribe everywhere that needs to be interested in backgroundColor changes
var token: NSObjectProtocol? // retain token for life of subscription, ie as long as you vc exists
...
token = NotificationCenter.default.addObserver(forName: .backgroundColorUpdated, object: nil, queue: .main) { notification in
    guard let backgroundColor = notification.userInfo?["backgroundColor"] as? UIColor else {
        return
    }
    //Do stuff with backgroundColors here
}



来源:https://stackoverflow.com/questions/55401038/swift-how-to-change-views-background-from-other-views

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!