যখন অ্যাল লেআউট ব্যবহার করা হচ্ছে তখন আমি কীভাবে কোনও ক্যালায়ারের অ্যাঙ্কর পয়েন্টটি সামঞ্জস্য করব?


161

দ্রষ্টব্য : এই প্রশ্নটি জিজ্ঞাসা করার পর থেকে বিষয়গুলি এগিয়ে গেছে; একটি ভাল সাম্প্রতিক ওভারভিউ জন্য এখানে দেখুন ।


স্বয়ংক্রিয় বিন্যাসের আগে, আপনি ফ্রেম সংরক্ষণ করে, অ্যাঙ্কর পয়েন্টটি সেট করে না দিয়ে এবং ফ্রেমটি পুনরুদ্ধার করে ভিউটি সরিয়ে না দিয়ে কোনও ভিউয়ের স্তরের অ্যাঙ্কার পয়েন্ট পরিবর্তন করতে পারেন।

একটি স্বয়ংক্রিয় বিন্যাস বিশ্বে, আমরা ফ্রেম আর সেট করি না, তবে দৃশ্যের অবস্থান যেখানে আমরা এটি চাই সেখানে সামঞ্জস্য করার সীমাবদ্ধতা মনে হয় না। আপনি আপনার দৃষ্টিভঙ্গি পুনরায় স্থাপন করতে সীমাবদ্ধতাগুলি হ্যাক করতে পারেন তবে ঘোরানো বা অন্যান্য আকার পরিবর্তনকারী ইভেন্টগুলিতে এগুলি আবার অবৈধ হয়ে যায়।

নিম্নলিখিত উজ্জ্বল ধারণাটি কাজ করে না কারণ এটি "লেআউট বৈশিষ্ট্যের (বাম এবং প্রস্থ) এর অবৈধ জুড়ি" তৈরি করে:

layerView.layer.anchorPoint = CGPointMake(1.0, 0.5);
// Some other size-related constraints here which all work fine...
[self.view addConstraint:
    [NSLayoutConstraint constraintWithItem:layerView
                                 attribute:NSLayoutAttributeLeft
                                 relatedBy:NSLayoutRelationEqual 
                                    toItem:layerView 
                                 attribute:NSLayoutAttributeWidth 
                                multiplier:0.5 
                                  constant:20.0]];

আমার উদ্দেশ্য এখানে ছিল বাম প্রান্তটি layerViewঅ্যাডজাস্ট করা অ্যাঙ্কর পয়েন্ট সহ তার প্রস্থের অর্ধেকের চেয়ে 20 টি (সুপারভিউয়ের বাম প্রান্ত থেকে যে দূরত্বটি আমি ইনসেট চাই তা) স্থাপন করা।

অটো লেআউটটি রেখে দেওয়া ভিউয়ের অবস্থান পরিবর্তন না করেই কি অ্যাঙ্কর পয়েন্ট পরিবর্তন করা সম্ভব? আমার কি হার্ডকোডযুক্ত মানগুলি ব্যবহার এবং প্রতিটি ঘোরার ক্ষেত্রে সীমাবদ্ধতা সম্পাদনা করা উচিত? আমি আশা করি না।

আমার অ্যাঙ্কর পয়েন্টটি পরিবর্তন করা দরকার যাতে আমি যখন ভিউটিতে কোনও রূপান্তর প্রয়োগ করি তখন আমি সঠিক ভিজ্যুয়াল এফেক্ট পাই।


আপনার এখানে যা আছে ঠিক তা দেওয়া দেখে মনে হচ্ছে আপনি উপরের কোডটি কাজ করে থাকলেও অস্পষ্ট লেআউটগুলি শেষ করতে চলেছেন। কিভাবে layerViewতার প্রস্থ জানেন? এটি কি তার ডান দিকটি অন্য কিছুর সাথে লেগে আছে?
জন এস্ট্রোপিয়া

//Size-related constraints that work fineএটিতে আচ্ছাদিত - স্তর দৃশ্যের প্রস্থ এবং উচ্চতাটি সুপারভিউ থেকে নেওয়া।
jrturton

উত্তর:


361

