इसमें पारदर्शी छेद वाला कायर


112

मेरे पास एक साधारण दृश्य है (चित्र के बाईं ओर) और मुझे इस दृश्य में किसी प्रकार का ओवरले (चित्र के दाईं ओर) बनाने की आवश्यकता है। इस ओवरले में कुछ अपारदर्शिता होनी चाहिए, इसलिए यह देखने वाला बोला अभी भी आंशिक रूप से दिखाई दे रहा है। सबसे महत्वपूर्ण बात यह है कि इस ओवरले के बीच में एक गोलाकार छेद होना चाहिए ताकि यह दृश्य के केंद्र को ओवरले न करे (चित्र बाइल देखें)।

मैं आसानी से इस तरह एक सर्कल बना सकता हूं:

int radius = 20; //whatever
CAShapeLayer *circle = [CAShapeLayer layer];

circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0,radius,radius) cornerRadius:radius].CGPath;
circle.position = CGPointMake(CGRectGetMidX(view.frame)-radius,
                              CGRectGetMidY(view.frame)-radius);
circle.fillColor = [UIColor clearColor].CGColor;

और इस तरह एक "पूर्ण" आयताकार ओवरले:

CAShapeLayer *shadow = [CAShapeLayer layer];
shadow.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height) cornerRadius:0].CGPath;
shadow.position = CGPointMake(0, 0);
shadow.fillColor = [UIColor grayColor].CGColor;
shadow.lineWidth = 0;
shadow.opacity = 0.5;
[view.layer addSublayer:shadow];

लेकिन मुझे नहीं पता कि मैं इन दोनों परतों को कैसे जोड़ सकता हूं ताकि वे मेरे मनचाहे प्रभाव पैदा करें। किसी को? मैं वास्तव में सब कुछ करने की कोशिश की है ... मदद के लिए बहुत बहुत धन्यवाद!

छवि


क्या आप एक बीज़ियर बना सकते हैं जिसमें आयत और वृत्त होते हैं और फिर ड्राइंग के दौरान उपयोग किया जाने वाला घुमावदार नियम एक छेद बनाएगा (मैंने कोशिश नहीं की है)।
वेन

मुझे नहीं पता कि यह कैसे करना है :)
animal_chin

फिर से बनाएँ, फिर moveToPointगोल आयत जोड़ें। द्वारा की पेशकश की विधियों के लिए डॉक्स की जाँच करें UIBezierPath
वेन

देखें कि क्या यह इसी तरह का प्रश्न और उत्तर मदद करता है: [UIView में पारदर्शी छेद काटें] [1] [१]: stackoverflow.com/questions/9711248/…

मेरा समाधान यहां देखें: stackoverflow.com/questions/14141081/… उम्मीद है कि यह किसी की मदद करता है
जेम्स लॉरेनस्टीन

जवाबों:


218

मैं जॉन स्टेनमेट के सुझाव से इसे हल करने में सक्षम था। अगर किसी को परवाह है, तो यहां अंतिम समाधान है:

int radius = myRect.size.width;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.mapView.bounds.size.width, self.mapView.bounds.size.height) cornerRadius:0];
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];

CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor grayColor].CGColor;
fillLayer.opacity = 0.5;
[view.layer addSublayer:fillLayer];

स्विफ्ट 3.x:

let radius = myRect.size.width
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.mapView.bounds.size.width, height: self.mapView.bounds.size.height), cornerRadius: 0)
let circlePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 2 * radius, height: 2 * radius), cornerRadius: radius)
path.append(circlePath)
path.usesEvenOddFillRule = true

let fillLayer = CAShapeLayer()
fillLayer.path = path.cgPath
fillLayer.fillRule = kCAFillRuleEvenOdd
fillLayer.fillColor = Color.background.cgColor
fillLayer.opacity = 0.5
view.layer.addSublayer(fillLayer)

