Установить закругленные углы и тень вида

Мне нужно закруглить нижний левый и правый углы представления и, основываясь на том, что я нашел в Интернете, я создал эту функцию внутри расширения UIview:

func setRoundedCorner(withRadius radius: CGSize, forCorners corners: UIRectCorner ) {

    let viewShape = CAShapeLayer()
    viewShape.bounds = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.bounds.width, height: self.bounds.height)
    viewShape.position = self.center
    viewShape.path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: radius).cgPath
    self.layer.mask = viewShape

}

Теперь я столкнулся с двумя проблемами с этим решением; несмотря на то, что он отлично работает для статического представления, мое представление программно меняет свою высоту, что приводит к усечению представления; Я нашел обходной путь для этой проблемы, каждый раз вспоминая метод setRoundedCorner, но это очень неудобно для моего представления; есть ли другой способ решить это? Еще одна проблема, которую мне труднее решить, — это набор теней. Я обычно использую этот метод:

func setShadow(height: CGFloat, width: CGFloat, opacity: Float, radius: CGFloat) {
    self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
    self.layer.shadowColor = UIColor.black.cgColor
    self.layer.shadowOpacity = opacity
    self.layer.shadowOffset = CGSize(width: width, height: height)
    self.layer.cornerRadius = radius
    self.layer.masksToBounds = false
}

Вместо этого вид выглядит так, когда тень должна быть под ним:

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

Но в этой ситуации, похоже, не работает вообще отсутствие тени. Кто-нибудь может дать мне совет?


person Lorenzo Santini    schedule 15.10.2018    source источник
comment
Покажите нам скриншот того, что вы получаете, и, возможно, скриншот вашей цели.   -  person Glenn Posadas    schedule 15.10.2018
comment
(1) Вы должны установить размер маски после того, как вы знаете окончательный размер представления. Также в iOS 11 нет необходимости в маске; можно закруглить отдельные углы. (2) У вас не может быть и маски, и тени, потому что маска обрезает тень. — Оба вопроса объяснялись здесь много раз. Пожалуйста, поищите, прежде чем спрашивать.   -  person matt    schedule 15.10.2018
comment
Можем ли мы получить ожидаемый результат?   -  person excitedmicrobe    schedule 15.10.2018
comment
@Glenn, я отредактировал свой вопрос   -  person Lorenzo Santini    schedule 15.10.2018
comment
@AngryWarden Я отредактировал пост, показывающий, как теперь выглядит вид ... Он должен выглядеть так, но с тенью под собой.   -  person Lorenzo Santini    schedule 15.10.2018


Ответы (2)


Здесь я делюсь с вами своей категорией добавления углового радиуса (используя BezierPath) и в то же время поддерживая добавление тени.

import UIKit

/// A category for all views.
extension UIView {
    /// Setups the layer of a view.
    public func setupLayer(
        cornerRadius: CGFloat = 22,
        borderWidth: CGFloat = 0,
        borderColor: UIColor = .clear,
        shadowOffSet: CGSize = CGSize(width: 0, height: 1),
        shadowColor: UIColor = UIColor(red:0, green:0, blue:0, alpha:0.15),
        shadowOpacity: Float = 1,
        shadowRadius: CGFloat = 2,
        shouldClipToBounds: Bool = false
        ) {

        self.layer.cornerRadius     = cornerRadius
        self.layer.borderWidth      = borderWidth
        self.layer.borderColor      = borderColor.cgColor
        self.layer.shadowOffset     = shadowOffSet
        self.layer.shadowColor      = shadowColor.cgColor
        self.layer.shadowOpacity    = shadowOpacity
        self.layer.shadowRadius     = shadowRadius
        self.clipsToBounds = shouldClipToBounds
    }

    /// Round the corner radius with bezier path.
    func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }
}

Не стесняйтесь редактировать все на этом. Теперь давайте поговорим о вашей проблеме. Кстати, этот код я использую в своих продакшн-проектах. Иногда вам нужно скруглить углы в ваших viewDidLayoutSubviews, viewWillLayoutSubviews. И если вы используете подкласс UIView или UITableViewCell или подобных классов, вы добавляете свой код скругления углов внутри их draw функций.

