iOS11での奇妙なuitableviewの動作。セルはナビゲーションプッシュアニメーションで上にスクロールします


116

最近、一部のコードを新しいiOS 11ベータ5 SDKに移行しました。

UITableViewから非常に混乱する動作が発生します。テーブルビュー自体はそれほど豪華ではありません。私はカスタムセルを持っていますが、ほとんどの場合、それはそれらの高さのためです。

tableviewを使用してビューコントローラーを押すと、セルが「スクロールアップ」する(またはtableviewフレーム全体が変更される)プッシュ/ポップナビゲーションアニメーションに沿って下がる追加のアニメーションが表示されます。gifを参照してください:

波状テーブルビュー

私は手動で作成tableviewしますloadViewメソッド自動レイアウト制約をテーブルビューのスーパービューの先頭、末尾、上、下に等しくなるように設定します。スーパービューは、ビューコントローラーのルートビューです。

ビューコントローラーのプッシュコードは非常に標準的です。 self.navigationController?.pushViewController(notifVC, animated: true)

同じコードがiOS 10で通常の動作を提供します。

何が悪いのかを教えていただけませんか?

編集:私は非常にシンプルなテーブルビューコントローラーを作成しましたが、そこで同じ動作を再現できます。コード:

class VerySimpleTableViewController : UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 4
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        cell.textLabel?.text = String(indexPath.row)
        cell.accessoryType = .disclosureIndicator

        return cell
    }


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        let vc = VerySimpleTableViewController.init(style: .grouped)

        self.navigationController?.pushViewController(vc, animated: true)
    }
}

編集2:私はUINavigationBarのカスタマイズに問題を絞り込むことができました。私はこのようなカスタマイズをしています:

rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)

ここで、createFilledImage所定の大きさと色の正方形画像を作成します。

この行をコメントアウトすると、通常の動作に戻ります。

この件についてのご意見をいただければ幸いです。


ナビゲーションバーのカスタマイズの問題ではない可能性があります。私はカスタマイズなしで同じ問題を抱えていました(受け入れられた回答でこれを解決しました)。UITableViewControllerを使用する代わりに、iOSがサブビューとして手動で作成されたテーブルビューを処理する方法に問題があると思います。
マークレナード

2
この動作はに設定navigationBar.isTranslucentした場合にのみ発生しfalseます。それ以外の場合は正常に動作します。
b_ray 2017

5
これはiOS11 GMのバグのようです。このバグ報告を複製して、この問題がAppleから注目されるようにしてください:openradar.appspot.com/34465226
b_ray

1
この問題はiOS 11.2ベータで修正されたようです。contentInsetAdjustmentBehaviorを決して設定しないでください。画面の下部にパディングを付けないため、iPhone Xのスクロールビューが壊れてしまうからです。コンテンツビューの下部は、iPhone Xのホーム「ボタン」の下にあります。
バトゥ

回答:


150

これは、デフォルトで設定されているUIScrollView's (UITableViewはUIScrollviewのサブクラス)新しいcontentInsetAdjustmentBehaviorプロパティが原因.automaticです。

影響を受けるコントローラーのviewDidLoadで次のスニペットを使用して、この動作をオーバーライドできます。

    tableView.contentInsetAdjustmentBehavior = .never

https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior


2
UIScrollViewContentInsetAdjustmentBehavior.automaticの定義に関するこのコメントは、次のように述べています。「スクロール互換かどうかに関係なく、ナビゲーションコントローラ内で自動調整のスクロールビューインセット= YESのビューコントローラがスクロールビューを所有している場合、下位互換性のために、上下のcontentInsetも調整されます。ビューはスクロール可能です。」私の理論では、ナビゲーションバーのcontentInsetは背景画像を設定することで影響を受け、動的に調整されます。
Maggy Hillen 2017

8
ストーリーボードでそれを行うこともできます。サイズインスペクタ->コンテンツインセット-> [なし]を設定します。
ウォンビキム2017

4
コンテンツがタブバーの背後にある場合、無効にするtableView.contentInsetAdjustmentBehaviorとインセットが破損します。
キーン