स्विफ्ट 4.2 और 5:

let radius: CGFloat = myRect.size.width
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height), cornerRadius: 0)
let circlePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 2 * radius, height: 2 * radius), cornerRadius: radius)
path.append(circlePath)
path.usesEvenOddFillRule = true

let fillLayer = CAShapeLayer()
fillLayer.path = path.cgPath
fillLayer.fillRule = .evenOdd
fillLayer.fillColor = view.backgroundColor?.cgColor
fillLayer.opacity = 0.5
view.layer.addSublayer(fillLayer)

2
अतिरिक्त लचीलेपन के लिए, अपने विचार को "IBDesignable" उपवर्ग बनाएं। यह वास्तव में आसान है! आरंभ करने के लिए, उपरोक्त कोड को इस प्रश्न के उत्तर में दें: stackoverflow.com/questions/14141081/…
clozach

2
नौसिखिए आईओएस डेवलपर के रूप में मैंने यह पता लगाने में कुछ घंटे बिताए हैं कि यह कोड अजीब परिणाम क्यों पैदा करता है। अंत में मैंने पाया, अगर उपरिशायी मास्क को किसी बिंदु पर पुनर्गणना किया जाता है, तो जोड़े गए सबलेयर को हटा दिया जाना चाहिए। यह view.layer.sublayers संपत्ति के माध्यम से संभव है। उत्तर के लिए बहुत बहुत धन्यवाद!
सेरझास

मैं इसके ठीक विपरीत क्यों हो रहा हूं। काले अर्द्ध पारदर्शी आकार के साथ स्पष्ट रंग की परत ??
चंचल वार्डे

मैं इस मोड का उपयोग करके एक सर्कल में एक पारदर्शी पाठ कैसे जोड़ सकता हूं, यह संभव है? मुझे पता नहीं कैसे
डिएगो फर्नांडो मुरिलो वेलेंकी

लगभग 6 साल, अभी भी मदद करता है, लेकिन ध्यान रखें कि खोखला छेद वास्तव में इसे रखने वाली परत के माध्यम से 'पंच' नहीं करता है। कहते हैं, अगर एक बटन पर छेद ओवरले। बटन सुलभ नहीं है, जिसकी जरूरत है अगर आप मेरी तरह 'गाइडेड ट्यूटोरियल' बनाने की कोशिश कर रहे हैं। @Nick याप द्वारा प्रदान की गई लाइब्रेरी आपके लिए वह काम करेगी, जहां फंक पॉइंट (अंदर का बिंदु: CGPoint, ईवेंट के साथ: UIEvent?) -> BIV {} का ओवरिवाइड करके। अधिक जानकारी के लिए उसकी लाइब्रेरी देखें। लेकिन, आप जो उम्मीद करते हैं, वह 'मुखौटा के पीछे दृश्यता' है, यह एक वैध उत्तर है।
infinity_coding7 15

32

इस प्रभाव को बनाने के लिए, मुझे स्क्रीन को ओवरलेइंग करते हुए एक संपूर्ण दृश्य बनाना आसान लगा, फिर परतों और UIBezierPaths का उपयोग करके स्क्रीन के कुछ हिस्सों को घटाया गया। एक स्विफ्ट कार्यान्वयन के लिए:

// Create a view filling the screen.
let overlay = UIView(frame: CGRectMake(0, 0, 
    UIScreen.mainScreen().bounds.width,
    UIScreen.mainScreen().bounds.height))

// Set a semi-transparent, black background.
overlay.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.85)

// Create the initial layer from the view bounds.
let maskLayer = CAShapeLayer()
maskLayer.frame = overlay.bounds
maskLayer.fillColor = UIColor.blackColor().CGColor

// Create the frame for the circle.
let radius: CGFloat = 50.0
let rect = CGRectMake(
        CGRectGetMidX(overlay.frame) - radius,
        CGRectGetMidY(overlay.frame) - radius,
        2 * radius,
        2 * radius)

