web-dev-qa-db-ja.com

iOS11での奇妙なuitableviewの振る舞い。セルがナビゲーションで上にスクロールするアニメーションをプッシュする

私は最近、いくつかのコードを新しいiOS 11 Beta 5 SDKに移行しました。

私は今UITableViewから非常に紛らわしい振舞いを得ます。テーブルビュー自体はそれほど派手ではありません。私はカスタムセルを持っていますが、ほとんどの場合それはそれらの高さのためだけのものです。

テーブルビューでView Controllerをプッシュすると、セルが「上にスクロール」(またはテーブルビューフレーム全体が変更)され、プッシュ/ポップナビゲーションアニメーションに沿って下に移動する追加のアニメーションが表示されます。 gifを見てください。

wavy tableview

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

View Controllerのプッシュコードは非常に標準的です。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は与えられたサイズと色で正方形の画像を作成します。

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

私はこの問題についての考えをいただければ幸いです。

115
iur

これはUIScrollView's(UITableViewはUIScrollviewのサブクラスです) new contentInsetAdjustmentBehavior propertyに起因します。これは.automaticに設定されていますデフォルトではです。

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

    tableView.contentInsetAdjustmentBehavior = .never

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

143
Maggy Hillen

Maggyの答えに加えて

OBJECTIVE-C

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

この問題は、iOS 11.2のナビゲーション移行時にView ControllerのビューのsafeAreaInsetsが誤って設定されていたiOS 11のバグが原因で発生していました。 contentInsetAdjustmentBehavior.neverに設定することは、他の望ましくない副作用を引き起こす可能性があるので、大きな回避策ではありません。回避策を使用する場合は、iOSバージョンが11.2以降の場合は必ず削除してください。

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

21
Lal Krishna

あなたは例えばdidFinishLaunchingWithOptionsの中でNSProxyを使用することによってアプリケーションを通してこの行動を一度に編集することができます:

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

これが私がどうやってこの問題を解決することができたか それでもiOS 11が自動的にインセットを設定することを可能にしている間 である。私はUITableViewControllerを使っています。

  • ストーリーボードのビューコントローラで、「トップバーの下のエッジを延長する」および「不透明バーの下のエッジを延長する」を選択します(またはプログラム的に)。セーフエリアインセットはあなたの視野がトップバーの下に行かないようにします。
  • ストーリーボードのテーブルビューで[セーフエリアへのインセット]ボタンをクリックします。 (またはtableView.insetsContentViewsToSafeArea = true) - これは必要ではないかもしれませんが、それは私がしたことです。
  • コンテンツインセット調整動作を "スクロール可能な軸"(またはtableView.contentInsetAdjustmentBehavior = .scrollableAxes)に設定します - .alwaysも機能する可能性がありますが、テストしませんでした。

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

viewSafeAreaInsetsDidChangeUIViewControllerメソッドをオーバーライドして、Table ViewがScroll Viewのインセットをセーフエリアのインセットに強制的に設定するようにします。これは、マギーの答えの「しない」設定と関連しています。

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

注:UITableViewControllerの場合、self.tableViewself.viewは同じものにする必要があります。

4
Santa Claus

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

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

2つのことをする必要があります。
1。 push/pop時にscrollViewがアニメーション化しないようにする
2。それはiPhone Xのために必要とされるので、.automaticな振る舞いを保持します。ポートレートでは、コンテンツは下のスクロールバーの下に表示されます。

新しい簡単な解決策:XIBの:メインビューの一番上に新しいUIViewを追加します。他のサブビューなどに接続する必要はありません。

古い解決策:

注: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
    }
}
3
El Horrible

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

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

上記のコードと合わせて、次のようにコードを追加してください。それは問題を解決しました

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

私はiOS 11.1のバグを再現することができますが、バグはiOS 11.2以降で修正されているようです。 http://openradar.appspot.com/34465226を参照してください。

2
Linda

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

self.navigationController.navigationBar.translucent = YES;
1
nemissm

このコードを削除する

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

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

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

0

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
Nazmul Hasan