OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

React Native の ScrollView でスクロール時に child を上部に貼り付けたい

こんにちは、アプリ開発担当のエモトです。本業は稲作で、合間に横スクロールのダンジョン攻略や、アプリ開発を行っています。

React Native で画面を作る時、ScrollView を利用する方は多いと思います。その画面でスクロールするとき、ある child だけ上部に固定させたいというシーンが出てくるかもしれません。iOS で言うと UITableView におけるセクションヘッダーに近い動きです。さて、それを React Native で実装したい場合、どうすれば良いでしょうか?

f:id:mitsuharu_e:20201128141318g:plain

上部固定させたい

まず最初にネイティブ開発で考えると、iOS の UIScrollView にはそのような機能がないので、UITableView のセクションヘッダーをカスタマイズする方法が考えられます。

それに従うと React Native なら ScrollView から SectionList に置き換えと、手間のかかる改修が予想されました・・・が!、なんと、React Native の ScrollView 自体にその機能が既に実装してありました。stickyHeaderIndices に固定したい child の index を指定するだけです。簡単でした。

const Component: React.FC<Props> = () => {
  const stickyHeaderIndices = [1]
  return (
    <ScrollView stickyHeaderIndices={stickyHeaderIndices} >
      <Header />
      <Sticky />
      <Contents />
    </ScrollView>
  )
}

なぜ上部固定できるのか?

すでに ScrollView で組んでるコードをバラすことなく、パラメーター1つで実現できました。ただ、ここで1つの疑問が生まれます。本来ネイティブの UIScrollView ではそのよう機能がないのに、なぜ React Native の ScrollView だとできるのか?。

ここで私は、「ScrollView はセクションヘッダーを利用するため、実は UITableView なのでは?」と考えましたが、ネイティブ側に対応する RCTScrollView.h を見る限り、UIView を継承しいて、その考えは誤りでした。

次に、stickyHeaderIndices を設定すると呼ばれる ScrollViewStickyHeader.js を見ると、その答えが分かりました。

style={[..., {transform: [{translateY: this._translateY}]}, ...]}

このコンポーネントは AnimatedView で作られて、style をアニメーション制御していました。あの React Native でも力技的な・地味なコードを書いているんだなーという印象を受けました。

まとめ

私のバックボーンは iOS アプリのネイティブ開発なので、何かを作る際はまずネイティブの知識や経験を持ってきて、それを React Native に当てはめることをやるので、今回のようなネイティブではできないことが React Native では簡単にできるのは驚かされます。日々勉強です。

また、毎日使っている、便利でスマートなフレームワークは、OSS活動される皆様方たちの努力の上でなりたっているんだなと、改めて実感しました。そのフレームワークを使って、よいアプリを作っていこうと思う、良い機会でした。