[React Native] 吹き出しUIの作り方とコーディングサンプル


Webアプリで吹き出しUIをコーディングするには、CSSの疑似要素を工夫して三角形を形成する。ところがReact Nativeでは疑似要素をサポートしていない。というのもReact Nativeのスタイルの適用方法は、オブジェクト形式で定義しなければならないからだ。

そもそもネイティブアプリ作成におけるレイアウトで、疑似要素っぽいことを求めるシーンがあるのか知らないが、React NativeのCSS適用方式では、それを再現することができない。

それでもデザイン要件で、吹き出しUIをコーディングしなければならないこともある。

このエントリーでは、React Nativeコンポーネントに吹き出しUIをつくる方法と、そのコーディングサンプルを紹介したい。

React Nativeにおける疑似要素

まず疑似要素について言及しておこう。CSSの疑似要素とは、ターゲット要素に対して擬似的に仮想の要素を配し、スタイル適用を可能にしている。たとえば::beforeならば、ターゲット要素の先頭子要素として要素が挿入される。::afterならば、ターゲット要素の末尾子要素として要素が挿入される。

このように擬似要素として定められた特定の場所に仮想の要素が挿入され、さまざまな装飾に活用されている。

ところがすでに述べたとおり、React Nativeのスタイル適用方法では、これをサポートしていない。疑似要素はサポートしていないのだが、再現はできる。

疑似でなければよいのだ。

吹き出し三角形のしくみ

React Nativeで吹き出しUIのコーディングサンプルを示す前に、吹き出しUIたらしめる三角形オブジェクトのCSSを確認しておきたい。

.talk::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 15px;
  width: 0;
  height: 0;
  border-top: 10px solid #000000;
  border-right: 10px solid transparent;
  border-left: 10px solid transparent;
}

ここでポイントとなるプロパティは、width,height,borderが三角形を形成している。ボックスモデルの概念だとcontent領域の外側にpadding領域があって、border領域、margin領域をもつ。

上記のCSSを見ると、width,heightは0pxで、borderは上、右、左辺が10pxになっている。つまりcontent領域は潰して、border領域でサイズを得ていることがわかる。

上辺のボーダー幅が10px、左右辺ともにボーダー幅が10px、色を透明にすることで、上辺ボーダーだけ残って三角形に見えるという理屈だ。この場合の疑似要素サイズは、横幅20px、縦幅10pxになる。下辺ボーダーを定義していないため、上辺ボーダー幅しか保持せず縦幅は10pxというわけだ。

吹き出しUIのコーディングサンプル

それでは本題の吹き出しUIのコーディングサンプルをご覧いただこう。

上向き吹き出し

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.triangle} />{/* ? 三角形の要素 */}
        <Text>React Nativeで吹き出しUIをつくる</Text>
      </View>     
    );
  }
}
const styles = StyleSheet.create({
  container: {
    marginVertical: 'auto',
    marginHorizontal: 'auto',
    padding: 24,
    backgroundColor: '#81d4fa',
  },
  triangle: {
    position: 'absolute',
    bottom: '100%',
    left: '50%',
    transform: 'translateX(-50%)',
    width: 0,
    height: 0,
    borderBottom: '10px solid #81d4fa',
    borderRight: '10px solid transparent',
    borderLeft: '10px solid transparent',
  }
});

右向き吹き出し

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.triangle} />{/* ? 三角形の要素 */}
        <Text>React Nativeで吹き出しUIをつくる</Text>
      </View>     
    );
  }
}
const styles = StyleSheet.create({
  container: {
    marginVertical: 'auto',
    marginHorizontal: 'auto',
    padding: 24,
    backgroundColor: '#81d4fa',
  },
  triangle: {
    position: 'absolute',
    top: '50%',
    left: '100%',
    transform: 'translateY(-50%)',
    width: 0,
    height: 0,
    borderTop: '10px solid transparent',
    borderBottom: '10px solid transparent',
    borderLeft: '10px solid #81d4fa',
  }
});

下向き吹き出し

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.triangle} />{/* ? 三角形の要素 */}
        <Text>React Nativeで吹き出しUIをつくる</Text>
      </View>     
    );
  }
}
const styles = StyleSheet.create({
  container: {
    marginVertical: 'auto',
    marginHorizontal: 'auto',
    padding: 24,
    backgroundColor: '#81d4fa',
  },
  triangle: {
    position: 'absolute',
    top: '100%',
    left: '50%',
    transform: 'translateX(-50%)',
    width: 0,
    height: 0,
    borderTop: '10px solid #81d4fa',
    borderRight: '10px solid transparent',
    borderLeft: '10px solid transparent',
  }
});

左向き吹き出し

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.triangle} />{/* ? 三角形の要素 */}
        <Text>React Nativeで吹き出しUIをつくる</Text>
      </View>     
    );
  }
}
const styles = StyleSheet.create({
  container: {
    marginVertical: 'auto',
    marginHorizontal: 'auto',
    padding: 24,
    backgroundColor: '#81d4fa',
  },
  triangle: {
    position: 'absolute',
    top: '50%',
    right: '100%',
    transform: 'translateY(-50%)',
    width: 0,
    height: 0,
    borderTop: '10px solid transparent',
    borderRight: '10px solid #81d4fa',
    borderBottom: '10px solid transparent',
  }
});

まとめ

React Nativeコンポーネントに吹き出しUIをつくる方法と、そのコーディングサンプルの紹介だった。

Webコンテンツのコーディングとの相違は、疑似要素ではなく空要素にスタイルを当てるという一点くらいなもので、難しさはないはずだ。三角形を形成するアプローチはCSSコーディングそのものでボーダーを工夫して再現する。

つまりそのアレンジ方法もWeb用エントリーのものから得ることができるということだ。「CSS 吹き出し」などで検索すると、それらしい情報が得られるはずだ。

このエントリーが、あなたのクリエイティビティを刺激するものであると期待したい。


Leave a Reply

Your email address will not be published. Required fields are marked *