Круговой UIView не полный круг

У меня есть интересная проблема, но я не знаю, как ее решить. Я пытаюсь расширить UIView с помощью @IBInspectable. Однако с помощью этого метода угловой радиус, по-видимому, устанавливается со стороны файлов пера по умолчанию, а не с фактическим размером представления.

Итак, когда в IB я устанавливаю «Просмотр как» на iPhoneSE и строю для iPhoneSE, вид представляет собой круг. Однако, если я строю для iPhone7, углы не полностью закругляются в круг. И наоборот, если я установлю «Просмотр как» для iPhone7 и создам для iPhone7, вид будет кругом. Однако, если я создам для iPhoneSE, углы будут закруглены.

Картинки и код ниже:

Расширение

extension UIView {

    @IBInspectable var cornerRadius:Double {
        get {
            return Double(layer.cornerRadius)
        }
        set {
            layer.cornerRadius = CGFloat(newValue)
            layer.masksToBounds = newValue > 0
        }
    }

    @IBInspectable var circleView:Bool {
        get {
            return layer.cornerRadius == min(self.frame.width, self.frame.height) / CGFloat(2.0) ? true : false
        }
        set {
            if newValue {
                layer.cornerRadius = min(self.frame.width, self.frame.height) / CGFloat(2.0)
                layer.masksToBounds = true
            }
            else{
                layer.cornerRadius = 0.0
                layer.masksToBounds = false
            }
        }
    }

}

«Просмотреть как» установлено как iPhoneSE в IB

Создан для iPhoneSE

введите здесь описание изображения

Сборка для iPhone 7

введите здесь описание изображения

«Просмотреть как» установлено как iPhone7

Сборка для iPhone SE

введите здесь описание изображения

Сборка для iPhone 7

введите здесь описание изображения

Настройки ИБ введите здесь описание изображения введите здесь описание изображения


person steventnorris    schedule 03.03.2017    source источник
comment
Не могли бы вы сделать скриншот настроек автомакета и скриншот, когда у вас выбран Circular UIView в IB?   -  person Samuel Tulach    schedule 08.03.2017
comment
@SamuelTulach Добавлено для вас выше.   -  person steventnorris    schedule 08.03.2017


Ответы (4)


Вы получите полный круг только в том случае, если ваш взгляд является квадратом.

Если ваш вид представляет собой прямоугольник, и вы установите cornerRadius со значением меньше половины наименьшего размера, вы получите второй вид, а если это значение больше, вы получите ромбовидный вид.

Проверьте свои ограничения, и вы должны вычислить cornerRadius после того, как представление завершит макет в viewDidLayout, чтобы получить правильный размер.

Вот игровая площадка, показывающая это (я добавил анимацию, чтобы лучше показать проблему):

import UIKit
import PlaygroundSupport

extension UIView
{
  func addCornerRadiusAnimation(from: CGFloat, to: CGFloat, duration: CFTimeInterval)
  {
    let animation = CABasicAnimation(keyPath:"cornerRadius")
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.fromValue = from
    animation.toValue = to
    animation.duration = duration
    self.layer.add(animation, forKey: "cornerRadius")
    self.layer.cornerRadius = to
  }
}

let v = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 450))
PlaygroundPage.current.liveView = v

let squareView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
squareView.backgroundColor = .red
squareView.layer.masksToBounds = true
v.addSubview(squareView)
var cornerRadius = CGFloat(0.5*min(squareView.frame.width,
                                   squareView.frame.height))
squareView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)

let rectangleView = UIView(frame: CGRect(x: 10, y: 200, width: 100, height: 200))
rectangleView.backgroundColor = .blue
rectangleView.layer.masksToBounds = true
v.addSubview(rectangleView)
cornerRadius = CGFloat(0.5*min(rectangleView.frame.width,
                                   rectangleView.frame.height))
rectangleView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)

let diamondView = UIView(frame: CGRect(x: 200, y: 200, width: 100, height: 200))
diamondView.backgroundColor = .green
diamondView.layer.masksToBounds = true
v.addSubview(diamondView)
cornerRadius = CGFloat(0.5*max(diamondView.frame.width,
                               diamondView.frame.height))
diamondView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)

Выход на площадку

person FranMowinckel    schedule 14.03.2017
comment
Вид квадратный. Проблема, похоже, не в прямоугольности, а в том, что код для округления запускается в жизненном цикле. Он выполняется до ограничений, полностью отображающих представление, поэтому округлость неверна. - person steventnorris; 17.03.2017
comment
@steventnorris Потому что вы должны вычислить cornerRadius после того, как представление завершило макет (это в моем ответе). Быстрое решение состоит в том, чтобы создать подкласс UIView и реализовать этот метод. - person FranMowinckel; 17.03.2017
comment
Ага. Это то, что мне, возможно, придется сделать. Я пытался сделать это таким образом, чтобы это применялось ко всем UIViews. Если я создам подкласс, нет возможности снова создать подкласс. Например, скажем, я создаю подкласс UIView как MyRoundView. Теперь, если я хочу UILabel, я должен решить, буду ли я создавать подкласс UILabel и копировать этот код или подкласс MyRoundView и не иметь методов и параметров, которые поставляются с UILabel. - person steventnorris; 17.03.2017
comment
Вы можете добавить некоторый метод makeRound в свое расширение и вызвать его в своем контроллере представления (например, в viewDidLayoutSubviews()). Или вы можете зациклить свое представление и подпредставления, ищущие свойство circleView. Или вы можете расширить свой контроллер представления с помощью метода makeRoundCircleSubviews... - person FranMowinckel; 17.03.2017

Вы упомянули ширину и высоту как 185,5, но сохранили ограничение по ширине как 350.

person Damodharam nandi damodaram    schedule 14.03.2017
comment
Проблема не в ограничениях. Это должно работать для нестатических ограничений ширины/высоты, и это не зависит от того, где он запускается в жизненном цикле, о котором я начинаю думать. - person steventnorris; 17.03.2017

Если вы не хотите перемещаться по viewDidLayout, вы можете просто сделать трюк перед установкой радиуса угла, добавив .layoutIfNeeded().

yourCircleView.layoutIfNeeded()
yourCircleView.layer.cornerRadius = yourCircleView.frame.size.width/2
person Alex    schedule 09.06.2017

Если все еще не удается, в Xcode удалите все (ВСЕ) ограничения и добавьте следующее в класс ячеек:

override func awakeFromNib() {
    super.awakeFromNib()        
    userImageView.layoutIfNeeded()
    userImageView.layer.cornerRadius = userImageView.frame.size.width / 2
    userImageView.layer.masksToBounds = true
    userImageView.clipsToBounds = true

}

person user3613987    schedule 17.04.2018