UIButton,允许点击传递到下面的按钮

问题描述 投票:0回答:1

enter image description here

我创建此图像是为了说明我的问题。

我有一个按钮,按住时会将背景更改为粉红色。 然后在两个按钮之间显示一个视图来显示视图。 然后顶部的另一个按钮添加内部阴影。

我无法让两个目标同时工作。

这可以实现吗?

我尝试使用 HitTest 但没有成功,因为它将点击传递给下面的按钮,但随后第一个按钮失去了目标。

我正在考虑使用 UIViews 来实现与我在按钮目标内使用图层来实现我想要的效果相同的效果。

我只需要两个可以同时接收触摸的视图。我更喜欢 UIButton 解决方案,因为按住触摸几乎是瞬时的,而长按手势需要一些时间才能生效。

我已经解决这个问题很长一段时间了,所以我决定寻求一些帮助。

ios uiview uibutton
1个回答
0
投票

您(可能)可以通过使用

UIView
并处理触摸而不是使用
UIButton
...

更轻松地完成此操作

首先,让我们创建一个基本的“触摸时更改背景”视图:

class HighlightView: UIView {
    
    // very light gray
    var normalColor: UIColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1.0)
    
    // light pink
    var hightlightColor: UIColor = UIColor(red: 1.0, green: 0.9, blue: 1.0, alpha: 1.0)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        backgroundColor = normalColor
    }
    func doHighlight(_ b: Bool) {
        backgroundColor = b ? hightlightColor : normalColor
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        backgroundColor = hightlightColor
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let t = touches.first else { return }
        let pt = t.location(in: self)

        // if touch is inside my bounds
        //  use highlight color
        // else, touch moved outside so
        //  use normal color
        
        if bounds.contains(pt) {
            backgroundColor = hightlightColor
        } else {
            backgroundColor = normalColor
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        backgroundColor = normalColor
    }
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        backgroundColor = normalColor
    }
    
}

带有示例视图控制器:

class TouchHoldVC: UIViewController {
    
    let holdView = HighlightView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        holdView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(holdView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            holdView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            holdView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            holdView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            holdView.heightAnchor.constraint(equalToConstant: 200.0),
        ])
        
    }
    
}

init
我们将背景颜色设置为“正常”...

  • 当我们第一次触摸视图时 -
    touchesBegan
    - 我们将背景颜色设置为“突出显示”
  • 如果我们将触摸移到视图之外,请将其设置回“正常”
  • 如果我们回到视图中,将其设置为“突出显示”
  • 在修饰(或取消)时,将其设置回“正常”

看起来像这样:

enter image description here


接下来我们可以创建一个“内阴影视图”类:

class InnerShadowView: UIView {
    
    // "inner" shadow
    private let innerShadowLayer = CAShapeLayer()
    private let innerShadowMaskLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() -> Void {
        
        // add sublayer
        self.layer.addSublayer(innerShadowLayer)

        // fillColor doesn't matter - just needs to be opaque
        innerShadowLayer.fillColor = UIColor.white.cgColor
        innerShadowLayer.fillRule = .evenOdd

    }
    
    override func layoutSubviews() {
        
        super.layoutSubviews()
        
        // for the "inner" shadow,
        // rectangle path needs to be larger than
        //  bounds + shadow offset + shadow raidus
        // so the shadow doesn't "bleed" from all sides
        let path = UIBezierPath(rect: bounds.insetBy(dx: -40, dy: -40))
        
        // create a path for the "hole" in the layer
        let holePath = UIBezierPath(rect: bounds)
        
        // this "cuts a hole" in the path
        path.append(holePath)
        path.usesEvenOddFillRule = true
        
        innerShadowLayer.path = path.cgPath
        
        // mask the layer, so we only "see through the hole"
        innerShadowMaskLayer.path = holePath.cgPath
        innerShadowLayer.mask = innerShadowMaskLayer
        
        // adjust properties as desired
        innerShadowLayer.shadowOffset = .zero
        innerShadowLayer.shadowColor = UIColor.black.cgColor
        innerShadowLayer.shadowRadius = 5
        
        // setting .shadowOpacity to a very small value (such as 0.025)
        //  results in very light shadow
        // set .shadowOpacity to 1.0 to clearly see
        //  what the shadow is doing
        innerShadowLayer.shadowOpacity = 0.75
        
    }
    
}