4
また、これを無効にすると、スクロールインジケーターが横向きのiPhone Xの(上部ギズモ)の後ろに配置されます。この動作の要点は、スクロールビューのコンテンツ領域を調整して、長方形ではない画面に表示されるようにすることです。これは現在iPhone X Simでしか見ることができないと思います。
PhoneyDeveloper 2017年

8
この問題は、iOS 11のバグによって引き起こされました。ナビゲーションの移行中に、ビューコントローラーのビューのsafeAreaInsetsが誤って設定されていましたが、iOS 11.2で修正する必要があります。に設定するcontentInsetAdjustmentBehavior.never、他の望ましくない副作用が発生する可能性があるため、優れた回避策ではありません。回避策を使用する場合は、iOSバージョンが11.2以上の場合は必ず削除してください。
smileyborg 2017年

23

マギーの答えに加えて

OBJECTIVE-C

if (@available(iOS 11.0, *)) {
    scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

この問題は、iOS 11のバグによって引き起こされsafeAreaInsetsました。ナビゲーションの移行中にビューコントローラーのビューが正しく設定されていませんでした。iOS11.2で修正する必要があります。に設定する contentInsetAdjustmentBehavior.never、他の望ましくない副作用が発生する可能性があるため、優れた回避策ではありません。回避策を使用する場合は、iOSバージョン> = 11.2の場合は必ず削除してください。

-smileyborg(Appleのソフトウェアエンジニア)による言及


6

たとえば、didFinishLaunchingWithOptionsでNSProxyを使用して、アプリケーション全体でこの動作を一度に編集できます。

if (@available(iOS 11.0, *)) {
      [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} 

1
これにより、UIImagePickerControllerのようなシステムのコントローラーが壊れます
ゴールウェイ

6

iOS 11でインセットを自動的に設定できるようにしながら、この問題を解決する方法を以下に示します。使用していUITableViewControllerます。

  • ストーリーボードの(またはプログラムで)ビューコントローラーで[エッジを上部バーの下に拡張]および[エッジを不透明バーの下に拡張]を選択します。安全領域のインセットは、ビューがトップバーの下に表示されないようにします。
  • ストーリーボードのテーブルビューにある[安全領域へのインセット]ボタンを確認します。(またはtableView.insetsContentViewsToSafeArea = true)-これは必要ないかもしれませんが、私がやったことです。
  • コンテンツインセット調整動作を「スクロール可能な軸」(またはtableView.contentInsetAdjustmentBehavior = .scrollableAxes)に設定します- 動作する.always可能性もありますが、テストしませんでした。

他のすべてが失敗した場合に試すもう1つのこと:

viewSafeAreaInsetsDidChange UIViewControllerメソッドをオーバーライドして、テーブルビューに強制的にスクロールビューインセットをセーフエリアインセットに設定します。これは、Maggyの回答の「Never」設定と連動しています。

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    self.tableView.contentInset = self.view.safeAreaInsets;
}

注:self.tableViewself.view同じですUITableViewController


このスレッドでほぼすべてを試しましたが、これは私にとってはうまくいきました。TabBarVCに埋め込まれたTableViewVC。ありがとうございました!
Josh Wolff

3

これは意図された動作というよりはバグのようです。ナビゲーションバーが半透明でない場合、または背景画像が設定されている場合に発生します。

contentInsetAdjustmentBehaviorを.neverに設定しただけでは、コンテンツのインセットはiPhone Xで正しく設定されません。たとえば、コンテンツはスクロールバーの下の下部に表示されます。

次の2つのことを行う必要があり
ます。1。push / popでscrollViewがアニメーション化しないようにします。2。iPhone
Xで必要なため、.automatic動作を維持します。これがないと、たとえば縦向きでは、コンテンツは下部のスクロールバーの下に表示されます。

新しいシンプルなソリューション: XIBの場合:メインビューの上に新しいUIViewを追加するだけで、トップ、リーディング、トレーリングがスーパービューになり、高さが0に設定されます。他のサブビューなどに接続する必要はありません。

古いソリューション:

注:UIScrollViewをランドスケープモードで使用している場合でも、水平インセットは正しく設定されないため(別のバグ?)、scrollViewのリーディング/トレーリングをIBのsafeAreaInsetsに固定する必要があります。

注2:以下の解決策には、tableViewが一番下までスクロールされ、コントローラーを押してポップバックすると、一番下に表示されなくなるという問題もあります。

override func viewDidLoad()
{
    super.viewDidLoad()

    // This parts gets rid of animation when pushing
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidDisappear(_ animated: Bool)
{
    super.viewDidDisappear(animated)
    // This parts gets rid of animation when popping
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidAppear(_ animated: Bool)
{
    super.viewDidAppear(animated)
    // This parts sets correct behaviour(insets are correct on iPhone X)
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .automatic
    }
}

parentViewとは何ですか?
PhoneyDeveloper 2017年

ビューコントローラーのメインビュー、私は答えを更新しました。どうも。
El Horrible

UITableViewControllerを使用している場合、tableViewはビューコントローラのビューです。また、デバイスを回転させると、インセットが異なるはずです。調整して欲しい。tableViewが最初に表示されるときのアニメーションが気に入らないだけです。
PhoneyDeveloper 2017年

あなたの場合、UITableViewはコントローラーのビューなので、それはsafeAreaInsets.bottom = 34(portrait)を持っているはずなので、単にtableView.contentInset = tableView.safeAreaInsetsを設定できます。
El Horrible

それは私にはうまくいきません。viewDidLoadでは、すべてのインセットはゼロです。そのコードをviewWillLayoutSubviewsで使用しようとすると、スクロールインジケーターが挿入されますが、tableView自体が水平方向にスクロールできるようになります。調整を無効にせずにviewWillLayoutSubviewsのインセットだけを見ると、下のAdjustedContentInsetは21になり、それだけが変わっているようです。
PhoneyDeveloper 2017年


2

上記のコードに加えて、次のコードを追加してください。問題を解決しました

override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
     tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset) 
}

