Додайте межу поза UIView (замість всередині)


82

Якщо додати межу подання за допомогою коду у поданні типу

self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;

межа додається всередину подання, як показано нижче: введіть тут опис зображення

правильний вигляд - це оригінальний вигляд, як ви можете бачити, чорна область облямованого виду менша за вихідну. але то , що я хочу , щоб це межа за межі первісної точки зору, як це: введіть тут опис зображення. чорна область дорівнює вихідній, як я можу це реалізувати?

Відповіді:


100

На жаль, є не просто невелика властивість, яку ви можете встановити для вирівнювання кордону зовні. Він малює вирівняно всередині, оскільки операції малювання за замовчуванням UIViews малюють у його межах.

Найпростішим рішенням, яке спадає на думку, було б розширити UIView на розмір ширини межі при застосуванні межі:

CGFloat borderWidth = 2.0f;

self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = borderWidth;

Я використав це для перегляду uitableviewcell. але на рядку, self.frame = CGRectInset (self.frame, -borderWidth, -borderWidth); Ширина та висота подання постійно збільшуються, якщо ми продовжуємо прокручувати подання таблиці .. Тож я закінчив, видаливши його.
Ніла

Цей метод продовжує збільшувати висоту перегляду, тому я видаляю цей код і використовую такий код self.view.layer.borderColor = [[UIColor colorWithRed: 209.0f / 255.0f зелений: 33.0f / 255.0f синій: 8.0f / 255.0f альфа: 1.0f] CGColor]; self.view.layer.borderWidth = 1.0f;
Різван Шах

4
Спробував це рішення в Swift, на жаль, не працює, межа продовжує малюватися всередині UIImageView
theDC

Якщо цей код знаходиться всередині методу, який викликається кілька разів, він буде продовжувати збільшуватися в розмірі, оскільки self.frame повторює себе. Щоб запобігти цьому, оголосіть властивість зберігати self.frame і встановіть його у viewDidload. наприклад, _originalSize = self.frame; де originalSize - це властивість CGRect. Потім змініть код на self.frame = CGRectInset (_originalSize, -borderWidth, -borderWidth);
GeneCode

Коли це реалізовано у ViewDidLoad, подання автоматично змінює розмір екрана (тобто вигляд змінює розмір до початкового розміру, і таким чином межа стає видимою). Якщо він реалізований у ViewDidAppear, він взагалі не створює межі за межами вихідного подання. Будь-які думки щодо того, як це реалізувати, щоб межа створювалася за межами початкового подання, а вигляд не змінював розмір?
JeffB6688

23

Гаразд, вже прийнята відповідь, але я думаю, що є кращий спосіб це зробити, вам просто потрібно мати новий шар трохи більший, ніж ваш вигляд, і не маскувати його до меж шару вигляду (що насправді є поведінка за замовчуванням). Ось зразок коду:

CALayer * externalBorder = [CALayer layer];
externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2);
externalBorder.borderColor = [UIColor blackColor].CGColor;
externalBorder.borderWidth = 1.0;

[myView.layer addSublayer:externalBorder];
myView.layer.masksToBounds = NO;

Звичайно, це якщо ви хочете, щоб ваша межа була на 1 одиницю більшою, якщо ви хочете більше, ви відповідно адаптуєте borderWidthі рамку шару. Це краще, ніж використовувати другий вигляд трохи більший, оскільки a CALayerсвітліший за a, UIViewі вам не потрібно змінювати фрейм myView, що добре, наприклад, якщо myViewєUIImageView

Примітка: Для мене результат не був ідеальним на тренажері (шар не був точно в потрібному положенні, тому шар іноді був товщі з одного боку), але був саме тим, що просять на реальному пристрої.

РЕДАГУВАТИ

Насправді проблема, про яку я говорю в НБ, полягала лише в тому, що я зменшив екран тренажера, при нормальних розмірах проблеми абсолютно немає