[সম্পাদনা: সতর্কতা: পুরো আগত আলোচনাটি সম্ভবত iOS বা 8 দ্বারা কমপক্ষে ভারাক্রমে বা কমিয়ে দেওয়া হবে, যা ভিউ ট্রান্সফর্মটি প্রয়োগ করার সময় লেআউটটিকে ট্রিগার করার ভুল আর করতে পারে না]]

অটোলেআউট বনাম দেখুন রূপান্তর

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

অন্য কথায়, সীমাবদ্ধতা যাদু নয়; এগুলি কেবল একটি করণীয় তালিকা।layoutSubviewsকরণীয় তালিকাটি সম্পন্ন হয়। এবং এটি ফ্রেম সেট করে এটি করে।

আমি বাগ হিসাবে এটি সম্পর্কিত সাহায্য করতে পারি না। যদি আমি এই ভিউটিতে এই রূপান্তরটি প্রয়োগ করি:

v.transform = CGAffineTransformMakeScale(0.5,0.5);

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

[আসলে, এখানে একটি দ্বিতীয় বিস্ময় রয়েছে: তাত্ক্ষণিকভাবে একটি ভিউ ট্রিগার লেআউটে রূপান্তর প্রয়োগ করা। এটি আমার কাছে অন্য একটি বাগ বলে মনে হচ্ছে। অথবা সম্ভবত এটি প্রথম বাগের হৃদয়। আমি যা প্রত্যাশা করব তা হ'ল কমপক্ষে বিন্যাসের সময় পর্যন্ত কোনও রূপান্তর নিয়ে পালাতে সক্ষম হবেন, উদাহরণস্বরূপ ডিভাইসটি ঘোরানো হয়েছে - ঠিক যেমন আমি বিন্যাসের সময় অবধি ফ্রেম অ্যানিমেশন দিয়ে দূরে যেতে পারি। তবে বাস্তবে বিন্যাসের সময়টি তাত্ক্ষণিক, যা কেবল ভুল বলে মনে হচ্ছে]]

সমাধান 1: কোনও সীমাবদ্ধতা নেই

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

সমাধান 2: কেবলমাত্র উপযুক্ত সীমাবদ্ধতা ব্যবহার করুন

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

NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
    if (con.firstItem == self.otherView || con.secondItem == self.otherView)
        [cons addObject:con];

[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];

আপশটটি হ'ল যদি আপনার কোনও বাধা যদি কোনও দৃশ্যের ফ্রেমকে প্রভাবিত করে তবে অটোলেআউট ভিউটির ফ্রেমটিকে স্পর্শ করবে না - যা রূপান্তর জড়িত থাকার পরে আপনি যা করছেন ঠিক সেটাই।

সমাধান 3: একটি সাবভিউ ব্যবহার করুন

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

এখানে একটি উদাহরণ দেওয়া আছে:

এখানে চিত্র বর্ণনা লিখুন

হোয়াইট ভিউ হোস্ট ভিউ; আপনি ভেবেছিলেন যে এটি স্বচ্ছ এবং অতএব অদৃশ্য। লাল দৃষ্টিভঙ্গিটি তার পর্যালোচনা, হোস্ট ভিউয়ের কেন্দ্রে এর কেন্দ্রটি পিন করে অবস্থিত by এখন আমরা কোনও সমস্যা ছাড়াই তার কেন্দ্রের চারপাশে লাল ভিউ স্কেল এবং ঘোরাইতে পারি এবং সত্যই চিত্রণটি দেখায় যে আমরা এটি করেছি:

self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);

এবং ইতিমধ্যে হোস্ট ভিউতে থাকা সীমাবদ্ধতাগুলি ডিভাইসটি ঘোরানোর সাথে সাথে এটি সঠিক জায়গায় রাখে।

সমাধান 4: পরিবর্তে স্তর পরিবর্তনগুলি ব্যবহার করুন

রূপান্তরগুলি দেখার পরিবর্তে, স্তর রূপান্তরগুলি ব্যবহার করুন, যা বিন্যাসকে ট্রিগার করে না এবং এই কারণে সীমাবদ্ধতার সাথে তাত্ক্ষণিক দ্বন্দ্ব সৃষ্টি করে না।

উদাহরণস্বরূপ, এই সাধারণ "থ্রোব" ভিউ অ্যানিমেশনটি অটোলেটের আওতায় ভালভাবে ভেঙে যেতে পারে:

[UIView animateWithDuration:0.3 delay:0
                    options:UIViewAnimationOptionAutoreverse
                 animations:^{
    v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
    v.transform = CGAffineTransformIdentity;
}];

যদিও শেষ পর্যন্ত দৃশ্যের আকারে কোনও পরিবর্তন হয়নি, কেবল transformকারণগুলির বিন্যাসটি ঘটতে কেবল সেট করা হয়েছে এবং সীমাবদ্ধতাগুলি ভিউটিকে চারপাশে ঝাঁপিয়ে তুলতে পারে। (এটি কি ত্রুটির মতো লাগে বা কী?) তবে আমরা যদি কোর অ্যানিমেশন (সিএবিসিক অ্যানিমেশন ব্যবহার করে এবং দৃশ্যের স্তরের সাথে অ্যানিমেশনটি প্রয়োগ করে) একই জিনিস করি তবে বিন্যাসটি ঘটে না এবং এটি সূক্ষ্মভাবে কাজ করে:

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];

3
রূপান্তরটি আমাকে সমস্যার কারণ নয়, কেবল নতুন অ্যাঙ্কার পয়েন্টটি সেট করছে। আমি সীমাবদ্ধতাগুলি সরিয়ে এবং অটোরেসাইজিং মাস্কটি চেষ্টা করার চেষ্টা করব।
jrturton

1
আমি এখানে কিছু বুঝতে পারি না। সমাধান 4: যখন কোনও ব্যাকিং লেয়ারে ট্রান্সফর্মটি প্রয়োগ করা হয় যা অটোলেআউটকেও প্রভাবিত করে, কারণ দর্শনটির রূপান্তর সম্পত্তি ব্যাকিং স্তরের রূপান্তরকে নির্দেশ করছে
লুকা বার্তোলেটি

1
@ অ্যানডি বিপরীতে, আইওএস 8-এ সমস্যাটি সম্পূর্ণভাবে চলে গেছে এবং আমার পুরো উত্তর অপ্রয়োজনীয়
ম্যাট

1
@ সুঙ্কাস আমি আপনার ইস্যুতে উত্তর দিয়েছি।
বেন সিনক্লেয়ার

2
আইওএস 8-এ, লেয়ার ট্রান্সফর্ম এছাড়াও অটো
লেআউটটিকে

41

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

শিরোনাম ফাইলটি দেখতে এমন দেখাচ্ছে যাতে আপনি আপনার পছন্দ মতামতটি সরাসরি ইন্টারফেস বিল্ডারের সাথে সংযুক্ত করতে পারেন

#import <UIKit/UIKit.h>

@interface BugFixContainerView : UIView
@property(nonatomic,strong) IBOutlet UIImageView *knobImageView;
@end

এবং এম ফাইলের মতো বিশেষ কোড প্রয়োগ করা হয়:

#import "BugFixContainerView.h"

@implementation BugFixContainerView
- (void)layoutSubviews
{
    static CGPoint fixCenter = {0};
    [super layoutSubviews];
    if (CGPointEqualToPoint(fixCenter, CGPointZero)) {
        fixCenter = [self.knobImageView center];
    } else {
        self.knobImageView.center = fixCenter;
    }
}
@end

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

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


5
এই পোস্ট করার জন্য আপনাকে ধন্যবাদ। যেহেতু আমি আমার উত্তর লিখেছি, আমি অবশ্যই ওভাররাইডিংয়ের মান বুঝতে পেরেছি layoutSubviews। আমি কেবল যুক্ত করব, যদিও এখানে অ্যাপল নিখুঁতভাবে আপনাকে যা করতে হবে তা আমার মনে হয় তাদের করা উচিত ছিল (অটোলেআউট তাদের বাস্তবায়নে) পাশাপাশি বরাবর।
ম্যাট

আপনি ঠিক বলেছেন তবে এটি আমার মনে হয় সত্যই ইস্যুটির সাথে সম্পর্কিত নয়। যেহেতু তারা উপরের কোডটি সরবরাহ করেছে আমি তাতে খুশি!
সেনস্লেন

