2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ReactNativeで複数行TextInputをスクロールしたときにfocusが当たるのを回避したい..出来たが...

Last updated at Posted at 2021-01-23

課題

メモ帳アプリで、1ページ丸々TextInputのページがあって、
そこでscrollするとフォーカスもあたってしまうという問題

 やり方1 TextInputを別要素で囲って制御する

参考:https://www.366service.com/jp/qa/cabd3c41d1468c813e5c2447e6911a01

ScrollView > TouchableHighlight > TextINput

でtextInputはpointerEvents=noneにしておく(pointerEventsはstateにset)。TextInputではイベントを拾わずScrollは外側のscrollViewで実現する。
PressはTouchableHighlightで拾い、そこでInputTextのpointerEventsをautoに変更し、ref経由でfocusを実行する。という感じ。

scrollとフォーカスの制御は問題なかったが、以下の点で問題があった。

  • フォーカスした時のkeybord避けにkeybord-spacerを使っていたのだが、高さが微妙にキーボードに被ってしまう。

  • なので..自分でキーボード表示時のにScrollViewの高さを変更して調整しようと考えたが...

  • ScrollViewや内部の要素にheightを指定するとスクロール出来ない。=>外をViewで囲って高さを指定することでクリア。

  • TouchableHighligh、TextInputに高さが指定できないので、新規作成のときは1行だけの高さしかなくてタッチ出来る範囲が狭くなる。不便。

  • キーボーどと被らないかもしれないが、Viewの一番下がキーボードの直上にくる。選択した位置がキーボードの上に来るわけではないので、これでは駄目.... 更にScrollToなどでの調整が必要

  • 高さをDimensions.get('window').heightから取得するとはみ出してしまう..navigationヘッダーやSafeareaを考慮しないと行けない。ちょっと小さめにしておくことが必要か.

  • そもそもフォーカスをした時に、タッチした位置が選択状態にならない、もう1回タッチしないと行けない。これがでかい。

ちょっと、課題が多すぎる..まだまだ時間がかかってしまう..

一応参考ソース

<ScrollView>
    <TouchableOpacity
        onPress={(e) => this.onpressWrapper(e)}
    >
        <TextInput
            style={[styles.textInput ]}//高さを指定するとscrollがそこで止まる
            multiline={true}
            onChangeText={(text) => this.save(text)}
            onFocus={() => console.log("focus")}
            defaultValue={this.state.text}
            pointerEvents={this.state.pointerEvents}
            ref={this.textInputRef}
        />
    </TouchableOpacity>
</ScrollView>
this.textInputRef = React.createRef();
onpressWrapper = (e) => {
    const ref = this.textInputRef.current
    this.setState({
        pointerEvents: 'auto',
    }, ref.focus())
}

やり方2 InputScrollView

以下使ってみる..
https://github.com/baijunjie/react-native-input-scroll-view

ここもスクロール制御は良いけど、フォーカスとキーボード回避がネック。
KeybordAvoidanceViewを使っており、1行程度がキーボードと被ってしまう。。。
フォーカス時にも上手くタッチ位置がキーボード上に来ない。

結論

スクロールでフォーカスが当たるほうがまだ使いやすい...
色々なテクニカルなことは他にもありそうだけど、もうちょっと余裕のある時に検討。
あとはネイティブで作ったらどういう挙動なんだろうか、確認したい所。

やり方3

InputScrollViewの中を見て、以下のコードをパクったら確かにscroll時にfocusが当たらなくなった。responderを使うと。
しかし一報で、keybordSpacerが効かなくなってしまった。(キーボードに被ってスクロールしていってしまう....)
もう少しで出来そうなのに...

これ以上はどんどん、トリッキーになって行きそうだし、、
規模も小さいアプリ出し、ネイティブアプリに変更しようかな。

onFocus = event => {
    const target = event.target;
    this._curFocus = target;
}

onBlur = event => {
    const target = event.target;
    if (this._curFocus === target) this._curFocus = null;
}

_checkhandleGesture = event => {
    const target = event.target;
    if (target === this._curFocus) return false;
    const targetInst = event._targetInst;
    const uiViewClassName = targetInst.type || // >= react-native 0.49
        targetInst.viewConfig.uiViewClassName; // <= react-native 0.48
    return uiViewClassName === 'RCTTextField' || uiViewClassName === 'RCTTextView' || uiViewClassName === 'RCTMultilineTextInputView';
};




renderScrollTextInput = () => {
    return (
        <ScrollView
            onFocus={this.onFocus}
            onBlur={this.onBlur}
            style={{ flex: 1 }}
        >
            <View style={{ flex: 1 }} onStartShouldSetResponderCapture={isIOS ? this._checkhandleGesture : null}>
                {this._renderInputText()}
            </View>
        </ScrollView>
    )
}

やり方4:編集モードと非編集モードを制御するのがよいのか?

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?