আমি কখন লেআউট সীমাবদ্ধতাগুলি সক্রিয় / নিষ্ক্রিয় করতে পারি?


104

আমি আইবিতে একাধিক সীমাবদ্ধতার সেট আপ করেছি এবং আমি কিছু স্টেটের উপর নির্ভর করে প্রোগ্রামের মাধ্যমে তাদের মধ্যে টগল করতে চাই। এখানে একটি constraintsAআউটলেট সংগ্রহ রয়েছে যার সবগুলিই আইবি থেকে ইনস্টল হিসাবে চিহ্নিত করা হয়েছে এবং একটি constraintsBআউটলেট সংগ্রহ যা সবগুলি আইবিতে আনইনস্টল করা আছে।

আমি প্রোগ্রামের মতো দুটি সেট এর মধ্যে টগল করতে পারি:

NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)

কিন্তু ... কখন করতে হবে তা বুঝতে পারি না । মনে হচ্ছে আমার একবারে এটি করতে সক্ষম হওয়া উচিত viewDidLoadতবে আমি এটি কাজ করতে পারি না। আমি ফোন করে view.updateConstraints()এবং view.layoutSubviews()সীমাবদ্ধতাগুলি স্থির করার পরে চেষ্টা করেছি , কিন্তু কোন ফলসই হয়নি।

আমি খুঁজে পেয়েছি যে আমি যদি প্রতিটি ক্ষেত্রে সীমাবদ্ধতাগুলি সেট করি তবে viewDidLayoutSubviewsপ্রত্যাশা অনুযায়ী কাজ করে। আমার ধারণা আমি দুটি জিনিস জানতে চাই ...

  1. আমি কেন এই আচরণ পাচ্ছি?
  2. ভিউডিডলড থেকে সীমাবদ্ধতাগুলি সক্রিয় / নিষ্ক্রিয় করা কি সম্ভব?

2
আপনি কী কী কী নিষ্ক্রিয় কনট্রেনট্রেটস এবং অ্যাক্টিভেট কনট্রেন্টগুলি ভিউলিলআউটসুবউভিউগুলিতে কাজ করেছেন? আমি এটি চেষ্টা করেছিলাম, এবং এটি সেখানে বা ভিডলিডে কাজ করে না। ভিউডিডঅ্যাপারে এটি একধরণের কাজ করেছে; নতুন সীমাবদ্ধতা যেখানে লাগানো উচিত সেই দৃশ্যটি উপস্থিত হয়েছিল, তবে আমি ল্যান্ডস্কেপে ঘুরে দেখলে ভিউটি আইবিতে নির্ধারিত সীমাবদ্ধতাগুলির দ্বারা নির্ধারিত অবস্থানে ফিরে যায় (এবং আমি যখন প্রতিকৃতিতে ঘোরার সময় সেখানে থাকি)। সীমাবদ্ধতাগুলিতে লগ করা, সঠিকগুলি (নতুন সক্রিয় হওয়া) দেখিয়েছে। এটি আমার কাছে একটি বাগের মতো মনে হচ্ছে।
rdelmar

1
হ্যাঁ, এগুলি বৈধ ছিল (তারা ভিউডিডঅ্যাপারে কাজ করেছিল), এবং সুপার কল করার দরকার নেই কারণ ভিউইলআলআউটসউবভিউগুলির কোনও ডিফল্ট বাস্তবায়ন নেই (যাইহোক আমি সুপারকে কল করার চেষ্টা করেছি, তবে এতে কোনও তফাত হয়নি)।
rdelmar

1
@ আরদেলমার সবেমাত্র আরও পরীক্ষা দেওয়ার সুযোগ পেয়েছে ... আমি যাচাই করতে পারি যে আপনি বর্ণিত একই আচরণটি আমি পেয়েছিলাম ... ভিউডিড অ্যাপায় প্রথমে কাজ করে, তবে তারপরে ঘোরানো হয়।
tybro0103

3
স্পষ্টতই আপনি এই উদ্দেশ্যে IB তে ইনস্টল না করা হিসাবে সীমাবদ্ধতা চিহ্নিত করতে পারবেন না। এখানে তথ্যটি খুঁজে পেয়েছে : stackoverflow.com/questions/27663249/… এবং এটি আমার জন্য সমস্যার সমাধান করেছে।
স্টিফান

