React Nativeでボタンを押している間動作する処理

はじめに

押している間なにかしらのアクションを発火させたい時があると思う

それは、ボタンを2秒押下で下書き保存や4秒押下で記事公開にする等をインタラクションを交えつつ処理をするようなケースである

私のケースだと、チャットシステム構築の際にいいねボタンの横にいいね数を表示しているのだが、実際にいいね数のテキストを押している間モーダルでいいねしたユーザを表示することはできないか考えたことがある

このようにユーザからのフィードバックを用いて処理するReact Nativeのコンポーネントは他のケースだと押下すると透過するTouchableOpacityや押下した際にハイライトを変えるTouchableHighlight、押下時にボタンがバウンスするTouchableBounceがある
今回は上記以外のケースである表題に関してオリジナルのフィードバックを返すボタンを構築する

セットアップ

import React, { Component } from 'react'
import {
  View,
  Text,
  StyleSheet,
  TouchableWithoutFeedback,
  TouchableHighlight
  } from 'react-native'

コンポーネントとスタイル設定

class OriginalBtn extends Component{
  constructor(props) {
    super(props)
    this.state = {
      modalVisible: false,
      userLists: ['miyabi', 'micky', 'hogehoge'],
      reactionNum: 3
    }
  }
  render() {
		return (
    <View style={styles.container}>
      <Modal
        animationType="fade"
        transparent={true}
        visible={this.state.modalVisible}
        style={styles.modal}
      >
        <View style={{
          marginTop: 40,
          flex: 1,
          flexDirection: 'column',
          alignItems: 'center'
          }}>
          <View style={{
            height: 100,
            width: 300,
            padding: 10,
            backgroundColor: 'rgba(0, 0, 0, 0.5)',
            }}>
            <Text style={{color: 'white'}}>{this.state.userLists.join('\n')}</Text>
          </View>
        </View>
      </Modal>
      <View style={[styles.contentscontainer]}>
        <View
        style={[styles.reactionContainer]}
        >
          <TouchableWithoutFeedback 
            onPressIn={this.PressIn} 
            onPressOut={this.PressOut}
                >
              <View>
              <Text
                style={styles.reactionNumText}
              >
              {this.state.reactionNum}
              </Text>
              </View>
          </TouchableWithoutFeedback>
        </View>
      </View>
    </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 12,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'transparent',
    borderWidth: 0.5,
    borderColor: 'rgba(255, 255, 255, 0.1)'
  },
  contentscontainer: {
    flex: 0.1
  },
  text: {
    color: 'white',
    marginLeft: 12,
    marginRight: 10,
    paddingRight: 20,
    fontSize: 15,
    width: 250,
  },
  reactionContainer: {
    flexDirection: 'row',// widthで吹き出しサイズやで
    marginTop: 5
  },
  reactionNumContainer: {
    width: 250,
  },
  reactionNumText: {
    color: 'white',
    fontSize: 12,
    fontWeight: '100',
    paddingTop: 6.9,
    paddingLeft: 5,
  },
  modal: {
    height: 100
  }
})

アクション作成

PressIn = () => {
    console.log('pushing')
    this.setState({modalVisible: true})
  }
PressOut = () => {
    console.log('push out!')
    this.setState({modalVisible: false})
  }

最後に

以上のサンプルコードを参考にユーザのフィードバックをもとに多様なインタラクションを表現してみて下さい

最終コード

import React, { Component } from 'react'
import {
  View,
  Text,
  StyleSheet,
  TouchableWithoutFeedback,
  TouchableHighlight
  } from 'react-native'

class OriginalBtn extends Component{
  constructor(props) {
    super(props)
    this.state = {
      modalVisible: false,
      userLists: ['miyabi', 'micky', 'hogehoge'],
      reactionNum: 3
    }
  }
  PressIn = () => {
    console.log('pushing')
    this.setState({modalVisible: true})
  }
  PressOut = () => {
    console.log('push out!')
    this.setState({modalVisible: false})
  }
  render() {
    return (
    <View style={styles.container}>
      <Modal
        animationType="fade"
        transparent={true}
        visible={this.state.modalVisible}
        style={styles.modal}
      >
        <View style={{
          marginTop: 40,
          flex: 1,
          flexDirection: 'column',
          alignItems: 'center'
          }}>
          <View style={{
            height: 100,
            width: 300,
            padding: 10,
            backgroundColor: 'rgba(0, 0, 0, 0.5)',
            }}>
            <Text style={{color: 'white'}}>{this.state.userLists.join('\n')}</Text>
          </View>
        </View>
      </Modal>
      <View style={[styles.contentscontainer]}>
        <View
        style={[styles.reactionContainer]}
        >
          <TouchableWithoutFeedback 
            onPressIn={this.PressIn} 
            onPressOut={this.PressOut}
          >
              <View>
              <Text
                style={styles.reactionNumText}
              >
              {this.state.reactionNum}
              </Text>
              </View>
          </TouchableWithoutFeedback>
        </View>
      </View>
    </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 12,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'transparent',
    borderWidth: 0.5,
    borderColor: 'rgba(255, 255, 255, 0.1)'
  },
  contentscontainer: {
    flex: 0.1
  },
  text: {
    color: 'white',
    marginLeft: 12,
    marginRight: 10,
    paddingRight: 20,
    fontSize: 15,
    width: 250,
  },
  reactionContainer: {
    flexDirection: 'row',
    marginTop: 5
  },
  reactionNumContainer: {
    width: 250,
  },
  reactionNumText: {
    color: 'white',
    fontSize: 12,
    fontWeight: '100',
    paddingTop: 6.9,
    paddingLeft: 5,
  },
  modal: {
    height: 100
  }
})