LoginSignup
13
8

More than 3 years have passed since last update.

Flutter で画像を角丸に切って『キレイに』ボーダーをつける

Last updated at Posted at 2020-02-13

画像を角丸に切って『キレイに』ボーダーをつける。こう。
スクリーンショット 2020-02-13 19.03.19.png

これが Flutter の場合、『キレイに』つけるのが地味に難題。
※一応だがキレイに書ける方法は一番下に載せてるので飛ばしても OK。

自分が思いつく実装方法は以下の 3 つ。

  1. BoxDecoration で image, border, borderRadius を指定
  2. BoxDecoration で border を表示、子をさらに ClipRRect で角丸クリップ
  3. CustomPaint で clip したりして頑張る

1, 2 を以下で試してみる。

1. BoxDecoration で image, border, borderRadius を指定

    return Container(
      width: 200,
      height: 200,
      decoration: BoxDecoration(
        image: DecorationImage(
          image: NetworkImage('https://i.picsum.photos/id/563/200/200.jpg'),
        ),
        border: Border.all(color: Colors.white, width: 3),
        borderRadius: BorderRadius.circular(10),
      ),
    );

結果↓
スクリーンショット 2020-02-13 18.50.48.png

なんだかんたんに出来たじゃん……ん?
スクリーンショット 2020-02-13 18.50.48.png

外側が若干汚い。どうやら 画像の丸角部分が少しはみ出してしまう ようだ。背景色やボーダーの色によってはごまかせるかもしれないが、場合によっては非常に目立ってしまう。

2. BoxDecoration で border を表示、子をさらに ClipRRect で角丸クリップ

    return Container(
      width: 200,
      height: 200,
      decoration: BoxDecoration( 
        border: Border.all(color: Colors.white, width: 3),
        borderRadius: BorderRadius.circular(10),
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(10),
        clipBehavior: Clip.hardEdge,
        child: Image.network('https://i.picsum.photos/id/563/200/200.jpg'),
      ),
    );

結果↓
スクリーンショット 2020-02-13 18.55.10.png

お、今度こそやったか……ん?
スクリーンショット 2020-02-13 18.55.10.png

今度は内側に緑の隙間が出来てしまった。これは border 分 child が小さくなった結果、角丸が合わなくなった ため。

2-2. 上記のコードを foregroundDecoration に変える

foregroundDecoration に設定すれば、その名の通り foreground にボーダーが書かれて、 child が縮まなくなる。

    return Container(
      width: 200,
      height: 200,
      foregroundDecoration: BoxDecoration( 

結果↓
スクリーンショット 2020-02-13 18.50.48.png

やっぱり汚くなる。 1 は結果的にこれと同じことをしているのであろう。

2-3. 若干の padding を入れる(現状一番キレイ)

画像を若干内側に引っ込ませればいいんじゃないの? という発想で padding を加えてみる。

    return Container(
      width: 200,
      height: 200,
      foregroundDecoration: BoxDecoration(
        border: Border.all(color: Colors.white, width: 3),
        borderRadius: BorderRadius.circular(10),
      ),
      // 魔法の padding
      padding: const EdgeInsets.all(0.5),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(10),
        clipBehavior: Clip.hardEdge,
        child: Image.network('https://i.picsum.photos/id/563/200/200.jpg'),
      ),
    );

結果↓
スクリーンショット 2020-02-13 19.03.19.png
スクリーンショット 2020-02-13 19.03.19.png

うまくいった!
うまくいった……けどさ……うーん。

他にきれいなやり方が見つからなかったら後で Issue に投げてみる。

補足: わかりやすいように border width: 3 にしてるけど、↑のやり方は width: 1 でも一応キレイに表示できる。
補足2: ClipRRect の clipBehavior: Clip.hardEdge は単に処理速度をちょっとでも上げたいという思いで設定している。デフォルトの antialias にしていても、 padding 入れないとやっぱりキレイにはならない。

13
8
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
13
8