1
আমি আমার প্রতিবন্ধকতাগুলি প্রশ্নের বর্ণনার মতো একইভাবে প্রয়োগ করেছি, তবে আমি তাদের কিছু ভিডিডিয়ায় সক্রিয় / নিষ্ক্রিয় করেছি। এটি কার্যকর হয়েছে তবে আপনি উপাদানগুলি দ্রুত অবস্থান পরিবর্তন করতে দেখতে পেলেন (একটি গৌণ তবে অবাঞ্ছিত সমস্যা)। ViewWillappear বা viewDidLoad এ পরিবর্তন করা কার্যকর হয়নি। তবে এই প্রশ্নটি পড়ার পরে, আমি ভিডিডিআলআউটসুভিউগুলিতে সেই পরিবর্তনটি করার চেষ্টা করেছি। এটি কাজ করেছে এবং অবস্থান পরিবর্তনটি আর ব্যবহারকারীর কাছে দৃশ্যমান নয়। (এটি ViewWillLayoutSubviews এও কাজ করেছে)। সুতরাং যে টিপ জন্য ধন্যবাদ!
শান্তিতে টাইপ

উত্তর:


185

আমি সক্রিয় ও নিষ্ক্রিয় NSLayoutConstraintsমধ্যে viewDidLoad, এবং আমি তা সঙ্গে কোনো সমস্যা হবে না। সুতরাং এটি কাজ করে। আপনার অ্যাপ্লিকেশন এবং আমার মধ্যে সেটআপের মধ্যে অবশ্যই একটি পার্থক্য থাকতে হবে :-)

আমি কেবল আমার সেটআপটি বর্ণনা করব - সম্ভবত এটি আপনাকে নেতৃত্ব দিতে পারে:

  1. আমাকে @IBOutletsসক্রিয় / নিষ্ক্রিয় করার জন্য প্রয়োজনীয় সমস্ত প্রতিবন্ধকতার জন্য আমি সেট আপ করেছি।
  2. এর মধ্যে ViewController, আমি দুর্বল নয় এমন শ্রেণীর বৈশিষ্ট্যগুলিতে সীমাবদ্ধতাগুলি সংরক্ষণ করি। এর কারণ হ'ল আমি খুঁজে পেয়েছি যে সীমাবদ্ধতা নিষ্ক্রিয় করার পরে, আমি এটি পুনরায় সক্রিয় করতে পারি না - এটি শূন্য ছিল। সুতরাং, নিষ্ক্রিয় হয়ে গেলে এটি মুছে ফেলা হবে বলে মনে হয়।
  3. আপনার NSLayoutConstraint.deactivate/activateমতো আমি ব্যবহার করি না, আমি পরিবর্তে constraint.active = YES/ NOব্যবহার করি।
  4. সীমাবদ্ধতা সেট করার পরে, আমি কল করি view.layoutIfNeeded()

131
"দুর্বল নয় এমন শ্রেণীর বৈশিষ্ট্যগুলিতে সীমাবদ্ধতাগুলি সংরক্ষণ করুন" আপনি আমাকে অনেক সময় বাঁচিয়েছেন, ধন্যবাদ!
OpenUserX03

10
"আমি শ্রেণিবদ্ধ সম্পত্তিগুলিতে সীমাবদ্ধতাগুলি সংরক্ষণ করি যা দুর্বল নয়": এটি আমার প্রচুর হৃদয় ব্যাথা রক্ষা করেছে। আমি জানতাম না যে আমি কোনও নির্বাচককে কোনও শূন্য বস্তুতে কল করছি। ধন্যবাদ !!
স্ট্যাটিক0886

