【问题标题】:How to be notified when frame in absolute coordinates change?如何在绝对坐标中的帧发生变化时得到通知?
【发布时间】:2014-11-30 18:54:35
【问题描述】:

当我的自定义 UIView 子类的绝对框架(不仅是相对于其父级的框架,而且当 superview/grandsuperview 等的框架发生变化,导致我的视​​图的框架发生变化)在屏幕上发生变化时,我需要得到通知。我尝试在-(void)didMoveToSuperview-(void)didMoveToWindow 处获取绝对帧convertRect:toView:,并且我还在两者中添加了此代码:

UIView *view = self.superview;
while (view) {
    [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
    [view addObserver:self forKeyPath:@"superview" options:NSKeyValueObservingOptionNew context:nil];
    view = view.superview;
}

它们都被调用了几次(这没关系),但我得到的坐标不正确。 所有设置实际可见框架的代码之后,还有其他东西运行。我通过将其放入我的代码来验证这一点:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        CGRect globalFrame = [view.superview.superview convertRect:view.superview.frame toView:[[view.delegate tutorialView] superview]];
        NSLog(@"after 2 sec %@", NSStringFromCGRect(globalFrame));
        if([view.delegate respondsToSelector:@selector(attachedViewFrameDidChange:)]){
            [view.delegate attachedViewFrameDidChange:globalFrame];
        }
    });

忘记view.delegate 和我的其他自定义参数/对象/方法。两秒钟后,我在globalFrame 中得到了正确的值。我在-(void)didMoveToSuperview-(void)didMoveToWindow-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 中有完全相同的代码,它们都以不正确的帧值调用(当我调用convertRect:toView: 时得到不正确的值。为什么会这样,我怎样才能得到两秒钟后得到的绝对/真实帧值(我在屏幕上看到的),显然没有等待?

【问题讨论】:

    标签: ios objective-c uiview frame


    【解决方案1】:

    我认为您可以通过使您的自定义视图成为视图控制器的委托,并在 viewDidLayoutSubviews 中调用委托方法来做到这一点。所以,在视图 controller.h 中,我有这个,

    @protocol UIViewControllerLayoutChanged <NSObject>
    -(void)layoutChanged;
    @end
    
    @interface ViewController : UIViewController
    @property (weak,nonatomic) id<UIViewControllerLayoutChanged> delegate;
    @end
    

    在.m文件中,

    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setDelegate:(RDLabel *)self.label]; // self.label is the view I want to be notified when its absolute frame changes
    }
    
    
    -(void)viewDidLayoutSubviews {
         [self.delegate layoutChanged];
    }
    

    在我的自定义视图类中,

    -(void)layoutChanged {
        NSLog(@"%@",NSStringFromCGRect([self.superview convertRect:self.frame toView:nil]));
    }
    

    每当我更改它时,它都会给我正确的绝对框架。当然,viewDidLayoutSubviews 会在任何时候需要重新布局任何视图时调用,即使它不涉及您关心的视图。要处理此问题,您可能需要在自定义类的代码中保留对框架的引用,并且仅在其框架从旧值更改时才执行您需要做的任何事情。

    【讨论】:

    • 这看起来是一个非常好的解决方案,但是,我正在为第 3 方库开发代码,我无法访问视图的控制器。即使我通过检查下一个响应者在视图层次结构中找到视图控制器,我也不想通过 swizzling 或类别的方式将代码“注入”到其中(我不能子类化控制器)。如果我能有一个不涉及视图控制器的解决方案,那就太好了。
    • @CanPoyrazoğlu,那么,您可以访问什么?
    • 视图本身及其超级视图。不过,我手中只有“自定义类”是视图本身。它的超级视图可以是任何东西。
    • @CanPoyrazoğlu,是每次视图的框架或其父视图之一更改其框架时调用的观察者方法。在我的测试中,我没有看到。
    • 在我的示例中,它们为 keypath "frame" 调用了两次。
    猜你喜欢
    • 2022-07-22
    • 2017-10-18
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多