4
এটি দুঃখজনক এবং অযৌক্তিক যে অটোলেআউট দল নিজেই ভিউ সিস্টেমে দীর্ঘকালীন এবং স্বজ্ঞাত আচরণটি কীভাবে ভেঙে দেয় তার চারপাশে কাজ করার জন্য একটি কাস্টম ধারক সাবক্লাস তৈরি করার পরামর্শ দেয়।
অ্যালগাল

8

আমি একটি সহজ উপায় খুঁজে। এবং এটি আইওএস 8 এবং আইওএস 9 এ কাজ করে।

ফ্রেম-ভিত্তিক লেআউট ব্যবহার করার সময় অ্যাঙ্করপয়েন্টটি অ্যাডজাস্ট করার মতো:

let oldFrame = layerView.frame
layerView.layer.anchorPoint = newAnchorPoint
layerView.frame = oldFrame

আপনি যখন অটো লেআউটটির সাথে ভিউয়ের অ্যাঙ্করটি সামঞ্জস্য করেন, আপনি একই জিনিসটি করেন তবে সীমাবদ্ধতার পথে। অ্যাঙ্করপয়েন্টটি যখন (০.০, ০.০) থেকে (১, ০.০) পরিবর্তিত হয়, স্তর স্তরটি দেখার প্রস্থের অর্ধেক দৈর্ঘ্যের সাথে বাম দিকে সরে যায়, সুতরাং আপনাকে এর জন্য ক্ষতিপূরণ করতে হবে।

আমি প্রশ্নটির প্রতিবন্ধকতা বুঝতে পারি না o সুতরাং, ধরে নিন যে আপনি একটি ধ্রুবক সহ সুপারভিউ সেন্টারএক্সের সাথে তুলনামূলকভাবে একটি সেন্টার এক্স সীমাবদ্ধ করেছেন: স্তরভিউ.সেন্টারএক্স = সুপারভিউ.সেন্টারএক্স + ধ্রুবক

layerView.layer.anchorPoint = CGPoint(1, 0.5)
let centerXConstraint = .....
centerXConstraint.constant = centerXConstraint.constant + layerView.bounds.size.width/2

আমার বন্ধু আপনার জন্য সেরা বিয়ারের গ্লাস। এটি এত সূক্ষ্ম কাজ: D
Błażej

3

আপনি যদি অটো লেআউট ব্যবহার করছেন তবে আমি দেখতে পাচ্ছি না যে ম্যানুয়ালি সেটিং পজিশনটি দীর্ঘ সময়ের মধ্যে কীভাবে কাজ করবে কারণ অবশেষে অটো লেআউটটি আপনি যে অবস্থানের মানটি সেট করেছেন এটি তার নিজস্ব বিন্যাস গণনা করার সময় ক্লাব করবে ber

পরিবর্তে, যা দরকার তা হ'ল অ্যাঙ্করপয়েন্টটি সেট করে উত্পাদিত পরিবর্তনগুলির জন্য ক্ষতিপূরণ দিতে লেআউটটির সীমাবদ্ধতাগুলি সংশোধন করা। নিম্নলিখিত ফাংশনটি অপ্রত্যাশিত দর্শনের জন্য এটি করে।

/**
  Set the anchorPoint of view without changing is perceived position.

 @param view view whose anchorPoint we will mutate
 @param anchorPoint new anchorPoint of the view in unit coords (e.g., {0.5,1.0})
 @param xConstraint an NSLayoutConstraint whose constant property adjust's view x.center
 @param yConstraint an NSLayoutConstraint whose constant property adjust's view y.center

  As multiple constraints can contribute to determining a view's center, the user of this
 function must specify which constraint they want modified in order to compensate for the
 modification in anchorPoint
 */