4
গুরুত্বপূর্ণ যে "নিষ্ক্রিয়" সীমাবদ্ধতাগুলি স্বয়ংক্রিয় বিন্যাস দ্বারা উপেক্ষা করা হয় না, সেগুলি মুছে ফেলা হয় Important সক্রিয়করণ / নিষ্ক্রিয় সীমাবদ্ধতাগুলি এগুলি আসলে যুক্ত করে এবং সেগুলি সরিয়ে দেয়। আমি পূর্বে নির্ধারিত প্রতিবন্ধকতাগুলি .active = falseসক্রিয় করার জন্য সেট না করা পর্যন্ত এগুলি উপেক্ষা করা হবে বলে প্রত্যাশিত প্রতিবন্ধকতাগুলি যুক্ত করার পরে একটি বিবাদযুক্ত অটো লেআউটটি ডিবাগ করার জন্য কিছু সময় ব্যয় করেছি।
lbarbosa

1
শ্রেণীর বৈশিষ্ট্যগুলিতে সীমাবদ্ধতাগুলি সংরক্ষণ করুন যা দুর্বল নয়, ঠিক আছে এটি অনেক সময় সাশ্রয় করে, আমি এগুলি ছাড়া কিছু মিশ্র ফলাফল পাচ্ছিলাম। ধন্যবাদ মানুষ!
মেগাএএমএএনএক্স

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

52

হতে পারে আপনি আপনার পরীক্ষা করতে পারেন @properties, weakসঙ্গে প্রতিস্থাপনstrong

কখনও কখনও এটি active = NOসেট কারণ self.yourConstraint = nil, যাতে আপনি self.yourConstraintআবার ব্যবহার করতে পারবেন না ।


5
সুইফট ল্যাঙ্গুয়েজ গাইডে যেমন বলা হয়েছে , বৈশিষ্ট্যগুলি ডিফল্টরূপে শক্তিশালী তাই আপনি কেবল সরাতে পারেন এবং এটি weakএটি করবে।
জোনাথন ক্যাবেরা

30
override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}

1
কারণ আমার ভিউ কন্ট্রোলার হ'ল চাইল্ড ভিউ কন্ট্রোলার - এটি "didLayoutSubviews" এ করা একমাত্র উপায় বলে মনে হয় !! অবগতির জন্য।
ট্যালো

এটিই একমাত্র বৈধ উত্তর
ইউনুস এরেন গজেল

@ টাল আপনি কি চাইল্ড ভিউ কন্ট্রোলারে নিজেই বাধা বা সংক্ষিপ্তসারগুলি বোঝাতে চাইছেন?
স্টিফান

এটি সেরা এক
ACAkgul

14

আমি বিশ্বাস করি যে আপনি যে সমস্যার মুখোমুখি viewDidLoad()হচ্ছেন এটি আফটার নাম না বলা পর্যন্ত তাদের মতামতগুলিতে যুক্ত না করা বাধাগুলির কারণে । আপনার কাছে অনেকগুলি বিকল্প রয়েছে:

ক) আপনি আপনার লেআউটের সীমাবদ্ধতাগুলি একটি আইবিআউটলেটতে সংযুক্ত করতে পারেন এবং এই উল্লেখগুলি দ্বারা আপনার কোডে এগুলি অ্যাক্সেস করতে পারেন। যেহেতু আউটলেটগুলি viewDidLoad()কিক্স অফ করার আগে সংযুক্ত রয়েছে , তাই সীমাবদ্ধতাগুলি অ্যাক্সেসযোগ্য হওয়া উচিত এবং আপনি সেগুলি সক্রিয় এবং নিষ্ক্রিয় করতে চালিয়ে যেতে পারেন।

খ) আপনি যদি ইউআইভিউ'র constraints()ফাংশনটি বিভিন্ন সীমাবদ্ধতাগুলি অ্যাক্সেসের জন্য ব্যবহার করতে চান তবে আপনাকে অবশ্যই viewDidLayoutSubviews()এটি বন্ধ করে দেওয়ার জন্য অপেক্ষা করতে হবে, যেহেতু কোনও নিব থেকে একটি ভিউ কন্ট্রোলার তৈরি করার পরে এটি প্রথম পয়েন্ট যা এতে কোনও ইনস্টলড বাধা থাকবে। layoutIfNeeded()আপনার কাজ শেষ হলে কল করতে ভুলবেন না । এটির অসুবিধাটিও রয়েছে যে প্রয়োগ করতে যদি কোনও পরিবর্তন ঘটে থাকে তবে লেআউট পাসটি দু'বার সম্পাদিত হবে এবং আপনাকে অবশ্যই নিশ্চিত করতে হবে যে অসীম লুপটি ট্রিগার হওয়ার কোনও সম্ভাবনা নেই।

