UIScrollViewでナビゲーションバーの高さも考慮した中央揃えを行う

UIScrollViewの中にスクロールさせたいビュー(コンテンツ)を配置し、フィット表示させているときに、ナビゲーションバーなどの高さも考慮し、画面の中央にコンテンツを表示する方法について解説します。

この記事ではObjective-Cを使用していますが、Swiftでも同じ方法で実装可能です。

目次

必要な処理

必要な処理は以下の通りです。

  1. スクロール対象のコンテンツビューを設定する。
  2. UIScrollViewにインセット量の調整方法を設定する。
  3. ズーム時にコンテンツビューのフレームを設定する。
  4. スクロールビューへのフィット処理を実装する。
  5. ビューコントローラのレイアウト時にフィット処理を実行する。

スクロール対象のコンテンツビューを設定する

スクロール対象のビューをこの記事ではコンテンツビューと呼びます。UIScrollViewにコンテンツビューを設定するには、UIScrollViewDelegateの適合クラスのviewForZoomingInScrollView:メソッドでコンテンツを返します。

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.contentsView;
}

インセット量の調整方法を設定する

UIScrollViewでのインセット量の調整方法を設定します。以下のようにUIScrollViewcontentInsetAdjustmentBehaviorプロパティをUIScrollViewContentInsetAdjustmentScrollableAxesに設定します。

scrollView.contentInsetAdjustmentBehavior = 
    UIScrollViewContentInsetAdjustmentScrollableAxes;

ズーム時にコンテンツビューのフレームを設定する

ズーム倍率が変更されたときに、コンテンツビューのフレームサイズを変更する処理を実装します。スクロールビューよりもコンテンツビューの方が小さくなるときに、中央揃えになるように、フレームの左上の座標を調整するようにします。

- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
    [self adjustContentFrameForScale:scrollView.zoomScale];
}

- (void)adjustContentFrameForScale:(CGFloat)zoomScale
{
    // 等倍時の大きさを取得する。たとえば、プロパティに入れておく
    CGSize contentSize = self.naturalContentSize;
    
    // ズーム後のサイズを計算する
    CGSize scaledSize = CGSizeMake(
        contentSize.width * zoomScale,
        contentSize.height * zoomScale);
    
    // 中央揃えになるようにオフセットを計算する
    CGSize scrollViewSize = self.scrollView.bounds.size;
    CGFloat xOffset = MAX(0, (scrollViewSize.width - scaledSize.width) / 2);
    CGFloat yOffset = MAX(0, (scrollViewSize.height - scaledSize.height) / 2);
    
    // コンテンツビューのフレームを設定する
    self.contentView.frame = CGRectMake(
        xOffset,
        yOffset,
        scaledSize.width,
        scaledSize.height
    );
    
    // スクロールビューに新しいサイズを設定する
    self.scrollView.contentSize = scaledSize;
}

スクロールビューへのフィット処理を実装する

ここまでの実装で、スクロールビューよりもコンテンツビューの方が小さいときに、小さい辺は中央揃えされるようになります。更に、フィット倍率を計算して、フィットさせる処理も実装します。この処理を実行すると、コンテンツビューが画面の中央にフィット表示されます。

- (void)zoomToFit
{
    // 等倍時の大きさを取得する。たとえば、プロパティに入れておく
    CGSize contentSize = self.naturalContentSize;
    
    // フィット倍率を計算する
    CGSize scrollViewSize = self.scrollView.bounds.size;
    CGFloat widthScale = scrollViewSize.width / contentSize.width;
    CGFloat heightScale = scrollViewSize.height / contentSize.height;
    
    // 小さい方の値を使用する
    CGFloat minScale = MIN(widthScale, heightScale);
    
    // スクロールビューに設定する
    self.scrollView.minimumZoomScale = minScale;
    self.scrollView.zoomScale = minScale;
    
    // コンテンツビューのサイズを調整する
    [self adjustContentFrameForScale:minScale];
}

ビューコントローラのレイアウト時にフィット処理を実行する

ビューコントローラが表示されるときや、デバイスの回転時、iPadのスプリットビューの状態変更などにより、ビューコントローラのサイズが変わるときに、追従してフィットさせるには、以下のように、viewWillLayoutSubviewsでフィット処理を実行します。

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    
    // スクロールビューのサイズを設定する
    self.scrollView.frame = self.view.bounds;
    
    // フィットさせる
    [self zoomToFit];
}

著書紹介

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次