ConvertRect को समझें: toView :, convertRect: FromView :, ConvertPoint: toView: और ConvertPoint: fromView: विधियों


128

मैं इन तरीकों की कार्यक्षमता को समझने की कोशिश कर रहा हूं। क्या आप मुझे उनके शब्दार्थ को समझने के लिए एक सरल प्रयोग प्रदान कर सकते हैं?

प्रलेखन से, उदाहरण के लिए, ConvertPoint: fromView: विधि इस प्रकार वर्णित है:

रिसीवर को दिए गए दृश्य के समन्वय प्रणाली से एक बिंदु को परिवर्तित करता है।

समन्वय प्रणाली का क्या अर्थ है? रिसीवर के बारे में क्या ?

उदाहरण के लिए, क्या यह ConvertPoint का उपयोग करके समझ में आता है : fromView: निम्नलिखित की तरह?

CGPoint p = [view1 convertPoint:view1.center fromView:view1];

NSLog उपयोगिता का उपयोग करते हुए, मैंने सत्यापित किया है कि p मान view1 के केंद्र के साथ मेल खाता है।

पहले ही, आपका बहुत धन्यवाद।

संपादित करें: उन लोगों के लिए, जिन्होंने इन विधियों को समझने के लिए एक सरल कोड स्निपेट बनाया है।

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 150, 200)];
view1.backgroundColor = [UIColor redColor];

NSLog(@"view1 frame: %@", NSStringFromCGRect(view1.frame));        
NSLog(@"view1 center: %@", NSStringFromCGPoint(view1.center));   

CGPoint originInWindowCoordinates = [self.window convertPoint:view1.bounds.origin fromView:view1];        
NSLog(@"convertPoint:fromView: %@", NSStringFromCGPoint(originInWindowCoordinates));

CGPoint originInView1Coordinates = [self.window convertPoint:view1.frame.origin toView:view1];        
NSLog(@"convertPoint:toView: %@", NSStringFromCGPoint(originInView1Coordinates));

दोनों मामलों में self.window रिसीवर है। लेकिन एक अंतर है। पहले मामले में ConvertPoint पैरामीटर view1 निर्देशांक में व्यक्त किया गया है। आउटपुट निम्नलिखित है:

रूपांतर: दृश्य से: {100, 100}

दूसरे में, इसके बजाय, ConvertPoint को पर्यवेक्षण (self.window) निर्देशांक में व्यक्त किया जाता है। आउटपुट निम्नलिखित है:

ConvertPoint: toView: {0, 0}

जवाबों:


184

प्रत्येक दृश्य की अपनी समन्वय प्रणाली होती है - 0,0 की उत्पत्ति और चौड़ाई और ऊंचाई के साथ। यह boundsदृश्य की आयत में वर्णित है । frameदेखने के लिए, तथापि, बिंदु पर इसके मूल के भीतर सीमा अपने superview की आयत होगा।

आपके दृश्य पदानुक्रम के सबसे बाहरी दृश्य की उत्पत्ति 0,0 पर हुई है जो कि iOS में स्क्रीन के शीर्ष बाईं ओर स्थित है।

यदि आप इस दृश्य में 20,30 पर एक सबव्यू जोड़ते हैं, तो सबव्यू में 0,0 पर एक बिंदु पर्यवेक्षण में 20,30 पर एक बिंदु से मेल खाती है। यह रूपांतरण उन तरीकों को कर रहा है।

ऊपर दिया गया आपका उदाहरण व्यर्थ है (कोई यमक नहीं) क्योंकि यह एक बिंदु को एक दृश्य से स्वयं में परिवर्तित करता है, इसलिए कुछ भी नहीं होगा। आप आमतौर पर यह पता लगा सकते हैं कि किसी दृश्य का कोई बिंदु उसके पर्यवेक्षण के संबंध में था - यह देखने के लिए कि स्क्रीन पर कोई दृश्य बंद हो रहा है या नहीं, यह देखने के लिए:

CGPoint originInSuperview = [superview convertPoint:CGPointZero fromView:subview];

