【iOS】UIStackViewを使ってアコーディオンを作る

やりたいこと

UIScrollViewがある状態でこういうアコーディオンが作りたい f:id:maximInstantcoffee:20200604092926g:plain

どうつくるか

UIStackViewを使います。
また、UILabelの高さを直接変更すると意図しない動きになるので、 ClipToBoundsをオンにしたViewを利用します。

つくりかた

Storybordで気をつける点は以下です

  • 上下左右の制約0でUIScrollViewを配置する(ContentLayaoutGuidesのチェックは外しておく)
  • UIScrollViewの中に、上下左右の制約0でUIStackViewを配置する。横幅はUIScrollViewと同じになる制約を追加する。
  • UIButtonの下にViewを配置、左右の制約0、高さの制約も0にする。ClipToBoundsをオンにする。
  • ClipToBoundsをオンにしたViewの中に、上左右の制約0でUILabelを配置

f:id:maximInstantcoffee:20200604100204p:plain

動きをつける

ボタンが押されたら、高さ0で設定した制約を、UILabelの高さと同じに変えます。 開いている場合は、再び高さ0に設定します。

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *acoordionView1Height;
@property (weak, nonatomic) IBOutlet UILabel *label1;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *accordionView2Height;
@property (weak, nonatomic) IBOutlet UILabel *label2;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)button1:(id)sender {
    [self.view layoutIfNeeded];
    
    if (_acoordionView1Height.constant != 0){
        _acoordionView1Height.constant = 0;
    }else{
        _acoordionView1Height.constant = _label1.frame.size.height;
    }
    
    [UIView animateWithDuration:0.3f
                     animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (IBAction)button2:(id)sender {
    [self.view layoutIfNeeded];
    
    if (_accordionView2Height.constant != 0){
        _accordionView2Height.constant = 0;
    }else{
        _accordionView2Height.constant = _label2.frame.size.height;
    }
    
    [UIView animateWithDuration:0.3f
                     animations:^{
        [self.view layoutIfNeeded];
    }];
}

GitHub

https://github.com/maximinstantcoffee/accordion