Сподіваюся, це допоможе


2
myView.layer.masksToBounds = НІ; це створює проблему, коли myView має CornerRadius.
умаканта

.masksToBounds = no // це також переповнить ваше зображення, якщо режим масштабування є aspectFill
iOS Blacksmith

22

З вище прийнятого найкращою відповіддю я зробив досвід роботи з такими не є добре результатами і непривабливими краями:

кордон без без'єрної доріжки

Тож я поділюся з вами своїм розширенням UIView Swift , яке використовує UIBezierPath замість цього як контур межі - без непривабливих країв (натхненно @Fattie ):

кордон з Безієвим шляхом

//  UIView+BezierPathBorder.swift

import UIKit

extension UIView {

    fileprivate var bezierPathIdentifier:String { return "bezierPathBorderLayer" }

    fileprivate var bezierPathBorder:CAShapeLayer? {
        return (self.layer.sublayers?.filter({ (layer) -> Bool in
            return layer.name == self.bezierPathIdentifier && (layer as? CAShapeLayer) != nil
        }) as? [CAShapeLayer])?.first
    }

    func bezierPathBorder(_ color:UIColor = .white, width:CGFloat = 1) {

        var border = self.bezierPathBorder
        let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:self.layer.cornerRadius)
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask

        if (border == nil) {
            border = CAShapeLayer()
            border!.name = self.bezierPathIdentifier
            self.layer.addSublayer(border!)
        }

        border!.frame = self.bounds
        let pathUsingCorrectInsetIfAny =
            UIBezierPath(roundedRect: border!.bounds, cornerRadius:self.layer.cornerRadius)

        border!.path = pathUsingCorrectInsetIfAny.cgPath
        border!.fillColor = UIColor.clear.cgColor
        border!.strokeColor = color.cgColor
        border!.lineWidth = width * 2
    }

    func removeBezierPathBorder() {
        self.layer.mask = nil
        self.bezierPathBorder?.removeFromSuperlayer()
    }

}

Приклад:

let view = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100))
view.layer.cornerRadius = view.frame.width / 2
view.backgroundColor = .red

//add white 2 pixel border outline
view.bezierPathBorder(.white, width: 2)

//remove border outline (optional)
view.removeBezierPathBorder()

в моєму випадку це має бути всередині :)
Пітер Крейнц

хороший спосіб думати, але ваша межа все ще "всередині", тому це потрібно виправити, щоб бути окресленим :)
Серж Рубенс

15

Для реалізації Swift ви можете додати це як розширення UIView.

extension UIView {

    struct Constants {
        static let ExternalBorderName = "externalBorder"
    }

    func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.whiteColor()) -> CALayer {
        let externalBorder = CALayer()
        externalBorder.frame = CGRectMake(-borderWidth, -borderWidth, frame.size.width + 2 * borderWidth, frame.size.height + 2 * borderWidth)
        externalBorder.borderColor = borderColor.CGColor
        externalBorder.borderWidth = borderWidth
        externalBorder.name = Constants.ExternalBorderName

        layer.insertSublayer(externalBorder, atIndex: 0)
        layer.masksToBounds = false

        return externalBorder
    }

    func removeExternalBorders() {
        layer.sublayers?.filter() { $0.name == Constants.ExternalBorderName }.forEach() {
            $0.removeFromSuperlayer()
        }
    }

    func removeExternalBorder(externalBorder: CALayer) {
        guard externalBorder.name == Constants.ExternalBorderName else { return }
        externalBorder.removeFromSuperlayer()
    }

}

Відмінно! Дякую! Деякі речі змінено в Swift 4 і тепер виглядає по-іншому, але Xcode пояснює, як змінити код. А в методі 'removeExternalBorder' має бути 'guard externalBorder.name =='.
DmitryKanunnikoff

13