// Create the path.
let path = UIBezierPath(rect: overlay.bounds)
maskLayer.fillRule = kCAFillRuleEvenOdd

// Append the circle to the path so that it is subtracted.
path.appendPath(UIBezierPath(ovalInRect: rect))
maskLayer.path = path.CGPath

// Set the mask of the view.
overlay.layer.mask = maskLayer

// Add the view so it is visible.
self.view.addSubview(overlay)

मैंने ऊपर दिए गए कोड का परीक्षण किया, और यहाँ परिणाम है:

यहां छवि विवरण दर्ज करें

मैंने CocoaPods में एक पुस्तकालय जोड़ा है जो उपरोक्त कोड के बहुत से सार करता है और आपको आसानी से आयताकार / परिपत्र छेद के साथ ओवरले बनाने की अनुमति देता है, जिससे उपयोगकर्ता ओवरले के पीछे के विचारों के साथ बातचीत कर सकता है। मैंने इसका उपयोग हमारे एक ऐप के लिए इस ट्यूटोरियल को बनाने के लिए किया है:

TAOverlayView का उपयोग करके ट्यूटोरियल

पुस्तकालय TAOverlayView कहा जाता है , और Apache 2.0 के तहत खुला स्रोत है। मुझे उम्मीद है कि आप इसे उपयोगी पाएँ!


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

1
@Mogsdad मैं स्पैमी प्रकट नहीं करना चाहता था, मैंने अभी इस लाइब्रेरी पर एक अच्छा समय बिताया है और मुझे लगा कि यह ऐसे ही लोगों की कोशिश कर रहा है। लेकिन प्रतिक्रिया के लिए धन्यवाद, मैं
निक याप

3
अच्छा अद्यतन, निक। मैं आपके कोने में हूँ - मैंने स्वयं पुस्तकालयों और उपयोगिताओं को प्रकाशित किया है, और मैं समझता हूं कि यह पूर्ण उत्तर देने के लिए बेमानी लग सकता है जब मेरा प्रलेखन पहले से ही इसे कवर करता है ... हालांकि विचार का उत्तर स्व-निहित है। यथासंभव। और लोग स्पैम के अलावा कुछ भी पोस्ट नहीं कर रहे हैं , इसलिए मैं उनके साथ नहीं रहना चाहूंगा। मुझे लगता है कि आप एक ही दिमाग के हैं, यही वजह है कि मैंने इसे आपको बताया। चीयर्स!
मोगादाद

मैंने आपके द्वारा बनाई गई फली का उपयोग किया, इसके लिए धन्यवाद। लेकिन ओवरले के नीचे मेरे विचार बातचीत करना बंद कर देते हैं। इसके साथ गलत क्या है? मैं इसके अंदर imageview के साथ एक स्क्रॉलव्यू है।
अम्मार मुजीब

@AmmarMujeeb आपके द्वारा बनाए गए "छेद" को छोड़कर ओवरले को इंटरैक्ट करता है। फली के साथ मेरा इरादा ओवरले था जो स्क्रीन के कुछ हिस्सों को उजागर करता है, और केवल आपको हाइलाइट किए गए तत्वों के साथ बातचीत करने की अनुमति देता है।
निक याप

11

स्वीकृत समाधान स्विफ्ट 3.0 संगत

let radius = myRect.size.width
let path = UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: self.mapView.bounds.size.width, height: self.mapView.bounds.size.height), cornerRadius: 0)
let circlePath = UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: 2.0*radius, height: 2.0*radius), cornerRadius: radius)
path.append(circlePath)
path.usesEvenOddFillRule = true

let fillLayer = CAShapeLayer()
fillLayer.path = path.cgPath
fillLayer.fillRule = kCAFillRuleEvenOdd
fillLayer.fillColor = UIColor.gray.cgColor
fillLayer.opacity = 0.5
view.layer.addSublayer(fillLayer)

