动态调整UICollectionView的补充视图(包含多行UILabel)

时间:2015-05-01 17:16:02

标签: ios objective-c autolayout uicollectionview

在UICollectionView的补充视图(标题)中,我有一个多行标签,我想截断为3行。

enter image description here

当用户点击标题(补充)视图中的任何位置时,我想将UILabel切换为0行,以便显示所有文本,并相应地增加collectionView的补充视图的高度(最好是动画)。点击标题后会发生以下情况:

enter image description here

到目前为止,这是我的代码:

// MyHeaderReusableView.m

// my gesture recognizer's action
- (IBAction)onHeaderTap:(UITapGestureRecognizer *)sender
{
    self.listIntro.numberOfLines = 0;

    // force -layoutSubviews to run again
    [self setNeedsLayout];
    [self layoutIfNeeded];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.listTitle.preferredMaxLayoutWidth = self.listTitle.frame.size.width;
    self.listIntro.preferredMaxLayoutWidth = self.listIntro.frame.size.width;
    [self layoutIfNeeded];

    CGFloat height = [self systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    self.frame = ({
        CGRect headerFrame = self.frame;
        headerFrame.size.height = height;
        headerFrame;
    });

    NSLog(@"height: %@", @(height));
}

当我在height末尾记录layoutSubviews时,其值为149,而标签被截断,numberOfLines设置为3.点击headerView后,设置{{1 }到0,并强制布局传递,然后高度记录为163.5。太好了!

唯一的问题是整个headerView不会增长,并且单元格不会被推下。

如何动态更改collectionView的补充视图(最好是动画)的高度?

我知道UICollectionViewFlowLayout的numberOfLinesheaderReferenceSize,但不太确定我在这种情况下如何使用它们。

2 个答案:

答案 0 :(得分:4)

我得到了一些工作,但我承认,它感觉很笨拙。我觉得这可以通过标准的CollectionView(和相关元素)API +挂钩到标准布局/显示失效来完成,但我无法让它工作。

唯一可以调整我的headerView大小的是设置我的集合视图的流程布局headerReferenceSize。不幸的是,我无法从我的UICollectionReusableView实例访问我的集合视图或它的流布局,所以我必须创建一个委托方法来传回正确的高度。

这就是我现在所拥有的:

// in MyHeaderReusableView.m
//
// my UITapGestureRecognizer's action
- (IBAction)onHeaderTap:(UITapGestureRecognizer *)sender
{
    self.listIntro.numberOfLines = 0;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.listTitle.preferredMaxLayoutWidth = self.listTitle.frame.size.width;
    self.listIntro.preferredMaxLayoutWidth = self.listIntro.frame.size.width;

    CGFloat height = [self systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    self.frame = ({
        CGRect headerFrame = self.frame;
        headerFrame.size.height = height;
        headerFrame;
    });

    if (self.resizeDelegate) {
        [self.resizeDelegate wanderlistDetailHeaderDidResize:self.frame.size];
    }
}

// in my viewController subclass which owns the UICollectionView:
- (void)wanderlistDetailHeaderDidResize:(CGSize)newSize
{
    UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;

    // this is the key line
    flowLayout.headerReferenceSize = newSize;

    // this doesn't look beautiful but it's the best i can do for now. I would love for just the bottom of the frame to animate down, but instead, all the contents in the header (the top labels) have a crossfade effect applied.    
    [UIView animateWithDuration:0.3 animations:^{
        [self.collectionView layoutIfNeeded];
    }];
}

就像我说的那样,不是我想要的解决方案,而是一种可行的解决方案。

答案 1 :(得分:0)

我遇到了与你相同的问题,所以我只是想知道:你有没有得到一个没有你在代码示例中提到的交叉渐变效果的解决方案?我的方法几乎相同,所以我遇到了同样的问题。另外还有一个评论:我设法实现了解决方案而不需要授权:我所做的是来自" MyHeaderReusableView.m"您可以通过以下方式引用UICollectionView(以及UICollectionViewLayout):

//from MyHeaderReusableView.m
if ([self.superview isKindOfClass:UICollectionView.class]) {

    //get collectionView reference
    UICollectionView * collectionView = (UICollectionView*)self.superview;

    //layout
    UICollectionViewFlowLayout * layout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
    //... perform the header size change

}