void SetViewAnchorPointMotionlesslyUpdatingConstraints(UIView * view,CGPoint anchorPoint,
                                                       NSLayoutConstraint * xConstraint,
                                                       NSLayoutConstraint * yConstraint)
{
  // assert: old and new anchorPoint are in view's unit coords
  CGPoint const oldAnchorPoint = view.layer.anchorPoint;
  CGPoint const newAnchorPoint = anchorPoint;

  // Calculate anchorPoints in view's absolute coords
  CGPoint const oldPoint = CGPointMake(view.bounds.size.width * oldAnchorPoint.x,
                                 view.bounds.size.height * oldAnchorPoint.y);
  CGPoint const newPoint = CGPointMake(view.bounds.size.width * newAnchorPoint.x,
                                 view.bounds.size.height * newAnchorPoint.y);

  // Calculate the delta between the anchorPoints
  CGPoint const delta = CGPointMake(newPoint.x-oldPoint.x, newPoint.y-oldPoint.y);

  // get the x & y constraints constants which were contributing to the current
  // view's position, and whose constant properties we will tweak to adjust its position
  CGFloat const oldXConstraintConstant = xConstraint.constant;
  CGFloat const oldYConstraintConstant = yConstraint.constant;

  // calculate new values for the x & y constraints, from the delta in anchorPoint
  // when autolayout recalculates the layout from the modified constraints,
  // it will set a new view.center that compensates for the affect of the anchorPoint
  CGFloat const newXConstraintConstant = oldXConstraintConstant + delta.x;
  CGFloat const newYConstraintConstant = oldYConstraintConstant + delta.y;

  view.layer.anchorPoint = newAnchorPoint;
  xConstraint.constant = newXConstraintConstant;
  yConstraint.constant = newYConstraintConstant;
  [view setNeedsLayout];
}

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

আপনি যদি কেবলমাত্র অস্থায়ী অ্যানিমেশনের জন্য ট্রান্সফর্মটি ব্যবহার করেন, তবে উপরের যেটি যথেষ্ট হতে পারে যেহেতু আমি বিশ্বাস করি না যে অটো লেআউটটি বিমানের অ্যানিমেশনগুলিকে চিত্রগুলি উপস্থাপন থেকে বাধা দেবে যা সম্পূর্ণরূপে সীমাবদ্ধতার ক্ষণস্থায়ী লঙ্ঘনের প্রতিনিধিত্ব করে।


আমি দুর্ভাগ্যক্রমে রূপান্তর ব্যবহার করছি। অবস্থান নির্ধারণ করা ঠিক আছে কারণ প্রতিবার দৃষ্টিভঙ্গিটি নির্ধারণের পরে পদ্ধতিটি বলা হয়, তাই এটি আঁটসাঁট হয়ে যায় না। আমি ভাবছি ওভাররাইড লেআউটআরেক্ট আরও ভাল সমাধান হতে পারে (আপনার আগের উত্তরগুলির মধ্যে একটিতে উল্লিখিত) তবে আমি এখনও এটি চেষ্টা করি নি।
jrturton

যাইহোক, এখানে আমি ব্যবহার করছি একটি পরীক্ষার রগ। : এটা মহান যদি কেউ এই মূর্ত আউট হবে github.com/algal/AutolayoutAnchorPointTestRig
algal

এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। @ ম্যাট এর উত্তর এমনকি অ্যাঙ্কার পয়েন্ট সম্পর্কে নয়।
আইলিয়ান ওনোফ্রেই

3

tl: dr: আপনি কোনও একটি প্রতিবন্ধকতার জন্য একটি আউটলেট তৈরি করতে পারেন যাতে এটি সরিয়ে আবার ফিরে পাওয়া যায়।


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

সবচেয়ে ছোট উদাহরণের জন্য বাধাগুলি আমি ভাবতে পারি।

এরপরে আমি যে দর্শনটি ঘুরতে চলেছে এবং কেন্দ্রের x প্রান্তিককরণ সীমাবদ্ধতার জন্য একটি আউটলেট যুক্ত করেছি।

@property (weak, nonatomic) IBOutlet UIView *rotatingView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *xAlignmentContstraint;

পরে viewDidAppearআমি নতুন অ্যাঙ্কার পয়েন্ট গণনা করি

UIView *view = self.rotatingView;

CGPoint rotationPoint = // The point I'm rotating around... (only X differs)
CGPoint anchorPoint = CGPointMake((rotationPoint.x-CGRectGetMinX(view.frame))/CGRectGetWidth(view.frame),
                                  (rotationPoint.y-CGRectGetMinY(view.frame))/CGRectGetHeight(view.bounds));

CGFloat xCenterDifference = rotationPoint.x-CGRectGetMidX(view.frame);

view.layer.anchorPoint = anchorPoint;

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

[self.view removeConstraint:self.xAlignmentContstraint];
self.xAlignmentContstraint = [NSLayoutConstraint constraintWithItem:self.rotatingView
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1.0
                                                           constant:xDiff];