"रिसीवर" उस ऑब्जेक्ट के लिए एक मानक उद्देश्य-सी शब्द है जो संदेश प्राप्त कर रहा है (विधियों को संदेशों के रूप में भी जाना जाता है) इसलिए मेरे उदाहरण में यहां रिसीवर है superview


3
आपके जवाब के लिए धन्यवाद, jrturton बहुत उपयोगी व्याख्या। convertPointऔर convertRectवापसी प्रकार में भिन्नता है। CGPointया CGRect। लेकिन क्या fromऔर to? क्या अंगूठे का एक नियम है जिसका मैं उपयोग कर सकता हूं? धन्यवाद।
लोरेंजो बी

आप कब से बदलना चाहते हैं, कब बदलना चाहते हैं?
२१

3
क्या होगा अगर सुपरव्यू सबव्यू का प्रत्यक्ष अभिभावक नहीं है, तो क्या यह अभी भी काम करेगा?
वान ड्यू ट्रैन

3
@VanDuTran हाँ, जब तक वे एक ही विंडो में हैं (जो कि एक iOS ऐप में सबसे अधिक विचार हैं)
jrturton

बहुत बढ़िया जवाब। मेरे लिए बहुत कुछ साफ करने में मदद की। कोई अतिरिक्त पठन?
JaeGeeTee

39

मुझे हमेशा यह भ्रामक लगता है इसलिए मैंने एक खेल का मैदान बनाया जहां आप नेत्रहीन यह पता लगा सकते हैं कि convertफ़ंक्शन क्या करता है। यह स्विफ्ट 3 और Xcode 8.1b में किया गया है:

import UIKit
import PlaygroundSupport

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Main view
        view.backgroundColor = .black
        view.frame = CGRect(x: 0, y: 0, width: 500, height: 500)

        // Red view
        let redView = UIView(frame: CGRect(x: 20, y: 20, width: 460, height: 460))
        redView.backgroundColor = .red
        view.addSubview(redView)

        // Blue view
        let blueView = UIView(frame: CGRect(x: 20, y: 20, width: 420, height: 420))
        blueView.backgroundColor = .blue
        redView.addSubview(blueView)

        // Orange view
        let orangeView = UIView(frame: CGRect(x: 20, y: 20, width: 380, height: 380))
        orangeView.backgroundColor = .orange
        blueView.addSubview(orangeView)

        // Yellow view
        let yellowView = UIView(frame: CGRect(x: 20, y: 20, width: 340, height: 100))
        yellowView.backgroundColor = .yellow
        orangeView.addSubview(yellowView)


        // Let's try to convert now
        var resultFrame = CGRect.zero
        let randomRect: CGRect = CGRect(x: 0, y: 0, width: 100, height: 50)

        /*
        func convert(CGRect, from: UIView?)
        Converts a rectangle from the coordinate system of another view to that of the receiver.
        */

        // The following line converts a rectangle (randomRect) from the coordinate system of yellowView to that of self.view:
        resultFrame = view.convert(randomRect, from: yellowView)

        // Try also one of the following to get a feeling of how it works:
        // resultFrame = view.convert(randomRect, from: orangeView)
        // resultFrame = view.convert(randomRect, from: redView)
        // resultFrame = view.convert(randomRect, from: nil)

        /*
        func convert(CGRect, to: UIView?)
        Converts a rectangle from the receiver’s coordinate system to that of another view.
        */

        // The following line converts a rectangle (randomRect) from the coordinate system of yellowView to that of self.view
        resultFrame = yellowView.convert(randomRect, to: view)
        // Same as what we did above, using "from:"
        // resultFrame = view.convert(randomRect, from: yellowView)

        // Also try:
        // resultFrame = orangeView.convert(randomRect, to: view)
        // resultFrame = redView.convert(randomRect, to: view)
        // resultFrame = orangeView.convert(randomRect, to: nil)


        // Add an overlay with the calculated frame to self.view
        let overlay = UIView(frame: resultFrame)
        overlay.backgroundColor = UIColor(white: 1.0, alpha: 0.9)
        overlay.layer.borderColor = UIColor.black.cgColor
        overlay.layer.borderWidth = 1.0
        view.addSubview(overlay)
    }
}

var ctrl = MyViewController()
PlaygroundPage.current.liveView = ctrl.view

विचारों को देखने के लिए सहायक संपादक ( ) को दिखाना याद रखें , इसे इस तरह देखना चाहिए:

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

बेझिझक यहाँ या इस मुट्ठी में और उदाहरणों का योगदान करें ।


धन्यवाद, रूपांतरणों को समझने में यह वास्तव में उपयोगी था।
आनंद

महान अवलोकन। हालाँकि मुझे लगता है कि वे self.viewबेमानी हैं, viewयदि selfआवश्यक नहीं है तो सरल उपयोग ।
जैकब ट्रहलाř

धन्यवाद @ JakubTruhlář, मैंने अभी हटा दियाself
phi

आपका बहुत बहुत धन्यवाद! आपके खेल के मैदान ने मुझे यह पता लगाने में बहुत मदद की कि यह रूपांतरण कैसे काम करता है।
अनवर अज़ीज़ोव

30

यहाँ स्पष्ट अंग्रेजी में एक स्पष्टीकरण है।

जब आप किसी अन्य दृश्य ( ) के समन्वय स्थान के लिए एक सबव्यू ( aViewएक सबव्यू की [aView superview]) की परिभाषा को बदलना चाहते हैं self

// So here I want to take some subview and put it in my view's coordinate space
_originalFrame = [[aView superview] convertRect: aView.frame toView: self];

3
यह सच नहीं है। यह दृश्य को स्थानांतरित नहीं करता है, यह आपको केवल दूसरे के संदर्भ में दृश्य के समन्वय देता है। आपके मामले में यह आपको aView के सह-निर्देश देगा कि वे स्वयं कहाँ होंगे।
कार्ल

सही बात। यह दृश्य को स्थानांतरित नहीं करता है। विधि एक CGRect देता है। आप CGRect के साथ जो करना चाहते हैं, वह आपका व्यवसाय है। :-) उपरोक्त मामले में, इसका उपयोग स्क्रीन पर अपनी दृश्य स्थिति बनाए रखते हुए एक दृश्य को दूसरे के पदानुक्रम में स्थानांतरित करने के लिए किया जा सकता है।
घोड़े की नाल esh

14

IOS में हर दृश्य में एक समन्वय प्रणाली होती है। एक समन्वय प्रणाली एक ग्राफ की तरह है, जिसमें x अक्ष (क्षैतिज रेखा) और y अक्ष (ऊर्ध्वाधर रेखा) है। वह बिंदु जिस पर रेखाएँ आपस में जुड़ती हैं, उत्पत्ति कहलाती है। एक बिंदु (x, y) द्वारा दर्शाया गया है। उदाहरण के लिए, (2, 1) का अर्थ है कि बिंदु 2 पिक्सेल शेष है, और 1 पिक्सेल नीचे।

आप यहाँ समन्वय प्रणालियों के बारे में अधिक पढ़ सकते हैं - http://en.wikipedia.org/wiki/Coordinate_system

लेकिन आपको जो जानने की जरूरत है, वह यह है कि, iOS में, हर दृश्य में यह OWN समन्वय प्रणाली है, जहां शीर्ष बाएं कोने में मूल है। X अक्ष दाईं ओर बढ़ता जा रहा है, और y अक्ष नीचे बढ़ता जा रहा है।

परिवर्तित अंक प्रश्न के लिए, इस उदाहरण को लें।

एक दृश्य है, जिसे वी 1 कहा जाता है, जो 100 पिक्सेल चौड़ा और 100 पिक्सेल ऊंचा है। अब उसके अंदर, एक और दृश्य है, जिसे V2 कहा जाता है, (10, 10, 50, 50) जिसका अर्थ है कि (10, 10) V1 की समन्वय प्रणाली का वह बिंदु है जहां V2 के ऊपरी बाएं कोने को स्थित होना चाहिए, और ( 50, 50) V2 की चौड़ाई और ऊंचाई है। अब, एक बिंदु INSIDE V2 के समन्वय प्रणाली को लें, (20, 20)। अब, वह बिंदु V1 की समन्वय प्रणाली के अंदर क्या होगा? यही वह विधियां हैं जिनके लिए (बेशक आप खुद की गणना कर सकते हैं, लेकिन वे आपको अतिरिक्त काम बचाते हैं)। रिकॉर्ड के लिए, V1 में बिंदु (30, 30) होगा।

उम्मीद है की यह मदद करेगा।


9

प्रश्न और आपके उत्तर पोस्ट करने के लिए आप सभी का धन्यवाद: इसने मुझे इस तरह से हल करने में मदद की।

मेरे विचार नियंत्रक में यह सामान्य दृश्य है।

उस दृश्य के अंदर कई समूह विचार हैं जो अपने बच्चे के विचारों को ऑटो लेआउट बाधाओं के साथ स्वच्छ बातचीत देने के बजाय थोड़ा अधिक करते हैं।

उन समूहीकरण दृश्यों में से एक के अंदर मेरे पास एक ऐड बटन है जो एक पॉपओवर व्यू कंट्रोलर प्रस्तुत करता है जहां उपयोगकर्ता कुछ जानकारी दर्ज करता है।

view
--groupingView
----addButton

डिवाइस रोटेशन के दौरान व्यू कंट्रोलर को UIPopoverViewControllerDelegate कॉल popoverController: willRepositionPopoverToRect: inView के माध्यम से अलर्ट किया जाता है:

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view
{
    *rect = [self.addButton convertRect:self.addbutton.bounds toView:*view];
}

ऊपर दिए गए पहले दो उत्तरों द्वारा दिए गए स्पष्टीकरण से जो आवश्यक भाग आता है, वह यह था कि मुझे जिस परिधि से बदलने की आवश्यकता थी, वह सीमा थी वह ऐड बटन , न कि उसका फ्रेम।

मैंने इसे अधिक जटिल दृश्य पदानुक्रम के साथ आज़माया नहीं है, लेकिन मुझे संदेह है कि विधि कॉल (inView :) में दिए गए दृश्य का उपयोग करके हम बहु-स्तरीय पत्ती दृश्य प्रकार की कुरूपता की जटिलताओं के आसपास प्राप्त करते हैं।


3
"मुझे ऐड बटन की सीमा से बदलना था, न कि यह फ्रेम है।" - अनिवार्य रूप से यह काम करने के लिए मुझे बहुत बदसूरत फ्रेम कोड से बचाया। इसे इंगित करने के लिए समय निकालने के लिए धन्यवाद
latenitecoder

3

मैंने अपने मामले में आवेदन करने के लिए इस पोस्ट का उपयोग किया। आशा है कि यह भविष्य में एक और पाठक की मदद करेगा।

एक दृश्य केवल अपने तत्काल बच्चों और माता-पिता के विचारों को देख सकता है। यह अपने भव्य माता-पिता या उसके पोते-पोतियों के विचारों को नहीं देख सकता है।

तो, मेरे मामले में, मैं एक भव्य माता पिता दृश्य कहा जाता है self.viewइस में, self.viewमैं subviews कहा जाता है को शामिल किया है self.child1OfView, self.child2OfView। में self.child1OfView, मैंने कहा है self.child1OfView1, नामक साक्षात्कार जोड़े हैं self.child2OfView1
अब अगर मैं शारीरिक रूप से एथेर स्पॉट self.child1OfView1की सीमा के बाहर के क्षेत्र में जाता हूं , तो भीतर की नई स्थिति की गणना करने के लिएself.child1OfViewself.viewself.child1OfView1self.view:

CGPoint newPoint = [self.view convertPoint:self.child1OfView1.center fromView:self.child1OfView];

3

आप नीचे दिए गए कोड को देख सकते हैं ताकि आप समझ सकें कि यह वास्तव में कैसे काम करता है।

    let scrollViewTemp = UIScrollView.init(frame: CGRect.init(x: 10, y: 10, width: deviceWidth - 20, height: deviceHeight - 20))

override func viewDidLoad() {
    super.viewDidLoad()

    scrollViewTemp.backgroundColor = UIColor.lightGray
    scrollViewTemp.contentSize = CGSize.init(width: 2000, height: 2000)
    self.view.addSubview(scrollViewTemp)

    let viewTemp = UIView.init(frame: CGRect.init(x: 100, y: 100, width: 150, height: 150))
    viewTemp.backgroundColor = UIColor.green
    self.view.addSubview(viewTemp)

    let viewSecond = UIView.init(frame: CGRect.init(x: 100, y: 700, width: 300, height: 300))
    viewSecond.backgroundColor = UIColor.red
    self.view.addSubview(viewSecond)

    self.view.convert(viewTemp.frame, from: scrollViewTemp)
    print(viewTemp.frame)


    /*  First take one point CGPoint(x: 10, y: 10) of viewTemp frame,then give distance from viewSecond frame to this point.
     */
    let point = viewSecond.convert(CGPoint(x: 10, y: 10), from: viewTemp)
    //output:   (10.0, -190.0)
    print(point)

    /*  First take one point CGPoint(x: 10, y: 10) of viewSecond frame,then give distance from viewTemp frame to this point.
     */
    let point1 = viewSecond.convert(CGPoint(x: 10, y: 10), to: viewTemp)
    //output:  (10.0, 210.0)
    print(point1)

    /*  First take one rect CGRect(x: 10, y: 10, width: 20, height: 20) of viewSecond frame,then give distance from viewTemp frame to this rect.
     */
    let rect1 = viewSecond.convert(CGRect(x: 10, y: 10, width: 20, height: 20), to: viewTemp)
    //output:  (10.0, 210.0, 20.0, 20.0)
    print(rect1)

    /* First take one rect CGRect(x: 10, y: 10, width: 20, height: 20) of viewTemp frame,then give distance from viewSecond frame to this rect.
     */
    let rect = viewSecond.convert(CGRect(x: 10, y: 10, width: 20, height: 20), from: viewTemp)
    //output:  (10.0, -190.0, 20.0, 20.0)
    print(rect)

}

1

मैं जवाब पढ़ता हूं और यांत्रिकी को समझता हूं लेकिन मुझे लगता है कि अंतिम उदाहरण सही नहीं है। एपीआई डॉक्टर के अनुसार, किसी दृश्य की केंद्र संपत्ति में पर्यवेक्षक की समन्वय प्रणाली में दृश्य का ज्ञात केंद्र बिंदु होता है।

यदि यह मामला है, तो मुझे लगता है कि यह कोई मतलब नहीं होगा कि सुपरवाइज को सबव्यू कॉर्डिनेट सिस्टम से सबव्यू सेंटर के केंद्र को बदलने के लिए कहें क्योंकि वैल्यू सबव्यू कॉर्डिनेट सिस्टम में नहीं है। क्या मतलब होगा विपरीत करने के लिए है कि पर्यवेक्षक समन्वय प्रणाली से एक सबव्यू के रूप में परिवर्तित ...

आप इसे दो तरीकों से कर सकते हैं (दोनों को समान मूल्य प्राप्त करना चाहिए):

CGPoint centerInSubview = [subview convertPoint:subview.center fromView:subview.superview];

या

CGPoint centerInSubview = [subview.superview convertPoint:subview.center toView:subview];

क्या मैं यह समझने में सफल हूं कि यह कैसे काम करना चाहिए?


मेरा उदाहरण गलत था, मैंने जवाब अपडेट कर दिया है। जैसा कि आप कहते हैं, केंद्र की संपत्ति पहले से ही पर्यवेक्षण के समन्वय स्थान में है।
jrturton

1

इन एपीआई का उपयोग करने के बारे में एक और महत्वपूर्ण बिंदु। सुनिश्चित करें कि मूल दृश्य श्रृंखला आपके द्वारा परिवर्तित की गई और देखने के लिए / के बीच में पूर्ण है। उदाहरण के लिए - aView, bView, और cView -

  • aView bView का एक उप-भाग है
  • हम aView.frame को cView में बदलना चाहते हैं

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.