override func draw(_ rect: CGRect) {
        super.draw(rect)
    // Round corners here...
}

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

Наконец, для настройки слоев я обычно вызываю это внутри объявления отложенной инициализации моих элементов управления (например, кнопок, текстовых полей...). Знайте разницу между добавлением углов с помощью bezierPath и просто layer.cornerRadius. :)

Надеюсь, это поможет!

person Glenn Posadas    schedule 15.10.2018
comment
Хорошо, спасибо большое... Попробую... всего пара вопросов... не могли бы вы объяснить мне разницу между использованием layer.cornerRadius и bezierPath? Я использовал последнюю, потому что мне нужно было установить только нижние углы... и еще один вопрос: что вы подразумеваете под функцией рисования пользовательского класса? - person Lorenzo Santini; 15.10.2018
comment
Ну, layer.cornerRadius не нужно вызывать внутри метода draw/viewWillLayoutSubviews. А еще вы скругляете все углы, используя это. При использовании BezierPath можно скруглить любой угол. Это могут быть все углы, верхний левый, только верхний правый, нижний правый и верхний правый и т. д. Метод draw (в ячейках или UIView) эквивалентен viewWillLayoutSubviews контроллеров. Не забудьте выбрать ответ, чтобы закрыть вопросы. Откройте новую тему, если вы хотите задать дополнительные вопросы (но убедитесь, что это не дубликат) :) - person Glenn Posadas; 15.10.2018
comment
Да ... большое спасибо ... Я попробую ваш код, а затем, если я решу свою проблему, я выберу ваш ответ. - person Lorenzo Santini; 15.10.2018
comment
Я попробовал ваш код, но он не работает... тени нет. - person Lorenzo Santini; 15.10.2018
comment
Как вы это реализовали? Который из? Смотрите мой отредактированный ответ, я опубликую образец вывода. - person Glenn Posadas; 16.10.2018
comment
Я просто вызвал setupLayer() и roundCorners() внутри методов viewDidLoad, и они скругляют углы, но не показывают никакой тени. Как я уже сказал в другом комментарии ... Может ли это быть связано с тем, что это представление имеет другие элементы внутри себя, и это настраиваемое представление? - person Lorenzo Santini; 16.10.2018
comment
Вы скорректировали значения, чтобы удовлетворить ваши требования? Как непрозрачность тени, радиус тени? Сначала попробуйте setupLayer() без roundCorners(). И помните, что roundCorners(), который использует BezierPath, должен быть внутри draw или viewWillLayoutSubviews - person Glenn Posadas; 17.10.2018
comment
Если я вызываю метод setupLayer() один внутри ViewController, он отлично работает, показывая тень и все остальное, но если я также вызываю метод roundCorners() внутри метода рисования (я указываю, что мы говорим о подклассе UIView), он округляет углы, но тень исчезает - person Lorenzo Santini; 17.10.2018

Вы можете просто добавить это расширение

extension UIView 
{ 
func dropShadow(scale: Bool = true) {
    layer.masksToBounds = false
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOpacity = 0.5
    layer.shadowOffset = CGSize(width: -1, height: 1)
    layer.shadowRadius = 1

    layer.shadowPath = UIBezierPath(rect: bounds).cgPath
    layer.shouldRasterize = true
    layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}

func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, radius: CGFloat = 1, scale: Bool = true) {
    layer.masksToBounds = false
    layer.shadowColor = color.cgColor
    layer.shadowOpacity = opacity
    layer.shadowOffset = offSet
    layer.shadowRadius = radius

    layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
    layer.shouldRasterize = true
    layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}


 }

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

  priceview.layer.cornerRadius = 5
  priceview.dropShadow(color: UIColor.darkGray, opacity: 0.5, offSet: CGSize(width: 1, height: 1), radius: 3, scale: true)

Я надеюсь, что это поможет вам.

person Virani Vivek    schedule 16.10.2018
comment
Это не работает ... может ли это быть вызвано тем, что это представление имеет другие элементы внутри себя, и это пользовательский UIView? - person Lorenzo Santini; 16.10.2018
comment
да, и он содержит много элементов внутри себя, и я даю ему тень, и он отлично работает для меня. - person Virani Vivek; 18.10.2018