[self.view addConstraint:self.xAlignmentContstraint];
[self.view needsUpdateConstraints];

অবশেষে আমি কেবল ঘোরানো ভিউতে ঘূর্ণন অ্যানিমেশনটি যুক্ত করি।

CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotate.toValue = @(-M_PI_2);
rotate.autoreverses = YES;
rotate.repeatCount = INFINITY;
rotate.duration = 1.0;
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

[view.layer addAnimation:rotate forKey:@"myRotationAnimation"];

ঘোরানো স্তরটি দেখতে ডিভাইসটি ঘোরানোর সময় বা অন্যথায় এটি সীমাবদ্ধতাগুলি আপডেট করার সময়ও কেন্দ্রীভূত থাকে (যা এটি হওয়া উচিত) হিসাবে দেখায়। নতুন সীমাবদ্ধতা এবং পরিবর্তিত অ্যাঙ্কর পয়েন্ট দৃশ্যত একে অপরকে বাতিল করে।


1
এটি আমার নির্দিষ্ট পরিস্থিতির জন্য কাজ করবে, দেখে মনে হচ্ছে এটি একটি দুর্দান্ত সাধারণ সমাধান সম্ভব নয়।
Jrturton

1

আমার বর্তমান সমাধানটি হ'ল স্তরের অবস্থানটি নিজেই সামঞ্জস্য করা viewDidLayoutSubviews। এই কোডটি layoutSubviewsএকটি ভিউ সাবক্লাসের জন্যও ব্যবহার করা যেতে পারে তবে আমার ক্ষেত্রে আমার দৃষ্টিভঙ্গি একটি ভিউ কন্ট্রোলারের অভ্যন্তরে একটি শীর্ষ স্তরের দৃষ্টিভঙ্গি, সুতরাং এর অর্থ হ'ল আমাকে ইউআইভিউ সাবক্লাস করতে হবে না।

এটি অনেক বেশি পরিশ্রমের মতো বলে মনে হচ্ছে তাই অন্যান্য উত্তর সর্বাধিক স্বাগত।

-(void)viewDidLayoutSubviews
{
    for (UIView *view in self.view.subviews)
    {
        CGPoint anchorPoint = view.layer.anchorPoint;
        // We're only interested in views with a non-standard anchor point
        if (!CGPointEqualToPoint(CGPointMake(0.5, 0.5),anchorPoint))
        {
            CGFloat xDifference = anchorPoint.x - 0.5;
            CGFloat yDifference = anchorPoint.y - 0.5;
            CGPoint currentPosition = view.layer.position;

            // Use transforms if we can, otherwise manually calculate the frame change
            // Assuming a transform is in use since we are changing the anchor point. 
            if (CATransform3DIsAffine(view.layer.transform))
            {
                CGAffineTransform current = CATransform3DGetAffineTransform(view.layer.transform);
                CGAffineTransform invert = CGAffineTransformInvert(current);
                currentPosition = CGPointApplyAffineTransform(currentPosition, invert);
                currentPosition.x += (view.bounds.size.width * xDifference);
                currentPosition.y += (view.bounds.size.height * yDifference);
                currentPosition = CGPointApplyAffineTransform(currentPosition, current);
            }
            else
            {
                CGFloat transformXRatio = view.bounds.size.width / view.frame.size.width;

                if (xDifference < 0)
                    transformXRatio = 1.0/transformXRatio;

                CGFloat transformYRatio = view.bounds.size.height / view.frame.size.height;
                if (yDifference < 0)
                    transformYRatio = 1.0/transformYRatio;

                currentPosition.x += (view.bounds.size.width * xDifference) * transformXRatio;
                currentPosition.y += (view.bounds.size.height * yDifference) * transformYRatio;
            }
            view.layer.position = currentPosition;
        }

    }
}

1

আমার ম্যাট এর উত্তর অনুপ্রাণিত, আমি একটি ভিন্ন পদ্ধতির চেষ্টা করার সিদ্ধান্ত নিয়েছে। উপযুক্তভাবে প্রয়োগ করা সীমাবদ্ধতা সহ একটি ধারক দর্শন ব্যবহার করা যেতে পারে। পরিবর্তিত অ্যাঙ্কর পয়েন্ট সহ ভিউটি খারাপ পুরানো দিনের মতো ঠিক অটোরেসাইজিং মাস্ক এবং স্পষ্ট ফ্রেম সেটিং ব্যবহার করে ধারক দৃশ্যের মধ্যে রাখা যেতে পারে।