তাত্ক্ষণিকতার একটি দ্রুত শব্দ: অক্ষম প্রতিবন্ধকতাগুলি পদ্ধতি দ্বারা ফিরে আসে না constraints() ! এর অর্থ যদি আপনি পরে আবার চালু করার অভিপ্রায় বাধা নিষ্ক্রিয় করেন তবে আপনাকে এটির একটি রেফারেন্স রাখতে হবে।

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


10

আপনি priorityসম্পত্তি "সক্ষম" এবং তাদের "অক্ষম" করতে সক্ষম করুন (সক্ষম করার জন্য 750 মান এবং উদাহরণস্বরূপ অক্ষম করার জন্য 250)। কিছু কারণে activeBOOL পরিবর্তন করা আমার UI- তে কোনও প্রভাব ফেলেনি। layoutIfNeededভিডিডলিডে বা তার পরে যে কোনও সময় প্রয়োজন নেই এবং সেট ও পরিবর্তন করা যায়।


একটি খুব ভাল পরামর্শ। সীমাবদ্ধতার অগ্রাধিকার পরিবর্তন কাজ করে viewWillTransition(to:, with:)বা viewWillLayoutSubviews()আপনি আপনার সমস্ত বিকল্প সীমাবদ্ধতা একটি স্টোরিবোর্ডে "ইনস্টলড" হিসাবে রাখতে পারেন। সীমাবদ্ধতা অগ্রাধিকার অ-প্রয়োজনীয় থেকে পরিবর্তিত হতে পারে না, তাই নীচের মানগুলি ব্যবহার করুন 1000। অন্যদিকে, সক্রিয়করণ (যুক্ত করা) এবং নিষ্ক্রিয়করণ (অপসারণ) সীমাবদ্ধতাগুলি কেবলমাত্র কাজ করে viewDidLayoutSubviews()এবং -s-তে strong @IBOutletরেফারেন্স রাখার প্রয়োজন NSLayoutConstraint
গ্যারি

"কিছু কারণে সক্রিয় BOOL পরিবর্তন করা আমার ইউআই তে কোনও প্রভাব ফেলেনি"। এখানে ভিত্তি করে । আমি মনে করি আপনি রানটাইমের সময় 1000 অগ্রাধিকার সহ কোনও প্রতিবন্ধকতা পরিবর্তন করতে পারবেন না। আপনি যদি এটি ডিএসিটিভ করতে চান তবে আপনার প্রাথমিক অগ্রাধিকারটি 999 বা তার চেয়ে কমতে সেট করা উচিত ....
হানি

আমি এই উক্তিটির সাথে একমত নই কারণ এটি ডিবাগ করতে সমস্যা তৈরি করতে পারে এবং প্রশ্নের উত্তর দেয় না। অগ্রাধিকার 250 এ সেট করা সীমাবদ্ধতাটিকে "নিষ্ক্রিয়" করবে না, এটি এখনও প্রভাব ফেলবে এবং লেআউটটিকে প্রভাবিত করবে। এটি বেশিরভাগ ক্ষেত্রে সীমাবদ্ধতাটিকে "নিষ্ক্রিয় করে" বলে মনে হতে পারে তবে অবশ্যই সব ক্ষেত্রে নয়। (বিশেষত, এই প্রশ্নের উত্তর খুঁজতে আমাকে নেতৃত্ব দেওয়ার ক্ষেত্রে নয়)
টুমাটা

এটি ক্র্যাশ হতে পারে এবং যেমন "ইনস্টলড সীমাবদ্ধতা (বা তদ্বিপরীত) না নেওয়ার প্রয়োজন থেকে অগ্রাধিকারকে রূপান্তরিত করা সমর্থনযোগ্য নয় You আপনি অগ্রাধিকার 250 কে পাস করেছেন এবং বিদ্যমান অগ্রাধিকারটি ছিল 1000" "
কার্তিক রমেশ

