首页 > 解决方案 > How to add "inner padding" into custom view so that its size will become smaller visually yet able retain its touchable area?

问题描述

I have the a custom view with the following simple constraint

  1. Height 88
  2. Width 88
  3. Center X
  4. Center Y

enter image description here

I tend to make it as circle visually. Here's my code.

extension UIView {
    func asCircle() {
        self.layer.cornerRadius = self.frame.width / 2;
        self.layer.masksToBounds = true
    }
}

class ViewController: UIViewController {

    @IBOutlet weak var circleView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        circleView.backgroundColor = .red
        circleView.asCircle()
        
        // 1. create a gesture recognizer (tap gesture)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
        
        // 2. add the gesture recognizer to a view
        circleView.addGestureRecognizer(tapGesture)
        
        // Currently, the touchable area of circleView is 88 x 88
    }

    // 3. this method is called when a tap is recognized
    @objc func handleTap(sender: UITapGestureRecognizer) {
        print("tap")
    }

}

What I would like to have is

  1. The touchable area of the circle remains 88 x 88
  2. The red circle however will look visually as 22 x 22

I add the following code, but it doesn't make any change

// We use 33, because 88-33-33 = 22
circleView.layoutMargins = UIEdgeInsets(top: 33, left: 33, bottom: 33, right: 33)

Does anyone know how to achieve so? Preferable without overriding draw function, or add an additional UIView as subview.

标签: iosswift

解决方案


将图层添加到您的 circleView 并清除 circleView 示例:

extension UIView {
        func asCircle() {
            self.layer.cornerRadius = self.frame.width / 2;
            self.layer.masksToBounds = true
        }
    }
    
    class ViewController: UIViewController {
    
        var circleView: UIView = {
            let circle = UIView()
            circle.translatesAutoresizingMaskIntoConstraints = false
            return circle
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.view.addSubview(self.circleView)
            
            circleView.backgroundColor = .clear
            self.circleView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
            self.circleView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
            
            let width = NSLayoutConstraint(item: self.circleView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1.0, constant: 88)
            
            let height = NSLayoutConstraint(item: self.circleView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: 88)
            self.circleView.addConstraints([width, height])
            self.circleView.layoutIfNeeded()
            
            // 1. create a gesture recognizer (tap gesture)
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
            
            // 2. add the gesture recognizer to a view
            circleView.addGestureRecognizer(tapGesture)
            
            // Currently, the touchable area of circleView is 88 x 88
        }
    
        // 3. this method is called when a tap is recognized
        @objc func handleTap(sender: UITapGestureRecognizer) {
            print("tap")
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            
            let layer = CALayer()
            layer.backgroundColor = UIColor.blue.cgColor
            layer.frame = CGRect(x: 0, y: 0, width: 22, height: 22)
            self.circleView.layer.insertSublayer(layer, at: 1)
            layer.cornerRadius = layer.frame.height / 2
            layer.position = CGPoint(x: self.circleView.frame.height / 2, y: self.circleView.frame.height / 2)
        }
    }

推荐阅读