এটি যাইহোক আমার পরিস্থিতির জন্য একটি ট্রিট কাজ করে। দ্যাভিডিডোডে ভিউগুলি এখানে সেট আপ করা হয়েছে:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIView *redView = [UIView new];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    self.redView = redView;

    UIView *greenView = [UIView new];
    greenView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    greenView.layer.anchorPoint = CGPointMake(1.0, 0.5);
    greenView.frame = redView.bounds;
    greenView.backgroundColor = [UIColor greenColor];
    [redView addSubview:greenView];
    self.greenView = greenView;

    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = 0.005;
    self.redView.layer.sublayerTransform = perspective;
}

সবুজ দৃষ্টিভঙ্গিতে স্বয়ংচালিত মুখোশের কারণে লাল ভিউটির ফ্রেমগুলি এই মুহুর্তে শূন্য বলে কিছু যায় আসে না।

আমি একটি ক্রিয়া পদ্ধতিতে একটি রোটেশন ট্রান্সফর্ম যুক্ত করেছি এবং এটিই ফলাফল:

এখানে চিত্র বর্ণনা লিখুন

এটি ডিভাইস রোটেশনের সময় নিজেকে হারাতে পারে বলে মনে হয়েছিল, তাই আমি এটিকে ভিডডিআলআউটসুবউভিজ পদ্ধতিতে যুক্ত করেছি:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    CATransform3D transform = self.greenView.layer.transform;
    self.greenView.layer.transform = CATransform3DIdentity;
    self.greenView.frame = self.redView.bounds;
    self.greenView.layer.transform = transform;
    [CATransaction commit];

}

আমি ভাবছি আপনার ক্ষেত্রে এটি কেবল view.layerএকা ছেড়ে আপনার সমস্ত কাজ একটি সাবলেয়ারে করা সহজ হত না কিনা view.layer। অন্য কথায়, দর্শনটি কেবল একটি হোস্ট হবে, এবং সমস্ত অঙ্কন এবং সাবলেয়ার রূপান্তর এবং এগুলি সীমাবদ্ধতার দ্বারা প্রভাবিত না করে একটি স্তর ডাউন হবে।
ম্যাট

1
ঠিক আছে, আপনার সাবভিউ সমাধানে অনুপ্রাণিত হয়ে আমি এটি আমার প্রবন্ধে যুক্ত করেছি! আমাকে আপনার স্যান্ডবক্সে খেলতে দেওয়ার জন্য ধন্যবাদ ...
ম্যাট

0

আমি মনে করি আপনি সেই পদ্ধতিতে অটোলেআউটটির উদ্দেশ্যকে পরাস্ত করছেন। আপনি উল্লেখ করেছেন যে প্রস্থ এবং ডান প্রান্তটি তত্ত্বাবধানের উপর নির্ভর করে, তবে কেন কেবল সেই চিন্তাভাবনার লাইন ধরে বাধা যুক্ত করবেন না?

অ্যাঙ্করপয়েন্ট / ট্রান্সফর্ম দৃষ্টান্তটি হারিয়ে ফেলুন এবং চেষ্টা করুন:

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeRight
                             relatedBy:NSLayoutRelationEqual 
                                toItem:self.view 
                             attribute:NSLayoutAttributeWidth 
                            multiplier:1.0f
                              constant:-somePadding]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeWidth
                             relatedBy:NSLayoutRelationEqual 
                                toItem:someViewWeDependTheWidthOn
                             attribute:NSLayoutAttributeWidth 
                            multiplier:0.5f // because you want it to be half of someViewWeDependTheWidthOn
                              constant:-20.0f]]; // your 20pt offset from the left

NSLayoutAttributeRightবাধ্যতা মানে ঠিক মত anchorPoint = CGPointMake(1.0, 0.5), এবং NSLayoutAttributeWidthবাধ্যতা মোটামুটিভাবে আপনার আগের কোডের সমতূল্য NSLayoutAttributeLeft