8

অব্যবহৃত বাধা নিষ্ক্রিয় করার উপযুক্ত সময়:

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    self.myLittleConstraint.active = NO;
}

মনে রাখবেন যে viewWillLayoutSubviewsএকাধিক বার বলা যেতে পারে, তাই এখানে কোন ভারী গণনা, ঠিক আছে?

দ্রষ্টব্য: আপনি যদি পরে কিছু প্রতিবন্ধকতাগুলি প্রতিক্রিয়া জানাতে চান তবে সর্বদা strongসেগুলি উল্লেখ করুন।


2
আমার কাছে একমাত্র নির্ভরযোগ্য উপায় হ'ল সীমাবদ্ধতাগুলি সামঞ্জস্য করা viewDidLayoutSubviews()। সীমাবদ্ধতাগুলিকে সামঞ্জস্য viewWillLayoutSubviews()করা আমার ক্ষেত্রে কার্যকর হয় না।
পেটারসিন

6

যখন একটি দৃশ্য তৈরি করা হয় তখন নিম্নলিখিত জীবনচক্রের পদ্ধতিগুলি ক্রমে ডাকা হয়:

  1. loadView
  2. viewDidLoad
  3. viewWillAppear
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear

এখন আপনার প্রশ্ন।

  1. আমি কেন এই আচরণ পাচ্ছি?

উত্তর: কারণ আপনি যখন দেখার মতামতগুলিতে সীমাবদ্ধতাগুলি সেট করার চেষ্টা করেন তখন সীমাবদ্ধতা সেট করা যায় viewDidLoadনা। এটা শুধুমাত্র পরে এর viewDidLayoutSubviewsযে দৃশ্য নির্ধারিত সীমা চূড়ান্ত করা হয়।

  1. ভিউডিডলড থেকে সীমাবদ্ধতাগুলি সক্রিয় / নিষ্ক্রিয় করা কি সম্ভব?

উত্তর: না। কারণ উপরে বর্ণিত।


ভিউ কনট্রোলার লাইফসাইকের আপনার বিবরণে আপনি কীভাবে প্রথম ভিউটি লোড করা হয় এবং তারপরে ভিউডিডলড বলা হয় সে সম্পর্কে কথা বলেছেন। তবুও আপনি এও বলেছিলেন যে ভিউডিডোড বলা হওয়ার সময় দ্বারা দৃশ্যটি তৈরি হয় না, এটি স্পষ্টতই একটি বৈপরীত্য। এছাড়াও, আপনি নিজের জন্য পরীক্ষা করে দেখতে পারেন যে ভিউডিডডোড বলা হওয়ার সময় দিয়ে তৈরি করা হয়েছে কারণ আপনি দৃশ্যে সাবউভিউ যুক্ত করতে পারেন।
এবেকারস্মিথ

ভিউডিডলডটি ঠিক হওয়া উচিত যেহেতু দর্শনগুলি তৈরি করা হয় এবং লোড করা হয় ... বাস্তবে যেখানে আপনি সীমাবদ্ধতাগুলি সক্রিয় করেন সেখানে মূলত কর্মক্ষমতা চলে আসে। আমি অনুমান করছি যে আসল সমস্যাটি যেখানে সীমাবদ্ধতাগুলি সক্রিয় হয়েছিল তার সাথে সম্পর্কিত নয়। stackoverflow.com/questions/19387998/…
গাবে

আমার উত্তর আরও পরিষ্কার হওয়ার জন্য আমি উত্তর সম্পাদনা করেছি
সুমিত

1

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

প্রধান জিনিস হ'ল নিয়মিতভাবে ওভাররাইডটি পুনরায় ব্যবহার করা updateConstraintsএবং সীমাবদ্ধতার ক্রিয়াকলাপগুলিকে পৃথক করা নয়, যতক্ষণ আপনি updateConstraintআপনার প্রথম সূচনা এবং বিন্যাসের পরে এস কল করেন । দেখার চক্রটি কোথায় রয়েছে তার পরে এটি মনে হয় না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.