これだけで問題は解決しました!! ありがとうございました。この問題で何時間も無駄にした!
Murat Yasar 2017

2

また、タブバーを使用する場合、コレクションビューの下部コンテンツインセットはゼロになります。このため、以下のコードをviewDidAppearに配置します。

if #available(iOS 11, *) {
    tableView.contentInset = self.collectionView.safeAreaInsets
}

2

私の場合、これはうまくいきました(viewDidLoadに入れてください):

self.navigationController.navigationBar.translucent = YES;

1

collectionViewまたは上部の余分なスペースを削除するtableView

    if #available(iOS 11.0, *) {
        collectionView.contentInsetAdjustmentBehavior  = .never
        //tableView.contentInsetAdjustmentBehavior  = .never
    } else {
        automaticallyAdjustsScrollViewInsets = false
    }

上記のコードcollectionViewまたはtableViewナビゲーションバーの下に移動します。
以下のコードは、コレクションビューがナビゲーションの下に移動するのを防ぎます

    self.edgesForExtendedLayout = UIRectEdge.bottom

しかし、私は以下のロジックとUICollectionViewのコードを使用するのが大好きです

エッジインセット値は長方形に適用され、その長方形で表される領域を縮小または拡張します。通常、エッジインセットは、ビューのレイアウト中にビューのフレームを変更するために使用されます。正の値を指定すると、フレームは指定された量だけインセット(または縮小)されます。負の値を指定すると、指定した量だけフレームがアウトセット(または拡大)されます。

collectionView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
//tableView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)

UICollectionViewの最良の方法

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
}

0

このコードを削除してください

self.edgesForExtendedLayout = UIRectEdgeNone

0
  if #available(iOS 11, *) {
        self.edgesForExtendedLayout = UIRectEdge.bottom
  }

テーブルビューを持つカスタムresultsControllersでUISearchControllerを使用していました。新しいコントローラーを結果コントローラーにプッシュすると、テーブルビューが検索対象になりました。

上記のコードは問題を完全に修正しました

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.