简体   繁体   中英

Remove gradient from subview on rotation

I can remove the gradient from the subview fine, But If a button is added to the subview I can not remove the gradient layer. How can I Remove gradient from subview on rotation.

Here is the code for the View Controller.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var buttonOutlet: UIButton!
    @IBOutlet weak var labelOutlet: UILabel!
    @IBOutlet weak var mySubView: UIView!   
    @IBOutlet weak var mySubView2: UIView!
    @IBOutlet weak var mySubView3: UIView!

    override func viewDidLayoutSubviews() {
         addGradient()
    }

    fileprivate func addGradient() {
        mySubView.mainGradientBackground()
        mySubView2.subGradientBackground()
        mySubView3.subGradientBackground()
        labelOutlet.labelTextfieldShadow()
        buttonOutlet.buttonGradientBackground(cornerRadius: 10, shadowRadius: 3)
    }

     /// This will let you know when the device rotates.
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
       if UIDevice.current.orientation.isValidInterfaceOrientation {

            removeSublayer(mySubView, layerIndex: 0)
            removeSublayer(mySubView, layerIndex: 0)

            removeSublayer(mySubView2, layerIndex: 0)
            removeSublayer(mySubView2, layerIndex: 0)

            removeSublayer(mySubView3, layerIndex: 0)
            removeSublayer(mySubView3, layerIndex: 0)

            removeSublayer(buttonOutlet, layerIndex: 0)
            removeSublayer(buttonOutlet, layerIndex: 0)

            removeSublayer(labelOutlet, layerIndex: 0)
        }
    }


    func removeSublayer(_ view: UIView, layerIndex index: Int) {
        guard let sublayers = view.layer.sublayers else {
            print("The view does not have any sublayers.")
            return
        }
        if sublayers.count > index {
            view.layer.sublayers!.remove(at: index)
        } else {
            print("There are not enough sublayers to remove that index.")
        }
    }
}

This is the Gradient Extension used to color any views I need.

import Foundation
import UIKit

extension UIView {
    /// Use this to set a gradient for the background.
    /// = This is a gradient with no shadow.
    func mainGradientBackground() {
        let color = Color()

        let leading = color.backgroundLeading
        let trailing = color.backgroundTrailing

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = [leading, trailing]
        gradientLayer.locations = [0,0.3]
        gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)

        layer.insertSublayer(gradientLayer, at: 0)
    }

    /// Use this to set a gradient for the background.
    /// = This is a gradient with a shadow.
     func subGradientBackground() {

        let corner: CGFloat = 15
        let color = Color()

        let leading = color.subBackgroundLeading
        let trailing = color.subBackgroundTrailing
        let borderColor = color.subBorderColor

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = [leading, trailing]
        gradientLayer.locations = [0,0.3,1]
        gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
        gradientLayer.borderColor = borderColor
        gradientLayer.borderWidth = 4
        gradientLayer.cornerRadius = corner
        layer.insertSublayer(gradientLayer, at: 0)

        let subLayer = CALayer()
        subLayer.frame = bounds
        subLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: corner - 2).cgPath
        subLayer.shadowColor = UIColor.red.cgColor
        subLayer.shadowOpacity = 1
        subLayer.shadowRadius = 2

        subLayer.shadowOffset = CGSize(width: 3, height: 4)

        layer.insertSublayer(subLayer, at: 0)
    }

      /// Use this to set a gradient for the background.
      /// = This is a gradient with a shadow.
      func subGradientBackgroundShadow() {

          let corner: CGFloat = 15

          let subLayer = CALayer()
          subLayer.frame = bounds
          subLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: corner - 2).cgPath
          subLayer.shadowColor = UIColor.red.cgColor
          subLayer.shadowOpacity = 1
          subLayer.shadowRadius = 2

          subLayer.shadowOffset = CGSize(width: 3, height: 4)

          layer.insertSublayer(subLayer, at: 0)
      }


    /// LabelShadow
    /// - Parameter masksToBounds: Keep the layer in its bound
    /// - Exp.. Set to true to keep text in textview in its frame.
    /// - Exp.. Set to false to let shadow out side the frame.
    /// - Defalr corner radius is 7
    func labelTextfieldShadow() {
        let color = Color()

        let dark = color.labelBackgroundDark
        let borderColor = color.labelBorderColor

        layer.masksToBounds = false
        layer.borderWidth = 0.5
        layer.borderColor = borderColor
        layer.cornerRadius = 7
        self.backgroundColor = dark

        layer.shadowRadius = 7
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOffset = CGSize(width: 3, height: 3)
        layer.shadowOpacity = 0.6
    }



    /// Button gradient
    /// - Parameter cornerRadius: Set the radius of the button. Use outlet height / 2
    /// - Parameter shadowRadius: Set the shadow radius. 2
    func buttonGradientBackground(cornerRadius: CGFloat, shadowRadius: CGFloat) {
        let color = Color()

        let leading = color.buttonLeading
        let middle = color.buttonMiddle
        let trailing = color.buttonTrailing
        let borderColor = color.buttonBorderColor

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = [leading, middle, trailing]
        gradientLayer.locations = [0,0.3,1]
        gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
        gradientLayer.borderColor = borderColor
        gradientLayer.borderWidth = 1
        gradientLayer.cornerRadius = cornerRadius
        layer.insertSublayer(gradientLayer, at: 0)

        let subLayer = CALayer()
        subLayer.frame = bounds
        subLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius - 2).cgPath
        subLayer.shadowColor =  UIColor.black.cgColor
        subLayer.shadowOpacity = 1
        subLayer.shadowRadius = shadowRadius
        subLayer.shadowOffset = CGSize(width: 2, height: 3)
        layer.insertSublayer(subLayer, at: 0)
    }
}