আপনার উত্তরের জন্য ধন্যবাদ, তবে আমি "অ্যাঙ্কার পয়েন্ট / ট্রান্সফর্ম দৃষ্টান্ত হারাতে" পারি না। সঠিক রূপান্তর করতে আমাকে একটি ট্রান্সফর্ম প্রয়োগ করতে হবে এবং অ্যাঙ্কর পয়েন্টটি সামঞ্জস্য করতে হবে।
jrturton

আরও ব্যাখ্যা করার জন্য, এই নির্দিষ্ট ক্ষেত্রে রুপান্তরিত ভিউটিকে কখনও কখনও তার ডান প্রান্তে Y অক্ষের সাথে ঘুরিয়ে স্ক্রিনে ভাঁজ করতে হবে। অতএব, অ্যাঙ্কর পয়েন্ট সরানো আছে। আমি একটি সাধারণ সমাধানও খুঁজছি।
jrturton

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

1
এটি হওয়া উচিত, তবে তা নয়। আপনি কি আসলে এটি চেষ্টা করেছেন? অ্যাঙ্কর পয়েন্ট পরিবর্তন করা অটো লেআউটটি কাজ করার পরে স্তরটির অবস্থানকে অফসেট করে । আপনার সমাধান কোনও পরিবর্তিত অ্যাঙ্কর পয়েন্টের সাথে কাজ করে না।
jrturton

হ্যাঁ, আমার প্রতিবন্ধকতাগুলির সাথে আমার মতামতের জন্য আমি বিভিন্ন অ্যাঙ্করপয়েন্টগুলি ব্যবহার করতে পারি। আপনার উত্তরটি viewDidLayoutSubviewsঠিক করা উচিত; positionসর্বদা সাথে যায় anchorPoint। আমার উত্তরটি কেবল পরিচয় রূপান্তরের জন্য সীমাবদ্ধতা কীভাবে সংজ্ঞায়িত করতে পারে তা দেখায়।
জন এস্ট্রোপিয়া

0

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

https://github.com/hansdesmedt/AutoLayout-scrollview-scale

এটি সম্পূর্ণরূপে অটোলাউটে তৈরি কাস্টম পেজিং সহ একটি ইউআইএসক্রোলভিউর একটি উদাহরণ এবং দীর্ঘতর চাপ দিয়ে জুম করতে ট্যাপ করে স্কেলযোগ্য (CATransfor3DMakeScale)। আইওএস 6 এবং 7 সামঞ্জস্যপূর্ণ।


0

এটি একটি বড় বিষয় এবং আমি সমস্ত মন্তব্য পড়িনি তবে একই সমস্যার মুখোমুখি হয়েছি।

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


0

tl; dr ধরুন আপনি নোঙ্গর পয়েন্টটি পরিবর্তন করেছেন (0, 0) অ্যাঙ্কর পয়েন্ট এখন শীর্ষে বামে। অটো লেআউটে আপনি যে কোনও সময় শব্দ কেন্দ্রটি দেখতে পাবেন, আপনার উপরের বামদিকে ভাবা উচিত ।

আপনি যখন আপনার অ্যাঙ্করপয়েন্টটি সামঞ্জস্য করবেন, আপনি কেবল অটোলআউট এর শব্দার্থবিজ্ঞান পরিবর্তন করবেন। অটো লেআউট আপনার অ্যাঙ্করপয়েন্ট বা তদ্বিপরীতে হস্তক্ষেপ করবে না। যদি আপনি এটি বুঝতে না পারেন তবে আপনার একটি খারাপ সময় কাটাতে চলেছে


উদাহরণ:

চিত্র এ। অ্যাঙ্কর পয়েন্টে কোনও পরিবর্তন নেই

#Before changing anchor point to top-left
view.size == superview.size
view.center == superview.center

চিত্র বি। অ্যাঙ্কর পয়েন্টটি উপরের বামে পরিবর্তিত হয়েছে

view.layer.anchorPoint = CGPointMake(0, 0)
view.size == superview.size
view.center == superview.topLeft                <----- L0-0K, center is now top-left

চিত্র এ এবং চিত্র বি ঠিক একই রকম দেখাচ্ছে। কিছুই পরিবর্তন হয়নি। কী কেন্দ্র পরিবর্তিত বোঝায় তার সংজ্ঞা ।


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