15
2

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.

Fringe81Advent Calendar 2019

Day 1

React Nativeでライブラリを使わずに枠線だけの吹き出しを作る

Last updated at Posted at 2019-12-01

Fringe81アドベントカレンダー1日目の記事です。

弊社の提供しているUniposというサービスではWeb版のほか、Android/iOS向けにReact Nativeを使ってアプリを開発しています。
今回はそのアプリの新機能開発において、「枠線だけの吹き出し」を作る必要が出たためやってみた、という軽めの記事でございます。

「枠線だけの吹き出し」というのはこんなやつです。

スクリーンショット 2019-11-28 9.38.48.png

react-native-svgなどを使って作る方法もありそうですが、今回は依存ライブラリなしでReact Nativeの標準コンポーネントだけを使って作ってみました。

環境

  • React Native 0.59.9
  • TypeScript 3.7.2

今回使用した環境は上記ですが、おそらく他の環境でも問題なく使用できるはずです。

結論

仕組みはどうあれ、先に出来上がったコードを貼ります。

import * as React from 'react';
import {View, Text, StyleSheet} from 'react-native';

const BALLOON_TRIANGLE_HEIGHT = 14;

export const CommentBalloon = ({text}: {text: string}) => {
  return (
    <View style={{justifyContent: 'flex-end', paddingTop: BALLOON_TRIANGLE_HEIGHT}}>
      <View style={styles.balloonContainer}>
        <View style={[styles.balloonTriangleBase, styles.balloonTriangleOuter]} />
        <View style={[styles.balloonTriangleBase, styles.balloonTriangleInner]} />
        <View style={styles.textContainer}>
          <Text style={styles.text}>{text}</Text>
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  balloonContainer: {
    width: '100%',
    backgroundColor: '#FFFFFF',
    borderWidth: 1,
    borderColor: '#E1E6E6',
    borderRadius: 2
  },
  balloonTriangleBase: {
    width: 0,
    height: 0,
    position: 'absolute',
    bottom: '100%',
    borderTopColor: 'transparent',
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent'
  },
  balloonTriangleOuter: {
    left: 32,
    borderWidth: BALLOON_TRIANGLE_HEIGHT,
    borderBottomColor: '#E1E6E6'
  },
  balloonTriangleInner: {
    left: 33,
    borderWidth: BALLOON_TRIANGLE_HEIGHT - 1, // border分だけ引く
    borderBottomColor: '#FFFFFF'
  },
  textContainer: {
    padding: 15
  },
  text: {
    fontWeight: '300',
    fontSize: 14,
    lineHeight: 20,
    color: '#4A4A4A',
    maxWidth: '100%',
    letterSpacing: 0
  }
});

仕組み

触ったことがある方はすでにご存知の通り、React NativeではCSSと似た形式のプロパティを持ったオブジェクトを用いて画面のスタイルを定義します。
そのため、CSSでできることは大抵できるのですが、いくつかできないことがあります。その中の一つに、:before:afterといった擬似要素が挙げられます。

CSSを使って吹き出しを作る方法として有名なのは、:before:after擬似要素を用いて、大きさのない要素に対してborderを当てることによって、吹き出しの三角形の部分(余談ですがくちばしって呼ぶらしいですね)を作る方法があります。

【コピペ改変OK】CSSで作れる吹き出しデザイン8選 | creive【クリーブ】

Webでの方法はこちらの記事がとても分かり易かったです。

React Nativeでは擬似要素が使用できないため、代わりに中身のないViewコンポーネントを配置して、そのコンポーネントに対してスタイルを当てています。

また、枠線のみの吹き出しにするため、大きさの違うくちばしを2つ用意し、外側の線部分と、内側の塗りの部分をずらして重ねています。(balloonTriangleOuterballoonTriangleInnerがそれ)


また、くちばしの部分は絶対位置指定(position: 'absolute')で配置しているため、このままだと上に配置されたコンポーネントがくちばしの上に重なってしまうのを防止するため、 <View style={{justifyContent: 'flex-end', paddingTop: BALLOON_TRIANGLE_HEIGHT}}> というコンポーネントでラップすることでCommentBalloonコンポーネント全体で見たときにくちばしを含んだ高さとなるように調整しています。

Simulator Screen Shot - iPhone 11 Pro Max - 2019-12-01 at 11.41.34.png

所感

React NativeのstyleがWebのCSSと同じ挙動になるように実装されているおかげもあり、こうやってWebでよく用いられるテクニックを転用して、さほど悩むことなく画面を作れるのは幸せなことだと改めて思いました。

15
2
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
15
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?