Ну, немає прямого методу, щоб це зробити. Ви можете розглянути кілька обхідних шляхів.

  1. Змініть і збільште кадр і додайте барвисті кольори, як це зробили
  2. Додайте вигляд позаду поточного вигляду з більшим розміром, щоб він виглядав як межа. Може працювати як власний клас перегляду
  3. Якщо вам не потрібна певна межа (чітка межа), ви можете покладатися на тінь для цієї мети

    [view1 setBackgroundColor:[UIColor blackColor]];
    UIColor *color = [UIColor yellowColor];
    view1.layer.shadowColor = [color CGColor];
    view1.layer.shadowRadius = 10.0f;
    view1.layer.shadowOpacity = 1;
    view1.layer.shadowOffset = CGSizeZero;
    view1.layer.masksToBounds = NO;
    

2

Збільште ширину та висоту кадру подання із шириною межі перед додаванням межі:

float borderWidth = 2.0f
CGRect frame = self.frame;
frame.width += borderWidth;
frame.height += borderWidth;
 self.layer.borderColor = [UIColor yellowColor].CGColor;
 self.layer.borderWidth = 2.0f;

2

Насправді існує дуже просте рішення. Просто встановіть їх обох так:

view.layer.borderWidth = 5

view.layer.borderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor

view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.25).cgColor

1

Мені сподобалось рішення @picciano. Якщо ви хочете вибуховане коло замість квадрата, замініть функцію addExternalBorder на:

func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
        let externalBorder = CALayer()
        externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
        externalBorder.borderColor = borderColor.cgColor
        externalBorder.borderWidth = borderWidth
        externalBorder.cornerRadius = (frame.size.width + 2 * borderWidth) / 2
        externalBorder.name = Constants.ExternalBorderName
        layer.insertSublayer(externalBorder, at: 0)
        layer.masksToBounds = false

    }

0

Мені сподобалось рішення @picciano & @Maksim Kniazev. Ми також можемо створити кільцеву межу з наступним:

func addExternalAnnularBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
    let externalBorder = CALayer()
    externalBorder.frame = CGRect(x: -borderWidth*2, y: -borderWidth*2, width: frame.size.width + 4 * borderWidth, height: frame.size.height + 4 * borderWidth)
    externalBorder.borderColor = borderColor.cgColor
    externalBorder.borderWidth = borderWidth
    externalBorder.cornerRadius = (frame.size.width + 4 * borderWidth) / 2
    externalBorder.name = Constants.ExternalBorderName
    layer.insertSublayer(externalBorder, at: 0)
    layer.masksToBounds = false
}

0

Як я розмістив межу навколо мого подання інтерфейсу користувача (main - SubscriptionAd) в Storyboard, це помістити його всередині іншого подання інтерфейсу користувача (background - BackgroundAd). Фоновий UIView має колір тла, який відповідає кольору межі, який я хочу, а Основний UIView має значення обмежень 2 з кожної сторони.

Я зв’яжу фонове подання з моїм ViewController, а потім увімкну і вимкнуть межу, змінивши колір тла.

Зображення вкладеного UIView з обмеженнями на вигляд зверху 2px навколо, що робить його меншим, ніж більшим


0

Стрімкий 5

extension UIView {
    fileprivate struct Constants {
        static let externalBorderName = "externalBorder"
    }

    func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) -> CALayer {
        let externalBorder = CALayer()
        externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
        externalBorder.borderColor = borderColor.cgColor
        externalBorder.borderWidth = borderWidth
        externalBorder.name = Constants.ExternalBorderName

        layer.insertSublayer(externalBorder, at: 0)
        layer.masksToBounds = false

        return externalBorder
    }

    func removeExternalBorders() {
        layer.sublayers?.filter() { $0.name == Constants.externalBorderName }.forEach() {
            $0.removeFromSuperlayer()
        }
    }

    func removeExternalBorder(externalBorder: CALayer) {
        guard externalBorder.name == Constants.externalBorderName else { return }
        externalBorder.removeFromSuperlayer()
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.