@ फैटी: आपका लिंक मर चुका है
रैंडी

10

मैंने Animal_chin के समान दृष्टिकोण लिया, लेकिन मैं अधिक दृश्यमान हूं, इसलिए मैंने इसे आउटलेट और ऑटो लेआउट का उपयोग करके इंटरफ़ेस बिल्डर में स्थापित किया।

यहाँ स्विफ्ट में मेरा समाधान है

    //shadowView is a UIView of what I want to be "solid"
    var outerPath = UIBezierPath(rect: shadowView.frame)

    //croppingView is a subview of shadowView that is laid out in interface builder using auto layout
    //croppingView is hidden.
    var circlePath = UIBezierPath(ovalInRect: croppingView.frame)
    outerPath.usesEvenOddFillRule = true
    outerPath.appendPath(circlePath)

    var maskLayer = CAShapeLayer()
    maskLayer.path = outerPath.CGPath
    maskLayer.fillRule = kCAFillRuleEvenOdd
    maskLayer.fillColor = UIColor.whiteColor().CGColor

    shadowView.layer.mask = maskLayer

मुझे यह समाधान पसंद है क्योंकि आप सर्कलपाथ को डिज़ाइन समय पर चारों ओर ले जा सकते हैं और बहुत आसानी से समय चला सकते हैं।
मार्क Moeykens

यह मेरे लिए काम नहीं किया, हालांकि मैंने इसे अंडाकार के बजाय एक सामान्य जड़ का उपयोग करने के लिए संशोधित किया था, लेकिन अंतिम मुखौटा छवि अभी गलत आ रही है :(
गेमडेव

7

कोड स्विफ्ट 2.0 संगत

@Animal_inch उत्तर से शुरू होकर, मैं थोड़ी उपयोगिता-श्रेणी का कोड देता हूं, आशा है कि यह सराहना करेगा:

import Foundation
import UIKit
import CoreGraphics

/// Apply a circle mask on a target view. You can customize radius, color and opacity of the mask.
class CircleMaskView {

    private var fillLayer = CAShapeLayer()
    var target: UIView?

    var fillColor: UIColor = UIColor.grayColor() {
        didSet {
            self.fillLayer.fillColor = self.fillColor.CGColor
        }
    }

    var radius: CGFloat? {
        didSet {
            self.draw()
        }
    }

    var opacity: Float = 0.5 {
        didSet {
           self.fillLayer.opacity = self.opacity
        }
    }

    /**
    Constructor

    - parameter drawIn: target view

    - returns: object instance
    */
    init(drawIn: UIView) {
        self.target = drawIn
    }

    /**
    Draw a circle mask on target view
    */
    func draw() {
        guard (let target = target) else {
            print("target is nil")
            return
        }

        var rad: CGFloat = 0
        let size = target.frame.size
        if let r = self.radius {
            rad = r
        } else {
            rad = min(size.height, size.width)
        }

        let path = UIBezierPath(roundedRect: CGRectMake(0, 0, size.width, size.height), cornerRadius: 0.0)
        let circlePath = UIBezierPath(roundedRect: CGRectMake(size.width / 2.0 - rad / 2.0, 0, rad, rad), cornerRadius: rad)
        path.appendPath(circlePath)
        path.usesEvenOddFillRule = true

        fillLayer.path = path.CGPath
        fillLayer.fillRule = kCAFillRuleEvenOdd
        fillLayer.fillColor = self.fillColor.CGColor
        fillLayer.opacity = self.opacity
        self.target.layer.addSublayer(fillLayer)
    }

    /**
    Remove circle mask
    */


  func remove() {
        self.fillLayer.removeFromSuperlayer()
    }

}

फिर, आपके कोड में जहाँ भी:

let circle = CircleMaskView(drawIn: <target_view>)
circle.opacity = 0.7
circle.draw()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.