質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.82%

スクロールの際にUIButtonの表示/非表示を切り替える方法について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 657

samson66

score 34

実現したいこと
tableviewをスクロールした際にcellが並ぶ画面(tableview)の上に
(浮いて見えるように)固定されたUIButtonがcellの邪魔にならないように非表示にし、
スクロールをしてない時は表示するようにしたいです。

画面レイアウト
tableviewに固定されているUIButton

以下のサイトを参考に作ってみましたが、シミュレーターでスクロールをしてみてもUIボタンは非表示になりませんでした。
http://blog.all-in.xyz/2016/06/20/how-to-put-button-on-tableview-which-will-not-scroll-with-table/

viewcontrollerには以下のようにコーディングしました。

import UIKit

class ViewController: UIViewController {

  // UIButton の表示/非表示を管理
  private var isButtonDisplayed: Bool = true

  @IBOutlet weak var addPictureButton: UIButton!

  // 先ほど実装した UITableView 側の ViewController の delegate に self を設定
  override func prepare(for segue: UIStoryboardSegue, sender: Any!) {
    if segue.identifier == "ArticleViewControllerSegue" {
      let vc = segue.destination as! ArticleViewController
      vc.delegate = self
    }
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
  }
}

// スクロール発生時に通知されるプロトコルを実装
extension ViewController: ArticleViewControllerDelegate {
  // スクロールアップ時に UIButton を表示する
  func viewDidscrolledUp() {
    if !isButtonDisplayed {
      addPictureButton.isHidden = false
      isButtonDisplayed = true
    }
  }

  // スクロールダウン時に UIButton を非表示にする
  func viewDidscrolledDown() {
    if isButtonDisplayed {
      addPictureButton.isHidden = true
      isButtonDisplayed = false
    }
  }
}
import UIKit

// スクロールの発生を検知してUIButtonの表示を切り替えるためのプロトコル
protocol ArticleViewControllerDelegate: class {
  func viewDidscrolledUp()
  func viewDidscrolledDown()
}

class ArticleViewController: UIViewController {

  @IBOutlet weak var tableview: UITableView!

  weak var delegate: ArticleViewControllerDelegate?
  // スクロールの開始点
  var scrollBeginingPoint: CGPoint!

  // ドラッグしてスクロールが発生する直前に呼び出される
  func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    scrollBeginingPoint = scrollView.contentOffset
  }

  // スクロールが発生している間常に呼び出される
  func scrollViewDidScroll(scrollView: UIScrollView) {
    let currentPoint = scrollView.contentOffset

    if scrollBeginingPoint.y < currentPoint.y {
      print("scroll to bottom")
      delegate?.viewDidscrolledDown()
    } else {
      print("scroll to top")
      delegate?.viewDidscrolledUp()
    }
  }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
      tableview.delegate = self
      tableview.dataSource = self
    }

}

extension ArticleViewController: UITableViewDelegate {
}

extension ArticleViewController: UITableViewDataSource {

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // スクロールさせるために50行のCellを表示
    return 50
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // CellのtextLabelにindexPath.rowを表示
    let cell = UITableViewCell(style: .default, reuseIdentifier: "cell1")
    cell.textLabel?.text = String(indexPath.row)
    return cell
  }

}


storyboardはこのような状態です。
イメージ説明

どんなことでも構いませんのでアドバイス、お待ちしておりますm(_ _)m

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

まず、最初にお聞きしたいのですが、なぜ 2 つの UIViewController を使われているのですか?
1 つの UIViewController に UITableView と UIButton を設置しても良いと思うのですが。

では、回答させていただきます。

まず、samson66 さんがやりたいと仰っているスクロールに応じてボタンの表示・非表示を切り替えたいということであれば、viewDidscrolledDown や viewDidscrolledUp  は、あまり本質的ではないと思うので、シンプルに、スクロールされたかどうか、スクロールが終わったかどうかという状況でお話しします。

また、以下に示すコードは、UI を Storyboard ではなく、コードベースで実装しているので少し見慣れないところも一部あるかと思いますが、適宜コメントを書いているので意味がわからないということは無いかと思います。
また、複雑な UI はどうしてもコードベースで制御するので、今のうちに慣れておくといいかと思います。

以下のコードは、UITableView と UIButton を表示させている UIViewController です。

スクロール時・スクロール終了時のボタン表示・非表示の切り替え方法は、コードとコメントを見ることで分かるのではないかと思います。

また、参考にされているページのコードを詳しく見てはいませんが、シンプルに 1 つの UIViewController で
実現できますし、Protocol を使う必要は無いかと思います。もちろん、遷移前のビューにスクロールを反映させたいという場合は、必要になるかもしれませんが。

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    fileprivate let cellId = "cellId"

    // tableView の生成
    fileprivate lazy var tableView: UITableView = {
        let tv = UITableView()
        tv.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
        tv.translatesAutoresizingMaskIntoConstraints = false
        tv.rowHeight = 80
        tv.delegate = self
        tv.dataSource = self
        return tv
    }()

    // button の生成
    fileprivate let button: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Click", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = .blue
        button.translatesAutoresizingMaskIntoConstraints = false
        button.layer.cornerRadius = 38
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // view に tableView と button を追加
        view.addSubview(tableView)
        view.addSubview(button)

        // tableView の位置を設定
        tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true // 上
        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true // 左
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true // 右
        tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true // 下

        // button の位置を設定
        button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32).isActive = true
        button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32).isActive = true
        button.widthAnchor.constraint(equalToConstant: 76).isActive = true // 幅
        button.heightAnchor.constraint(equalToConstant: 76).isActive = true // 高さ
    }

    // スクロール中に呼ばれる
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("start")
        // 表示・非表示を綺麗に見せるために、アニメーションを適用
        UIView.animate(withDuration: 0.25) {
            self.button.alpha = 0
        }
    }

    // スクロールが終わった時に呼ばれる
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("end scroll")
        UIView.animate(withDuration: 0.25) {
            self.button.alpha = 1
        }
    }

    // ドラッグスクロールが終わった時に呼ばれる
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        print("end drag")
        UIView.animate(withDuration: 0.25) {
            self.button.alpha = 1
        }
    }

    // セルの数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }

    // セルのテキストを設定
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        cell.textLabel?.text = "item \(indexPath.row)"
        return cell
    }

}


起動時
起動時

スクロール中
スクロール中

スクロール終了時
スクロール終了時

参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

TableViewの上にボタンを用意すればすんなり書けます。
サンプル作りましたので参考になれば幸いです。
https://github.com/MilanistaDev/DisappearButttonWhileScrolling

最小で書くならこんな感じです。

ボタンをTableViewの上に置く。

イメージ説明

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var bottomButton: UIButton!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }
}

extension ViewController: UIScrollViewDelegate {

    // 肝はここ
    //スクロール開始時にボタンのalpha値を0に
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        self.bottomButton.alpha = 0.0
    }
    //スクロール終了時にボタンのalpha値を1に
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        self.bottomButton.alpha = 1.0
    }
}

extension ViewController: UITableViewDelegate {
}

extension ViewController: UITableViewDataSource {

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

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = String(indexPath.row)
        return cell
    }
}

イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.82%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る