入力欄と直近発言が画面下にあるようなチャットアプリにおいて、iOSのバーチャルキーボードが被って不都合が起きていた
解決方法
- 基本方針はwindow.scrollTo
- ネットワークのレスポンスでログが増える
- コンテンツが予測不能なタイミングで非同期に更新され、高さが変わる
- React.useEffectはコンポーネントのレンダリング後に呼ばれる、これを使う
const [logs, setLogs] = useState(...)
- レスポンスでsetLogsして再描画をトリガーする
useEffect(scrollToBottom, [logs])
でレンダリング後にスクロール- これでこの経路は解決
- テキストエリアが中身の文章量によってサイズを変える
- Material-UIのTextareaAutosize
- onChangeでスクロールしても上手くいかなかった
- なぜなら、このタイミングではまだレンダリングが終わっていないから
- TextareaAutosize
- 内容変更時に高さを調べて、更新する必要があればsetStateしている
- この変更のトリガーでコンポーネントのレンダリングが走る
- 子コンポーネントのレンダリングの後にフックをする方法がわからなかった
setTimeout(scrollToBottom);
する- これでレンダリング後になる保証はないかも
- scrollToBottomの中身 ts
const scrollToBottom = () => {
const e = document.getElementById("bottom") as HTMLElement;
const y = e.offsetTop - document.documentElement.clientHeight + 300;
if (y > 0) {
window.scrollTo(0, y);
}
};
- 300はバーチャルキーボードの高さ。デバイスから取得する方法がわからなかった
- 参考資料(*1)によれば301で、手元での11ProMaxでの実験でもまあ問題なさそうだったからこうした
- bottomは入力欄の下にhrを置いてる
-
関連 テキスト入力後にフォーカスが外れる 参考資料
https://github.com/mui-org/material-ui/blob/next/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js pKeicho
window.innerHeightで取得する場合、上にスクロールをしてアドレスバーが表示されているときと、下にスクロールしてアドレスバーが表示されていないときでは取得できる値が異なる。 document.documentElement.clientHeightで取得する場合はアドレスバーによる影響はなく、常に一定の値が取得できる。
-
ios - What is the height of iPhone’s onscreen keyboard? - Stack Overflow
- (*1)List of the official iOS keyboards’ heights (and how to calculate them) | by Federica Benacquista | Dec, 2020 | Medium The Eccentric Ways of iOS Safari with the Keyboard | by David Fedor | Open Digerati html - Iphone safari not resizing viewport on keyboard open - Stack Overflow iphone - iPad Web App: Detect Virtual Keyboard Using JavaScript in Safari? - Stack Overflow Issues with position fixed & scrolling on iOS