如何正确更改水平视图的布局?

时间:2014-11-10 17:32:25

标签: ios objective-c layout

您好,我正在尝试为我的应用创建这种布局。

layout 因此,从图像中可以看出,UICollectionView必须移动到屏幕右侧并改变大小。当方向改变时,所有UIViews的大小也会发生变化。

我试图更改代码中元素的位置,然后在视图出现时调用该方法:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        // portrait
        [self portraitUISetup];

    } else {
        // landscape
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(landscapeUISetup)
                                                     name:UIDeviceOrientationDidChangeNotification
                                                   object:nil];
    }
}

-(void)portraitUISetup
{
    self.flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    self.flowLayout.minimumLineSpacing = 18.0f;
    self.flowLayout.itemSize = CGSizeMake(167, 254);
    self.flowLayout.sectionInset = UIEdgeInsetsMake(18, 40, 52, 18);

    CGRect rect = self.textView.frame;
    rect.size.width = 355;
    rect.size.height = 438;
    rect.origin.x = 373;
    rect.origin.y = 230;
    self.textView.frame = rect;

    rect = self.collectionView.frame;
    rect.size.width = 768;
    rect.size.height = 327;
    rect.origin.x = 0;
    rect.origin.y = 697;
    self.collectionView.frame = rect;

    rect = self.slideshow.frame;
    rect.size.width = 768;
    rect.size.height = 181;
    rect.origin.x = 0;
    rect.origin.y = 20;
    self.slideshow.frame = rect;

    rect = self.selectedIssueCover.frame;
    rect.size.width = 293;
    rect.size.height = 438;
    rect.origin.x = 40;
    rect.origin.y = 230;
    self.selectedIssueCover.frame = rect;

}

-(void)landscapeUISetup
{
    self.flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;

    self.flowLayout.minimumLineSpacing = 49.0f;
    self.flowLayout.itemSize = CGSizeMake(167, 254);
    self.flowLayout.sectionInset = UIEdgeInsetsMake(18, 23, 0, 25);
    self.collectionView.alwaysBounceHorizontal = NO;

    CGRect rect = self.collectionView.frame;
    rect.size.width = 217;
    rect.size.height = 539;
    rect.origin.x = 810;
    rect.origin.y = 229;
    self.collectionView.frame = rect;

    rect = self.slideshow.frame;
    rect.size.width = self.view.bounds.size.width;
    rect.size.height = 181;
    rect.origin.x = 0;
    rect.origin.y = 20;
    self.slideshow.frame = rect;

    rect = self.selectedIssueCover.frame;
    rect.size.width = 333;
    rect.size.height = 498;
    rect.origin.x = 40;
    rect.origin.y = 233;
    self.selectedIssueCover.frame = rect;

    rect = self.textView.frame;
    rect.size.width = 355;
    rect.size.height = 498;
    rect.origin.x = 414;
    rect.origin.y = 233;
    self.textView.frame = rect;

}

问题我遇到过这种方法的问题是,只要我推送到另一个视图,此视图就会重置为纵向视图(可能是故事板中设置的视图),即使设备也是如此在风景中。

那么正确的方法是什么呢?

4 个答案:

答案 0 :(得分:0)

将您的布局逻辑放在viewWillLayoutSubviews内,而不是注册轮换事件。

答案 1 :(得分:0)

如果您正在使用Interface Builder,那么根据尺寸等级设置两种不同的布局非常容易。如果您将底部的模拟指标从wAny hAny更改为wRegular hAny并设置一些新的布局限制,则会在运行时自动在两者之间切换。

答案 2 :(得分:0)

好的问题是界面检查。我改变了一点,并使用@Ian MacDonald的建议来使用viewDidLayoutSubviews

这是我现在可以使用的解决方案。

-(void)viewDidLayoutSubviews
{
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationLandscapeLeft ||  orientation == UIInterfaceOrientationLandscapeRight)
    {
        [self landscapeUISetup];

    } else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {

        [self portraitUISetup];
    }

}

答案 3 :(得分:0)

执行此操作的正确方法是使用UICollectionViewFlowLayoutInvalidationContext。有关示例实现,请参见如何在轮换时使流集合视图布局无效:

http://aplus.rs/2015/how-to-invalidate-flow-collection-view-layout-on-rotation/

要-即:

假设您希望网格布局的单元格总是屏幕宽度的一半。您希望在纵向和横向中保持该布局。从iOS 8开始,用正确的咒语就不容易了。

首先,子类UICollectionViewFlowLayout;然后,添加以下方法:

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds {

  UICollectionViewFlowLayoutInvalidationContext *context = (UICollectionViewFlowLayoutInvalidationContext *)[super invalidationContextForBoundsChange:newBounds];
  context.invalidateFlowLayoutDelegateMetrics = (
                                                 CGRectGetWidth(newBounds) != CGRectGetWidth(self.collectionView.bounds) ||
                                                 CGRectGetHeight(newBounds) != CGRectGetHeight(self.collectionView.bounds)
                                                 );
  return context;
}

这里的关键是将返回的上下文从super UICollectionViewFlowLayoutInvalidationContext转换为允许您切换invalidateFlowLayoutDelegateMetrics属性。这将告诉UIKit它应该重新查询FlowLayout的委托大小。

在集合视图控制器中,确保将其设置为采用UICollectionViewDelegateFlowLayout协议,然后添加此委托调用:

- (CGSize)collectionView:(UICollectionView *)collectionView
                layout:(UICollectionViewFlowLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

  return CGSizeMake(floor(self.view.bounds.size.width/2.0), 88);
}