【问题标题】:Applying a shadow to a subview loaded from nib对从 nib 加载的子视图应用阴影
【发布时间】:2018-12-11 23:34:25
【问题描述】:

我正在从viewWillAppear 的笔尖加载自定义视图类。加载笔尖后,我将其添加为子视图,然后应用一些约束,然后更新约束。那时我尝试向这个视图添加阴影,但没有显示阴影....

仅在某些情况下,ViewController 具有包含contentView 的滚动视图。所有视图的内容都在这个contentView 中。

这是我的代码:

视图控制器

class MyViewController: UIViewController {

    @IBOutlet weak var contentView: UIView!

    var matches: [Match] = []
    var matchViews: [MatchDetailsView] = []

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

        setMatches()
    }

    func setMatches() {

        // Match One
        let matchOneDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 0 ? matches[0] : nil, delegate: self, tag: 1)
        contentView.addSubview(matchOneDetailsView)
        matchOneDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchOneLeadingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchOneTrailingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchOneTopConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 32)

        // Match Two
        let matchTwoDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 1 ? matches[1] : nil, delegate: self, tag: 2)
        contentView.addSubview(matchTwoDetailsView)
        matchTwoDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchTwoLeadingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchTwoTrailingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchTwoTopConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .top, relatedBy: .equal, toItem: matchOneDetailsView, attribute: .bottom, multiplier: 1, constant: 32)

        // Match Three
        let matchThreeDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 2 ? matches[2] : nil, delegate: self, tag: 3)
        contentView.addSubview(matchThreeDetailsView)
        matchThreeDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchThreeLeadingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchThreeTrailingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchThreeTopConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .top, relatedBy: .equal, toItem: matchTwoDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
        let matchThreeBottomConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -32)

        NSLayoutConstraint.activate([matchOneLeadingConstraint, matchOneTrailingConstraint, matchOneTopConstraint, matchTwoLeadingConstraint, matchTwoTrailingConstraint, matchTwoTopConstraint, matchThreeLeadingConstraint, matchThreeTrailingConstraint, matchThreeTopConstraint, matchThreeBottomConstraint])

        updateViewConstraints()

        matchViews.append(matchOneDetailsView)
        matchViews.append(matchTwoDetailsView)
        matchViews.append(matchThreeDetailsView)

        styleMatchViews()
    }


    func styleMatchViews() {
        for view in matchViews {
            view.addShadow(opacity: 0.25, yOffset: 0, xOffset: 0, radius: 5.0)
            view.roundCorners(withRadius: 5.0)
        }
    }
}

MatchDetailsView

class MatchDetailsView: UIView {

        class func instanceFromNib(match: Match?, delegate: MatchDetailsViewDelegate, tag: Int) -> MatchDetailsView {

        let view = UINib(nibName: "MatchDetailsView", bundle: nil).instantiate(withOwner: MatchDetailsView(), options: nil)[0] as! MatchDetailsView
        view.translatesAutoresizingMaskIntoConstraints = false
        view.updateMatchContent()
        return view
    }
}

UIViewExtension

extension UIView {

/**
 Add Shadow

 Puts a Drop Shadow in the UIView
 */
func addShadow(opacity: Float, yOffset: Int, xOffset: Int, radius: CGFloat) {
        self.layer.masksToBounds = false
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOpacity = opacity
        self.layer.shadowOffset = CGSize(width: xOffset, height: yOffset)
        self.layer.shadowRadius = radius
        self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
    }
}

如果MatchDetailsView 的 nib 文件将“clipsToBounds”设置为 false,为什么加载页面时我的影子没有出现?我是否错过了 layout 函数,即使它们的布局似乎正确?

【问题讨论】:

    标签: ios swift uiview nslayoutconstraint


    【解决方案1】:

    您正在将 .shadowPath 设置为视图的边界...但在自动布局布局视图之后,该点的边界可能不是(可能不会是)边界。

    对于“阴影视图”,最好将阴影设置在视图本身的layoutSubviews() 中。

    您还应该在 viewDidLoad() 中添加和设置您的子视图 viewWillAppear() 可能会被多次调用(取决于您的导航),您最终会添加多个子视图副本。

    所以...

    像这样更改您的 MatchDetailsView 类:

    class MatchDetailsView: UIView {
    
        var opacity: CGFloat = 0.0
        var xOffset: CGFloat = 0.0
        var yOffset: CGFloat = 0.0
    
        // for the shadowRadius
        var sRadius: CGFloat = 0.0
    
        // for the cornerRadius
        var cRadius: CGFloat = 0.0
    
        override func layoutSubviews() {
    
            self.layer.masksToBounds = false
    
            self.layer.shadowColor = UIColor.black.cgColor
            self.layer.shadowOpacity = Float(opacity)
            self.layer.shadowOffset = CGSize(width: xOffset, height: yOffset)
            self.layer.shadowRadius = sRadius
            self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
    
            self.layer.cornerRadius = cRadius
        }
    
        class func instanceFromNib(match: Match?, delegate: MatchDetailsViewDelegate, tag: Int) -> MatchDetailsView {
    
            let view = UINib(nibName: "MatchDetailsView", bundle: nil).instantiate(withOwner: MatchDetailsView(), options: nil)[0] as! MatchDetailsView
            view.translatesAutoresizingMaskIntoConstraints = false
            view.updateMatchContent()
            return view
        }
    
    }
    

    然后,在您的视图控制器中:

    override func viewDidLoad() {
        super.viewDidLoad()
        setMatches()
    }
    
    func setMatches() {
    
        // Match One
        let matchOneDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 0 ? matches[0] : nil, delegate: self, tag: 1)
        contentView.addSubview(matchOneDetailsView)
        matchOneDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchOneLeadingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchOneTrailingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchOneTopConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 32)
    
        // Match Two
        let matchTwoDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 1 ? matches[1] : nil, delegate: self, tag: 2)
        contentView.addSubview(matchTwoDetailsView)
        matchTwoDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchTwoLeadingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchTwoTrailingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchTwoTopConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .top, relatedBy: .equal, toItem: matchOneDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
    
        // Match Three
        let matchThreeDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 2 ? matches[2] : nil, delegate: self, tag: 3)
        contentView.addSubview(matchThreeDetailsView)
        matchThreeDetailsView.translatesAutoresizingMaskIntoConstraints = false
        let matchThreeLeadingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
        let matchThreeTrailingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
        let matchThreeTopConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .top, relatedBy: .equal, toItem: matchTwoDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
        let matchThreeBottomConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -32)
    
        NSLayoutConstraint.activate([matchOneLeadingConstraint, matchOneTrailingConstraint, matchOneTopConstraint, matchTwoLeadingConstraint, matchTwoTrailingConstraint, matchTwoTopConstraint, matchThreeLeadingConstraint, matchThreeTrailingConstraint, matchThreeTopConstraint, matchThreeBottomConstraint])
    
        matchViews.append(matchOneDetailsView)
        matchViews.append(matchTwoDetailsView)
        matchViews.append(matchThreeDetailsView)
    
        styleMatchViews()
    }
    
    
    func styleMatchViews() {
        for view in matchViews {
            view.opacity = 0.25
            view.yOffset = 0.0
            view.xOffset = 0.0
            view.sRadius = 5.0
            view.cRadius = 5.0
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-01
      • 1970-01-01
      • 2015-09-19
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      相关资源
      最近更新 更多