UIView के बाहर एक बॉर्डर जोड़ें (अंदर की बजाय)


82

यदि किसी दृश्य में कोड का उपयोग करके दृश्य की सीमा जोड़ें

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

बॉर्डर को निम्नलिखित जैसे दृश्य के अंदर जोड़ा जाता है: यहाँ छवि विवरण दर्ज करें

सही दृश्य मूल दृश्य है, जैसा कि आप देख सकते हैं, सीमा दृश्य का काला क्षेत्र मूल से कम है। लेकिन मैं जो प्राप्त करना चाहता हूं वह मूल दृश्य के बाहर की सीमा है, जैसे यहाँ छवि विवरण दर्ज करें:। काला क्षेत्र मूल के बराबर है, मैं इसे कैसे लागू कर सकता हूं?

जवाबों:


100

दुर्भाग्य से, बस एक छोटी सी संपत्ति नहीं है जिसे आप बाहर से सीमा को संरेखित करने के लिए सेट कर सकते हैं। यह अंदर से संरेखित करता है क्योंकि UIViews डिफ़ॉल्ट ड्राइंग ऑपरेशन इसकी सीमा में आते हैं।

सबसे सरल समाधान जो मन में आता है वह सीमा को लागू करते समय सीमा चौड़ाई के आकार द्वारा यूआईवाईवाई का विस्तार करना होगा:

CGFloat borderWidth = 2.0f;

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

मैंने इसका उपयोग यूटेबुलसेल के विचार पर किया है। लेकिन लाइन पर, self.frame = CGRectInset (self.frame, -borderWidth, -borderWidth); अगर हम टेबलव्यू को स्क्रॉल करते रहते हैं तो व्यू की चौड़ाई और ऊंचाई बढ़ती रहती है। इसलिए मैंने इसे हटाकर समाप्त कर दिया।
नीला

यह विधि दृश्य ऊंचाई को बढ़ाती रहती है इसलिए मैं इस कोड को हटाता हूं और निम्न कोड का उपयोग करता हूं। self.view.layer.borderColor = [[UIColor colorWithRed: 209.0f / 255.0f हरा: 33.0f / 255.0 नीले, 8.0f / 255.0f अल्फा: 1.0f] CGColor]; self.view.layer.borderWidth = 1.0f;
रिजवान शाह

4
स्विफ्ट में इस समाधान की कोशिश की, दुर्भाग्य से काम नहीं करता है, सीमा UIImageView के अंदर
खींचती

यदि यह कोड एक ऐसी विधि के अंदर है जिसे कई बार कहा जाता है, तो यह आकार में बढ़ता रहेगा क्योंकि self.frame खुद को दोहराता है। इसे रोकने के लिए, self.frame को संग्रहीत करने के लिए एक संपत्ति घोषित करें और इसे viewDidload में सेट करें। उदाहरण के लिए, _originalSize = self.frame; जहां ओरिजिनलसाइज एक CGRect प्रॉपर्टी है। फिर कोड को self.frame = CGRectInset (_originalSize, -borderWidth, -borderWidth) में बदलें;
जिनेकोड

जब यह ViewDidLoad में कार्यान्वित किया जाता है, तो दृश्य स्क्रीन के आकार के अनुसार ऑटो का आकार बदल जाता है (अर्थात दृश्य मूल आकार का हो जाता है और इस प्रकार सीमा दृश्यमान हो जाती है)। यदि इसे ViewDidAppear में लागू किया जाता है, तो यह मूल दृश्य के बाहर की सीमा नहीं बनाता है। इसे लागू करने के बारे में कोई विचार ताकि सीमा को मूल दृश्य के बाहर बनाया जाए और दृश्य का आकार परिवर्तन न हो?
जेफ़बी ६६

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और परत के फ्रेम को तदनुसार अनुकूलित कर सकते हैं । यह एक दूसरे दृश्य का उपयोग करने से बेहतर है क्योंकि एक CALayerकी तुलना में हल्का है UIViewऔर आप के फ्रेम को संशोधित नहीं करते हैं myView, जो उदाहरण के लिए अच्छा है यदि myViewएक हैUIImageView

NB: मेरे लिए परिणाम सिम्युलेटर पर बिल्कुल सही नहीं था (परत बिल्कुल सही स्थिति में नहीं थी इसलिए परत कभी-कभी एक तरफ मोटी होती थी) लेकिन वास्तव में वास्तविक डिवाइस के लिए पूछा गया था।

संपादित करें

वास्तव में मैं एनबी में जिस समस्या के बारे में बात करता हूं वह सिर्फ इसलिए थी क्योंकि मैंने सिम्युलेटर की स्क्रीन को कम कर दिया था, सामान्य आकार पर कोई समस्या नहीं है

आशा करता हूँ की ये काम करेगा


2
myView.layer.masksToBounds = NO; यह समस्या पैदा कर रहा है जब myView में कॉर्नररियस है।
.मकांटा

.masksToBounds = कोई // यह भी अपनी छवि अतिप्रवाह अगर यह की स्केलिंग मोड aspectFill है
आईओएस लोहार

22

ऊपर स्वीकार किए गए सर्वोत्तम उत्तर के साथ मैंने ऐसे अच्छे परिणाम और भद्दे किनारों के साथ अनुभव किए :

बेज़ियर पथ के बिना सीमा

इसलिए मैं आपके साथ अपना यूआईवीवाई स्विफ्ट एक्सटेंशन साझा करूंगा , जो सीमावर्ती रूपरेखा के बिना एक यूआईबीज़ियरपथ का उपयोग करता है - बिना भद्दे किनारों ( @ फैटी से प्रेरित ):

बेज़ियर पथ के साथ सीमा

//  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

स्विफ्ट कार्यान्वयन के लिए, आप इसे 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()
    }

}

अति उत्कृष्ट! धन्यवाद! स्विफ्ट 4 में कुछ चीजें बदली हैं और अब अलग दिखती हैं, लेकिन एक्सकोड बताता है कि कोड को कैसे संशोधित किया जाए। और मेथड 'removeExternalBorder' में 'guard externalBorder.name ==' होना चाहिए।
दिमित्रीकुननिकॉफ

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

मैंने स्टोरीबोर्ड में अपने UI दृश्य (मुख्य - SubscriptionAd) के चारों ओर एक सीमा कैसे रखी है, इसे किसी अन्य UI दृश्य (पृष्ठभूमि - पृष्ठभूमि) के अंदर रखना है। बैकग्राउंड यूइवीवाई में एक बैकग्राउंड कलर है जो बॉर्डर कलर से मिलता है जो मैं चाहता हूं, और मेन यूआईवीईवाई में हर तरफ से वैल्यू 2 है।

मैं पृष्ठभूमि दृश्य को अपने ViewController से लिंक करूंगा और फिर पृष्ठभूमि का रंग बदलकर सीमा को चालू और बंद कर दूंगा।

शीर्ष दृश्य 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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.