UIDeviceOrientationDidChangeNotification多次调用

时间:2014-02-21 19:43:05

标签: ios objective-c orientation uideviceorientation

当设备更改方向时,UIDeviceOrientationDidChangeNotification会多次调用。我不确定为什么会发生这种情况或如何解决它。

我要做的是保持scrollview的contentoffset相同,所以当用户旋转屏幕时,app会保留他们所在的页面。

奇怪的是当我第一次按照我想要的方式执行代码时旋转屏幕。但每次在此之后代码执行多次并最终将contentoffset设置为0。

这就是我所拥有的。

- (void)loadView {

    //some code that sizes itself depending on the current orientation
    //WILL BE CALLED AFTER EVERY ORIENTATION CHANGE

}

- (void)viewDidLoad {

    //begin generating messages 
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];


    [[NSNotificationCenter defaultCenter]
        addObserver:self selector:@selector(orientationChanged:)
        name:UIDeviceOrientationDidChangeNotification
        object:[UIDevice currentDevice]];

    //if is portrait and was landscape
    if (orientation==1 && temp==2) {
        int cal = offsetHolder.x/screenframe.size.height;
        offsetHolder.x = cal * screenframe.size.width;
        ScrollView.contentOffset = offsetHolder;
    }

    //if is landscape and was portrait
    if (orientation==2 && temp==1) {
        int cal = offsetHolder.x/screenframe.size.width;
        offsetHolder.x = cal * screenframe.size.height;
        ScrollView.contentOffset = offsetHolder;
    }


}

在方向更改时,我更改'int orientation'的值,然后调用loadview来更改视图的大小。然后我调用viewdidload来获取正确的contentoffset

- (void) orientationChanged:(NSNotification *)note {

    CGRect screenframe = [[UIScreen mainScreen] bounds];

    //holding the current offset
    offsetHolder = ScrollView.contentOffset;

    if ([[UIDevice currentDevice] orientation] == 1 || [[UIDevice currentDevice] orientation] == 0 || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) {
        temp=orientation;
        orientation = 1;

        [self loadView];
        [self viewDidLoad];
    }

    else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceDown ||      [[UIDevice currentDevice] orientation] == UIDeviceOrientationFaceUp){

        temp=orientation;
    }

    else{
        temp=orientation;
        orientation = 2;
        [self loadView];
        [self viewDidLoad];
    }
}

编辑:

我发现了这个问题。我正在做的是创建另一个self.view实例而不是覆盖这个实例。是否有一种简单的方法来销毁此视图并重新初始化它?

EDIT2:

找到了解决办法。我按照jsds的说明停止调用loadview和viewdidload。而是将我的loadview中的所有代码移动到我从loadview调用的另一个函数。所有这些代码都会实例化UI(initview)对象,并根据方向将它们放在正确的位置。

然后我创建另一个从视图中删除所有子视图的函数。然后在方向改变时,我调用此函数和我的initview来销毁所有子视图,然后在方向更改时重新创建它们。

2 个答案:

答案 0 :(得分:1)

UIDeviceOrientation基本上有6种不同的状态,即两个肖像,两个风景,面朝上和面朝下。因此,当您从平面位置到垂直位置拾取设备时,将触发通知。 您可以使用宏UIDeviceOrientationIsValidInterfaceOrientation

过滤面朝上,面朝下和未知状态
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];

    // Ignore changes in device orientation if unknown, face up, or face down.
    if (!UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation)) {
        return;
    }

如果您仍然发现多次触发通知,我恐怕您可能需要使用带有标志的自定义逻辑来检查先前和当前值。

就我而言,由于我使用了反应式可可框架,以下代码对我有用:

if (IS_IPAD) { @weakify(self); [[[[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIDeviceOrientationDidChangeNotification object:nil] takeUntil:[self rac_willDeallocSignal]] map:^id (NSNotification *notification) { return @([[UIDevice currentDevice] orientation]); }] filter:^BOOL(NSNumber *deviceOrientationNumber) { UIDeviceOrientation currentOrientation = [deviceOrientationNumber integerValue]; //We ignore the UIDeviceOrientationUnknown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown return UIDeviceOrientationIsValidInterfaceOrientation(currentOrientation); }] distinctUntilChanged] subscribeNext:^(id x) { @strongify(self); //do something here... }]; }

这里distinctUntilChanged方法确保仅在方向更改为新的有效值时才触发代码。

答案 1 :(得分:0)

您永远不应该自己调用loadView或viewDidLoad。这取决于管理框架。

如果要根据viewDidLoad中的视图边界定位或调整视图大小,请不要这样做。将其移至viewWillLayoutSubviews。当设备方向改变时,将自动调用它。

或者,使用自动布局约束,然后您根本不需要做任何事情。