Here is four screen shots of the screen.

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

This is a color struct to color all of the views.. Main view, Sub view, Labels and Buttons.

struct Color {

    // Use these colors to style the main background.
    /// This color is used for the main view's background leading greadient color.
    let backgroundLeading = #colorLiteral(red: 0.2745098039, green: 0.231372549, blue: 0.231372549, alpha: 1).cgColor

    /// TThis color is used for the main view's background trailing greadient color.
    let backgroundTrailing = #colorLiteral(red: 0.2784313725, green: 0.2352941176, blue: 0.2352941176, alpha: 1).cgColor



    // Use these colors to style the sub view.
    /// This color is used for the sub view's leading greadient color.
    let subBackgroundLeading = #colorLiteral(red: 0.1960784314, green: 0.2549019608, blue: 0.2549019608, alpha: 1).cgColor

    /// This color is used for the sub view's trailing greadient color.
    let subBackgroundTrailing = #colorLiteral(red: 0.1012082246, green: 0.2111029723, blue: 0.1947238818, alpha: 1).cgColor

    /// This color is used for the sub view's border.
    let subBorderColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1).cgColor



    // Use these colors to style the labels.
    /// This color is used for editing text background.
    let labelBackgroundLight = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1) as UIColor

    /// This color is used for disabled text background.
    let labelBackgroundDark = #colorLiteral(red: 0.1843137255, green: 0.137254902, blue: 0.1384684741, alpha: 1) as UIColor

    /// This color is used for the label's border.
    let labelBorderColor = #colorLiteral(red: 0.6, green: 0.6, blue: 0.6, alpha: 1).cgColor



    // Use these colors to style the buttons.
    /// This color is used for the button's leading greadient color.
    let buttonLeading = #colorLiteral(red: 0.1960784314, green: 0.2549019608, blue: 0.2549019608, alpha: 1).cgColor

    /// This color is used for the button's middle greadient color.
    let buttonMiddle = #colorLiteral(red: 0.2, green: 0.2, blue: 0.2, alpha: 1).cgColor

    /// This color is used for the button's trailing greadient color.
    let buttonTrailing = #colorLiteral(red: 0.1012082246, green: 0.2111029723, blue: 0.1947238818, alpha: 1).cgColor

    /// This color is used for the button's border color.
    let buttonBorderColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1).cgColor


    // Use these colors for the text
    /// This color is used for the deiabled label and text field.
    let labelDisableColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)

    /// This color is used for the enabled label and text field.
    let labelEnableColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

    /// The text color white.
    let labelWhiteTextColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)

    /// The text color Black
    let labelBlackTextColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
}

Instead of assuming that a layer is at a given index, just retain the laters you want to remove as an instance variable (or in an array of CALayers) and then tell the layer(s) to remove themselves from their super layer.

For example:

var layersToRemoveLater = [CALayer]()
...
layersToRemoveLater.append(someLayer)
layersToRemoveLater.append(someOtherLayer)
...
layersToRemoveLater.forEach { $0.removeFromSuperLayer() }

The way to do this was to change each one of the extension to a class. With extension you have to take care of all of the layout your self. By using these as a class you can set each Button, Sub view Ect... in the storyboard, this way the view itself will redrawing the layout.

/// Use this to set a greadient for the background.
/// = This is a greadient with no shadow.
class MainGradientView: UIView {