通过添加

HighlightView
作为子视图来修改
InnerShadowView

class HighlightView: UIView {
    
    var normalColor: UIColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1.0)
    var hightlightColor: UIColor = UIColor(red: 1.0, green: 0.9, blue: 1.0, alpha: 1.0)
    
    let shadView = InnerShadowView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        
        shadView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(shadView)
        
        let g = self
        NSLayoutConstraint.activate([
            shadView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            shadView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            shadView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            shadView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        
        backgroundColor = normalColor
        shadView.isHidden = true
    }
    
    func doHighlight(_ b: Bool) {
        backgroundColor = b ? hightlightColor : normalColor
        shadView.isHidden = !b
        
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(true)
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let t = touches.first else { return }
        let pt = t.location(in: self)
        if bounds.contains(pt) {
            doHighlight(true)
        } else {
            doHighlight(false)
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(false)
    }
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(false)
    }
        
}

现在使用相同的示例控制器:

  • 当我们第一次触摸视图时 -
    touchesBegan
    - 我们将背景颜色设置为“突出显示”并且我们显示阴影视图
  • 如果我们将触摸移到视图之外,请将其设置回“正常”并隐藏阴影视图
  • 如果我们回到视图中,将其设置为“突出显示”并显示阴影视图
  • 在修饰(或取消)时,将其设置回“正常”并隐藏阴影视图

看起来像这样:

enter image description here


接下来,一个带有图像和标签的简单“内容视图”:

class SomeContentView: UIView {

    let label = UILabel()
    let imgView = UIImageView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        
        imgView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(imgView)
        
        let pad: CGFloat = 8.0
        let g = self
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: pad),
            label.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 12.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -16.0),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -pad),
            
            imgView.topAnchor.constraint(equalTo: g.topAnchor, constant: pad),
            imgView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: pad),
            //imgView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            imgView.widthAnchor.constraint(equalToConstant: 80.0),
            imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1.0),
            imgView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -pad),
        ])
        
        label.numberOfLines = 0
        label.textAlignment = .center
        label.text = "This an image view and a label, in a view we will call \"SomeContentView\""
        
        if let img = UIImage(named: "test300x300") {
            imgView.image = img
        }
    }

}

它本身看起来像这样:

enter image description here

我们将向我们的

HighlightView
--
func addContent(_ cView: UIView)
-- 添加一个函数,这样我们就可以将其添加为子视图:

class HighlightView: UIView {
    
    var normalColor: UIColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1.0)
    var hightlightColor: UIColor = UIColor(red: 1.0, green: 0.9, blue: 1.0, alpha: 1.0)
    
    let shadView = InnerShadowView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        
        shadView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(shadView)
        
        let g = self
        NSLayoutConstraint.activate([
            shadView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            shadView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            shadView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            shadView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        
        backgroundColor = normalColor
        shadView.isHidden = true
    }
    
    func doHighlight(_ b: Bool) {
        backgroundColor = b ? hightlightColor : normalColor
        shadView.isHidden = !b
        
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(true)
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let t = touches.first else { return }
        let pt = t.location(in: self)
        if bounds.contains(pt) {
            doHighlight(true)
        } else {
            doHighlight(false)
        }
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(false)
    }
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        doHighlight(false)
    }
    
    func addContent(_ cView: UIView) {
        
        cView.translatesAutoresizingMaskIntoConstraints = false
        insertSubview(cView, at: 0)
        
        let g = self
        NSLayoutConstraint.activate([
            cView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            cView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            cView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            cView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        
    }
    
}

并对示例控制器进行一些更改 - 我们将添加

SomeContentView
的实例并让它的约束设置高度:

class TouchHoldVC: UIViewController {
    
    let holdView = HighlightView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        holdView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(holdView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            holdView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            holdView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            holdView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            // the content view will set the height of the "touch hold" Highlight view
            //holdView.heightAnchor.constraint(equalToConstant: 200.0),
        ])
        
        holdView.addContent(SomeContentView())

    }
    
}

我们得到这个:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.