Просто замаскируйте UIView прямоугольником
Я хочу знать, как просто замаскировать видимую область UIView любого типа. Все ответы/учебники, которые я читал до сих пор, описывают маскировку с помощью изображения, градиента или создания круглых углов, что намного более продвинуто, чем то, что я хочу.
Пример: у меня есть UIView с ограничениями (0, 0, 100, 100), и я хочу вырезать правую половину представления с помощью маски. Поэтому моя рамка маски будет (0, 0, 50, 100).
Любая идея, как это сделать просто? Я не хочу переопределять метод drawrect, так как это должно быть применимо к любому UIView.
Я пробовал это, но он просто делает весь вид невидимым.
CGRect mask = CGRectMake(0, 0, 50, 100);
UIView *maskView = [[UIView alloc] initWithFrame:mask];
viewToMask.layer.mask = maskView.layer;
Ответы
Ответ 1
Благодаря ссылке из MSK, я поступил так хорошо, что хорошо работает:
// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = CGRectMake(0, 0, 50, 100);
// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);
// Set the path to the mask layer.
maskLayer.path = path;
// Release the path since it not covered by ARC.
CGPathRelease(path);
// Set the mask of the view.
viewToMask.layer.mask = maskLayer;
Ответ 2
Спасибо за ответы, ребята.
В случае, если кто-то не может найти подходящий ответ по SO на этот вопрос в течение нескольких часов, как я только что сделал, я собрал рабочую суть в Swift 2.2 для masking
/clipping
UIView
с CGRect
/UIBezierPath
:
https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94
extension UIView {
func mask(withRect rect: CGRect, inverse: Bool = false) {
let path = UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
func mask(withPath path: UIBezierPath, inverse: Bool = false) {
let path = path
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
Использование:
let viewSize = targetView.bounds.size
let rect = CGRect(x: 20, y: 20, width: viewSize.width - 20*2, height: viewSize.height - 20*2)
// Cuts rectangle inside view, leaving 20pt borders around
targetView.mask(withRect: rect, inverse: true)
// Cuts 20pt borders around the view, keeping part inside rect intact
targetView.mask(withRect: rect)
Надеюсь, это спасет кого-то в будущем :)
Ответ 3
Не нужно никакой маски вообще.
Просто поместите его в представление оболочки с меньшим фреймом и установите clipsToBounds.
wrapper.clipsToBounds = YES;
Ответ 4
Очень простой пример в Swift ViewController на основе принятого ответа:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let redView = UIView(frame: view.bounds)
view.addSubview(redView)
view.backgroundColor = UIColor.greenColor()
redView.backgroundColor = UIColor.redColor()
mask(redView, maskRect: CGRect(x: 50, y: 50, width: 50, height: 50))
}
func mask(viewToMask: UIView, maskRect: CGRect) {
let maskLayer = CAShapeLayer()
let path = CGPathCreateWithRect(maskRect, nil)
maskLayer.path = path
// Set the mask of the view.
viewToMask.layer.mask = maskLayer;
}
}
Выход
![введите описание изображения здесь]()
Ответ 5
Необязательный слой, альфа-канал используется как маска для выбора между фоном слоя и результатом компоновки слоя с фильтрованным фоном.
@property (сохранить) CALayer * mask
Правильный способ сделать то, что вы хотите, - создать maskView
того же кадра (0, 0, 100, 100) как viewToMask
, который слой, который вы хотите скрыть. Затем вам нужно установить clearColor для пути, который вы хотите сделать невидимым (это заблокирует взаимодействие вида по пути, поэтому будьте осторожны с иерархией представлений).
Ответ 6
Swift 5, спасибо @Dan Rosenstark
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let red = UIView(frame: view.bounds)
view.addSubview(red)
view.backgroundColor = UIColor.cyan
red.backgroundColor = UIColor.red
red.mask(CGRect(x: 50, y: 50, width: 50, height: 50))
}
}
extension UIView{
func mask(_ rect: CGRect){
let mask = CAShapeLayer()
let path = CGPath(rect: rect, transform: nil)
mask.path = path
// Set the mask of the view.
layer.mask = mask
}
}
Ответ 7
Настройка MaskToBounds
недостаточно, например, в сценарии, где у вас UIImageView
, который находится внутри RelativeLayout
. Если вы поместите свой UIImageView
ближе к верхнему краю макета, а затем поверните свой UIImageView
, он перейдет в макет, и он не будет обрезан. Если вы установите для этого флага значение true, оно будет обрезано да, но оно также будет обрезано, если UIImageView
находится в центре макета, и это не то, что вы хотите.
Итак, определение maskRect
- правильный подход.