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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

4177閲覧

メッセンジャーUIの実現方法

TakutoNagano

総合スコア150

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2015/11/18 03:48

###前提・実現したいこと
TableViewの下が最新情報を表示するメッセンジャー機能の実装です。
(例:Line、Facebook Messenger)
画面遷移後に一番下に最新のメッセージを表示したい。
無理やり実現しているがより良い実装方法を知りたい。

皆さんの知見を是非お貸しください。

###発生している問題・エラーメッセージ
配列情報を取得後に
tableView.scrollToRowAtIndexPath(lastIndexPath atScrollPosition: .Bottom, animated: animted)
(lastIndexPathは最後のSectionの最後のCell、つまり最新メッセージを示すNSIndexPathです)
を実行しても、一番下のセルまで表示されない。

###現在の実装
サーバから、JSON配列でメッセージ情報を受信時間による降順で受信しパース。(最新が先頭)
reverseをかけて逆順に並び替えTableViewに表示しているが、
一番下まで綺麗に表示されないため以下の処理を実装。

tableView.scrollToRowAtIndexPath(lastIndexPath atScrollPosition: .Bottom, animated: animted)をコール
↓(以下ループ)
scrollViewDidEndScrollingAnimationでスクロール座標を取得

一番下のセルまで表示しているか →[true] 終了

[false]
ContentOffsetを計算しtableView.setContentOffset(ContentOffset, animated: true)を実行

###補足情報(言語/FW/ツール等のバージョンなど)
Xcode 7.0.1(今後Xcode 7.1以降にアップ予定)
StoryboardとAutoLayoutを使用
Swift 2.0
現在はiOS7以上の対応をしていますが、iOS8以上のみまたはiOS9のみの情報でも構いません。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

scrollToRowAtIndexPath() の前に reloadData() を入れてもダメでしょうか?

チャットアプリ風に、画面下部にTextFieldを配置したテストプログラムで、
以下のように処理してみたところ、正常にスクロールしてくれました。

swift

1var cells: Dictionary<NSIndexPath, String> = [:] 2 3//returnを押した時に呼ばれる 4func textFieldShouldReturn(textField: UITextField) -> Bool { 5 //close keyboard 6 textField.resignFirstResponder() 7 //add 8 let indexPath = NSIndexPath(forRow: cells.count, inSection: 0) 9 cells[indexPath] = textField.text 10 //clear text 11 textField.text = "" 12 //reload 13 tableView.reloadData() 14 //scroll 15 tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true) 16 17 return true 18}

Xcode7.1 + iPhone5 + iOS9.1です。

投稿2015/11/18 06:03

編集2015/11/18 06:10
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakutoNagano

2015/11/18 06:19

回答ありがとうございます! ベストアンサーで教えていただいたstackoverflowに記述されている通り、TableViewの描画状態と呼び出すタイミングの関係による動作不良だったようです。 テストプログラムまで作って試して頂いてありがとうございました!
fuzzball

2015/11/18 06:24

「画面遷移後に‥」というのを見落としていて、的外れな回答になってしまいましたw
guest

0

ベストアンサー

もしかして、scrollToRowAtIndexPathをviewWillAppearのタイミングで実行していますか?
もしそうなら、以下のURLが参考になると思います。
http://stackoverflow.com/questions/2156614/how-to-start-uitableview-on-the-last-cell

ここに書かれているように、scrollToRowAtIndexPathはviewDidAppear以降のタイミングなら正しく動作しますが、viewWillAppearのタイミングではtableViewの最終セルが読み込まれていないため、意図した位置にスクロールさせるのが難しいようです。
iOS6以前なら、scrollToRowAtIndexPathの前にreloadDataを入れることでうまく動作できるようになっていたようですが、iOS7以降はそれもうまくいかず、結局上記URLの最高得票を得た回答の最後のコメントからリンクされている
http://stackoverflow.com/questions/4163579/how-to-detect-the-end-of-loading-of-uitableview/19367073
の回答にあるように、willDisplayCellの中で最終セルをロードしたか判断し、そのタイミングでscrollToRowAtIndexPathを実行すれば、うまく最終位置を表示できるようです。

viewDidAppearのタイミングでは、一旦テーブルが表示されてから最終位置へスクロールする形になってしまうため、あらかじめ最終位置を表示した状態から開始したい場合は、これを参考にしてください。

投稿2015/11/18 05:33

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakutoNagano

2015/11/18 06:14

下段リンクの方を参考にしてみたところ、うまく動作しました! ありがとうございます!! 挙動としてはviewWillAppearで通信を投げおりレスポンスが返ってくる前にviewDidAppearまで呼び出されています。 ただ、そこからreloadDataとscrollToRowAtIndexPathを同時に呼び出していたため「tableViewの最終セルが読み込まれていない」状態での呼び出しになっていたようです。 以下のようにコードを修正ました。 初回ロード時限定の動きなのでフラグ制御を追加、またギリギリ次のセクション・セルの頭だけが見えている状態だとindexPathsForVisibleRows?.lastとindexPathの値にずれが生じたので一つ早めに処理してみました。 func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if let lastIndexPath = tableView.indexPathsForVisibleRows?.last { if lastIndexPath.section - 1 == indexPath.section { if isFirstScrollToBottom { isFirstScrollToBottom = false tableView.scrollToRowAtIndexPath(dataSource.lastIndexPath(), atScrollPosition: .Bottom, animated: false) } } } }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問