 override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
}

private func setupView() {
    autoresizingMask = [.flexibleWidth, .flexibleHeight]

    guard let gradientLayer = self.layer as? CAGradientLayer else {
        return;
    }
    let color = Color()

    let leading = color.backgroundLeading
    let trailing = color.backgroundTrailing

    gradientLayer.frame = bounds
    gradientLayer.colors = [leading, trailing]
    gradientLayer.locations = [0,0.3]
    gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
}

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}


}





/// Use this to set a greadient for the background.
/// = This is a greadient with a shadow.
class SubGradientView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
}

private func setupView() {
    autoresizingMask = [.flexibleWidth, .flexibleHeight]

    guard let gradientLayer = self.layer as? CAGradientLayer else {
        return;
    }

    let corner: CGFloat = 15
    let color = Color()

    let leading = color.subBackgroundLeading
    let trailing = color.subBackgroundTrailing
    let borderColor = color.subBorderColor

    gradientLayer.frame = self.bounds
    gradientLayer.colors = [leading, trailing]
    gradientLayer.locations = [0,0.3,1]
    gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
    gradientLayer.borderColor = borderColor
    gradientLayer.borderWidth = 0.4
    gradientLayer.cornerRadius = corner

    self.layer.shadowColor = UIColor.black.cgColor
    self.layer.shadowOpacity = 1
    self.layer.shadowRadius = 2
    self.layer.shadowOffset = CGSize(width: 3, height: 4)
}

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}
}



/// Use this to set a greadient for the background.
/// = This is a greadient with no shadow.
class TabBarGradientView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
}

private func setupView() {
    autoresizingMask = [.flexibleWidth, .flexibleHeight]

    guard let gradientLayer = self.layer as? CAGradientLayer else {
        return;
    }


    let color = Color()

    let leading = color.buttonLeading
    let middle = color.buttonMiddle
    let trailing = color.buttonTrailing
    let borderColor = color.buttonBorderColor

    gradientLayer.frame = bounds
    gradientLayer.colors = [leading, middle, trailing]
    gradientLayer.locations = [0,0.3,1]
    gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
    gradientLayer.borderColor = borderColor
    gradientLayer.borderWidth = 1
    gradientLayer.cornerRadius = self.frame.width / 50
}

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}
}


/// Use this to set a greadient for the background.
/// = This is a greadient with a shadow.
class ButtonGradientView: UIButton {

override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
}

private func setupView() {
    autoresizingMask = [.flexibleWidth, .flexibleHeight]

    guard let gradientLayer = self.layer as? CAGradientLayer else {
        return;
    }


    let color = Color()

    let leading = color.buttonLeading
    let middle = color.buttonMiddle
    let trailing = color.buttonTrailing
    let borderColor = color.buttonBorderColor

    gradientLayer.frame = bounds
    gradientLayer.colors = [leading, middle, trailing]
    gradientLayer.locations = [0,0.3,1]
    gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
    gradientLayer.borderColor = borderColor
    gradientLayer.borderWidth = 1
    gradientLayer.cornerRadius = self.frame.height / 2

    self.layer.frame = bounds
    self.layer.shadowColor =  UIColor.black.cgColor
    self.layer.shadowOpacity = 1
    self.layer.shadowRadius = 2
    self.layer.shadowOffset = CGSize(width: 2, height: 3)
}

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}
}


/// Use this to set a greadient for the keypad switch.
/// = This is a greadient with a shadow.
class SwitchGradientView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setupView()
}

private func setupView() {
    autoresizingMask = [.flexibleWidth, .flexibleHeight]

    guard let gradientLayer = self.layer as? CAGradientLayer else {
        return;
    }


    let color = Color()

    let leading = color.buttonLeading
    let middle = color.buttonMiddle
    let trailing = color.buttonTrailing
    let borderColor = color.buttonBorderColor

    gradientLayer.frame = bounds
    gradientLayer.colors = [leading, middle, trailing]
    gradientLayer.locations = [0,0.3,1]
    gradientLayer.startPoint = CGPoint(x: 0.05, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
    gradientLayer.borderColor = borderColor
    gradientLayer.borderWidth = 1
    gradientLayer.cornerRadius = 9

    self.layer.frame = bounds
    self.layer.shadowColor =  UIColor.black.cgColor
    self.layer.shadowOpacity = 1
    self.layer.shadowRadius = 2
    self.layer.shadowOffset = CGSize(width: 2, height: 3)
}

override class var layerClass: AnyClass {
    return CAGradientLayer.self
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM