ইউআইভিউজের সেটনিডস লেডআউট, লেআউটআইফিড এবং লেআউটসুভিউগুলির মধ্যে কী সম্পর্ক?


105

যে কেউ মধ্যে সম্পর্ক একটি নির্দিষ্ট ব্যাখ্যা দিতে পারেন UIView's setNeedsLayout, layoutIfNeededএবং layoutSubviewsপদ্ধতি? এবং একটি উদাহরণ বাস্তবায়ন যেখানে তিনটিই ব্যবহৃত হবে। ধন্যবাদ।

আমাকে কী বিভ্রান্ত করে তা হ'ল আমি যদি setNeedsLayoutএই পদ্ধতিটির পরে আমার কাস্টম ভিউটিকে একটি বার্তা প্রেরণ করি তবে এটি এই পদ্ধতির পরে ডাকে layoutSubviews, ঠিক তখনই এড়িয়ে চলে layoutIfNeeded। দস্তাবেজগুলি থেকে আমি প্রত্যাশা করব যে প্রবাহটি setNeedsLayout> কারণগুলির layoutIfNeededজন্য ডাকা হবে> কারণগুলি কল layoutSubviewsকরা হবে।

উত্তর:


104

আমি এখনও এটি নিজেই বের করার চেষ্টা করছি, তাই এটি সন্দেহজনকভাবে নিয়ে নিন এবং এতে ত্রুটি থাকলে আমাকে ক্ষমা করুন।

setNeedsLayoutএটি একটি সহজ একটি: এটি কেবল ইউআইভিউ-র কোথাও একটি পতাকা সেট করে যা এটির প্রয়োজনীয় বিন্যাস হিসাবে চিহ্নিত করে। layoutSubviewsএটি পরবর্তী পুনরায় চিত্রগ্রহণের আগে ভিউটিতে কল করতে বাধ্য করবে । মনে রাখবেন যে সম্পত্তি হিসাবে আপনি অনেক ক্ষেত্রে এই স্পষ্টভাবে কল করতে হবে না autoresizesSubviews। যদি এটি সেট হয়ে থাকে (যা এটি ডিফল্টরূপে হয়) তবে কোনও দৃশ্যের ফ্রেমে যে কোনও পরিবর্তন হলে এর দৃশ্যকে তার সংক্ষিপ্তসারগুলি সরিয়ে দেবে।

layoutSubviewsআপনি যে সমস্ত পদ্ধতিতে আকর্ষণীয় জিনিসটি ব্যবহার করেন তা হ'ল। এটি drawRectলেআউটের সমতুল্য , যদি আপনি করেন। একটি তুচ্ছ উদাহরণ হতে পারে:

-(void)layoutSubviews {
    // Child's frame is always equal to our bounds inset by 8px
    self.subview1.frame = CGRectInset(self.bounds, 8.0, 8.0);
    // It seems likely that this is incorrect:
    // [self.subview1 layoutSubviews];
    // ... and this is correct:
    [self.subview1 setNeedsLayout];
    // but I don't claim to know definitively.
}

আফাইক layoutIfNeededসাধারণত আপনার সাবক্লাসে ওভাররাইড করা বোঝায় না। এটি এমন একটি পদ্ধতি যা আপনি কল করার জন্য বোঝাতে চেয়েছিলেন যখন আপনি এখনই কোনও দৃশ্য দেখাতে চান । অ্যাপলের বাস্তবায়ন দেখতে এরকম কিছু দেখতে পাবে:

-(void)layoutIfNeeded {
    if (self._needsLayout) {
        UIView *sv = self.superview;
        if (sv._needsLayout) {
            [sv layoutIfNeeded];
        } else {
            [self layoutSubviews];
        }
    }
}

আপনি layoutIfNeededএটিকে (এবং এটির তত্ত্বাবধানগুলি প্রয়োজন হিসাবে) অবিলম্বে ছড়িয়ে দেওয়ার জন্য একটি মতামত আহ্বান করবেন ।


2
আপনাকে ধন্যবাদ - খুশি কেউ অবশেষে এর উত্তর দিলেন। এরই মধ্যে আমাকে সেটনিডস ডিসপ্লেতেও ডলার করতে হয়েছিল - যার ফলে ড্রআরেক্ট বলা হয় - এবং কন্টেন্টমোড। শুধুমাত্র কন্টেন্টমোড = ইউআইভিউস কনটেন্টমোড্রেড্রাও যখন ভিউয়ের সীমা পরিবর্তন হয় তখন সেটনিডস ডিসপ্লে ডেকে আনে। অন্যান্য কন্টেন্টমোড পছন্দগুলি কেবলমাত্র ভিউটিকে ছোট করে দেওয়া হতে পারে, কিছু পরিমাণে স্থানান্তরিত করতে পারে বা প্রান্তে সারিবদ্ধ হয়। আমার কাস্টম ইউআইটিএবলভিউসেল ওরিয়েন্টেশন পরিবর্তনগুলিতে পুনরায় আঁকতে চায় নি, এটি কেবলমাত্র স্কেল হবে, যতক্ষণ না আমি কন্টেন্টমোডকে ইউআইভিউকন্টেন্টমোড্রেড্রে সেট না করে।
তারফা

আমি মনে করি সম্ভবত আপনার কোডের [স্ব.সুবভিউ 1 লেআউটসভিউগুলি] [স্ব.সুবউভিউ 1 সেটনিডস লেআউট] দিয়ে প্রতিস্থাপন করা উচিত। লেআউটসুভিউগুলি যেহেতু ওভাররাইড করা বোঝানো হচ্ছে তবে তা অন্য কোনও ভিউ থেকে বা কল করার জন্য নয়। হয় কাঠামো কখন এটি কল করতে হবে তা নির্ধারণ করে (দক্ষতার জন্য এক কলে একাধিক বিন্যাসের অনুরোধকে একত্রিত করে) বা আপনি অপ্রত্যক্ষভাবে ভিউ হায়ারার্কির কোথাও লেআউটআইফনেডকে কল করে করেন।
তারফা

আমার উপরোক্ত মন্তব্যে সংশোধন: "... যেহেতু লেআউটসুভিউগুলি বোঝানো হচ্ছে নিজের থেকে ওভাররাইড করা বা নিজেকে কল করা বা বোঝানো নয় কিন্তু অন্য কোনও ভিউ থেকে আহ্বান করা বা বোঝানো নয় ..."
টারফা

আমি আসলে সম্পর্কে নিশ্চিত নই [subview1 layoutSubviews]। এটি খুব ভাল হতে পারে, যেমন drawRect, আপনি এটি সরাসরি কল করার কথা নয়। তবে আমি নিশ্চিত নই setNeedsLayoutযে লেআউট পর্বের সময় কল করার কারণে একই লেআউট পর্বের সময় দৃশ্যটি ছড়িয়ে দেওয়া হবে বা যদি পরের বার পর্যন্ত দেরি হয়। কারও কাছ থেকে উত্তর পেয়ে ভাল লাগবে যে সত্যিই বুঝতে পারে যে এটি কীভাবে কাজ করে ...
n8 গ্রে

34

আমি এন 8 গ্রে এর উত্তরটি যোগ করতে চাই যে কিছু ক্ষেত্রে আপনাকে তার setNeedsLayoutপরে কল করতে হবে layoutIfNeeded

উদাহরণস্বরূপ বলা যাক যে আপনি ইউআইভিউউ প্রসারিত একটি কাস্টম ভিউ লিখেছেন, যাতে সাবভিউগুলির অবস্থান জটিল এবং অটোরেসাইজিং ম্যাস্ক বা আইওএস 6 অটোলাউট দিয়ে করা যায় না। ওভাররাইড করে কাস্টম পজিশনিং করা যায় layoutSubviews

উদাহরণ হিসাবে, আসুন আমরা বলি যে আপনার কাছে একটি কাস্টম ভিউ রয়েছে যার একটি contentViewসম্পত্তি এবং edgeInsetsসম্পত্তি রয়েছে যা কনটেন্টভিউয়ের চারপাশে মার্জিন সেট করতে দেয়। layoutSubviewsএই মত দেখতে হবে:

- (void) layoutSubviews {
    self.contentView.frame = CGRectMake(
        self.bounds.origin.x + self.edgeInsets.left,
        self.bounds.origin.y + self.edgeInsets.top,
        self.bounds.size.width - self.edgeInsets.left - self.edgeInsets.right,
        self.bounds.size.height - self.edgeInsets.top - self.edgeInsets.bottom); 
}

আপনি যখনই edgeInsetsসম্পত্তি পরিবর্তন করেন আপনি যদি ফ্রেম পরিবর্তন অ্যানিমেট করতে সক্ষম হতে চান তবে আপনাকে edgeInsetsসেটারটি নীচে ওভাররাইড করতে হবে এবং setNeedsLayoutতারপরে কল করতে হবে layoutIfNeeded:

- (void) setEdgeInsets:(UIEdgeInsets)edgeInsets {
    _edgeInsets = edgeInsets;
    [self setNeedsLayout]; //Indicates that the view needs to be laid out 
                           //at next update or at next call of layoutIfNeeded, 
                           //whichever comes first 
    [self layoutIfNeeded]; //Calls layoutSubviews if flag is set
}

এইভাবে, আপনি যদি নিম্নলিখিতটি করেন, যদি আপনি কোনও অ্যানিমেশন ব্লকের অভ্যন্তরে এজসিট সম্পত্তি পরিবর্তন করেন তবে সামগ্রীভিউয়ের ফ্রেম পরিবর্তন অ্যানিমেটেড হবে।

[UIView animateWithDuration:2 animations:^{
    customView.edgeInsets = UIEdgeInsetsMake(45, 17, 18, 34);
}];

যদি আপনি সেটএডিজিনেটস পদ্ধতিতে লেআউটআইফনেডে কলটি যোগ না করেন তবে অ্যানিমেশনটি কাজ করবে না কারণ পরবর্তী লেসনচক্রটিতে লেআউটসুভিউগুলি কল হবে, যা এনিমেশন ব্লকের বাইরে কল করার সমতুল্য।

যদি আপনি কেবল সেটএডিজিনেটস পদ্ধতিতে লেআউটআইফিডকে কল করেন তবে সেটনিডস লেআউট পতাকাটি সেট না হওয়ার কারণে কিছুই ঘটবে না।


4
অথবা [self layoutIfNeeded]প্রান্ত ইনসেটগুলি সেট করার পরে আপনার অ্যানিমেশন ব্লকের মধ্যে কেবল কল করতে সক্ষম হওয়া উচিত ।
স্কট ফিস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.