【Flutter】Widgetを強調する

image

BackdropFilterを使えば、Widgetを暗くしたりぼかしたりする事ができます。
公式ドキュメントを読みながら簡単にハンズオンをしてみましょう!

BackdropFilter

BackdropFilterは、親Widgetに対してフィルターをかけた上から子Widgetを描画します。これ大事です。

準備

こちらのコードに対してBackdropFilterを使ってみましょう!

import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      home: MyApp(),
      debugShowCheckedModeBanner: false,
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.tealAccent,
      body: Center(
        child: Container(
          height: 600,
          width: 600,
          color: Colors.lightBlueAccent,
          child: Center(
            child: Container(
              height: 400,
              width: 400,
              decoration: const BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(
                      "https://www.kamo-it.org/_next/image?url=%2Fassets%2Fmember%2Ftaiga.jpg&w=3840&q=75"),
                  fit: BoxFit.cover,
                ),
              ),
              child: Center(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: const [
                    SearchField(),
                    SearchButton(),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class SearchButton extends StatelessWidget {
  const SearchButton({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Container(
      height: 45,
      width: 90,
      decoration: BoxDecoration(
        color: Colors.limeAccent,
        borderRadius: BorderRadius.circular(10),
      ),
      child: const Center(
        child: Text(
          "Search",
          style: TextStyle(
            fontSize: 20,
          ),
        ),
      ),
    );
  }
}

class SearchField extends StatelessWidget {
  const SearchField({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 45,
      decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(color: Colors.limeAccent),
          borderRadius: BorderRadius.circular(10)),
      child: Row(
        children: const [
          Padding(
            padding: EdgeInsets.all(8.0),
            child: SizedBox(
              height: 25,
              width: 25,
              child: Icon(Icons.search),
            ),
          ),
          Flexible(
            child: SizedBox(
              height: 30,
              width: 200,
              child: TextField(
                decoration: InputDecoration(
                  border: InputBorder.none,
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

初期状態ではこのような画面構成になります。
初期画面

Widgetをぼかす

公式ドキュメントでは、サンプルコードとしてWidgetをぼかす例が紹介されています。
それでは、例に沿って背景をぼかし、検索ボックスとボタンを強調してみましょう。

検索ボックスとボタンはRowの要素なので、 Rowを強調すれば良さそうです。

BackdropFilterは、親Widgetに対してフィルターをかけた上から子Widgetを描画します。

ということで、Rowの親要素にフィルターをかけ、その上からRowを描画してあげましょう。

では、RowをBackdropFilterでラップしてあげましょう。
公式ドキュメントの例の真似をして、filterにはImageFilter.blurを使います。

BackdropFilter(
  filter: ImageFilter.blur(
    sigmaX: 5.0,
    sigmaY: 5.0,
  ),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceAround,
    children: const [
      SearchField(),
      SearchButton(),
    ],
  ),
),

検索ボックスとボタンの強調
親階層のWidgetをぼかす事ができました。sigmaX, sigmaYをいじってみるとぼかし具合が変わります。

では、子階層のWidgetをぼかしたい場合はどうしたら良いでしょうか。
ドキュメントに聞いてみましょう。

If all you want to do is apply an ImageFilter to a single widget, use ImageFiltered instead.

そういう時はImageFilteredを使え、と言っています。

子Widgetをぼかす

ImageFilteredのドキュメントに目を通しつつ、使ってみましょう。

ImageFiltered(
  imageFilter: ImageFilter.blur(
    sigmaX: 2.0,
    sigmaY: 2.0,
  ),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceAround,
    children: const [
      SearchField(),
      SearchButton(),
    ],
  ),
),

ImageFilteredの例
子階層のWidgetをぼかすことができました!(ぐちゃぐちゃ)

これまで見てきた方法は、親以上の階層を全て、または子以下の階層を全てぼかすやり方です。

こうなると今度は任意の階層だけぼかす方法が気になります。 これもドキュメントに聞いてみると、

If the BackdropFilter needs to be applied to an area that exactly matches its child, wraps the BackdropFilter with a clip widget that clips exactly to that child.

Clip widgetとBackdropFilterで囲め、と言っています。実際にやってみましょう。

任意の階層だけぼかす

ここでは、分かりやすさのためfilterにColorFilterを使います。
詳しい説明は省きますが、今回の実装ではフィルターをかけた範囲が暗くなるようにしています。

Center(
  child: ClipRect(
    child: BackdropFilter(
      filter: const ColorFilter.mode(
        Colors.black54,
        BlendMode.darken,
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: const [
          SearchField(),
          SearchButton(),
        ],
      ),
    ),
  ),
),

Centerが暗くなる例
このようにClip WidgetでBackdropFilterを直接ラップすると、検索ボックスとボタンの隙間が暗くなっているのがわかると思います。
これは、Clip Widgetの親であるCenterの階層だけが暗くなっているということです。

このやり方ではClip Widgetの親階層以下、かつBackdropFilterの子階層より上の階層にフィルターがかかります。

では、画像全体が暗くなるようにしてみましょう。

ClipRect(
  child: Center(
    child: BackdropFilter(
      filter: const ColorFilter.mode(
        Colors.black54,
        BlendMode.darken,
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: const [
          SearchField(),
          SearchButton(),
        ],
      ),
    ),
  ),
),

画像が暗くなる例
Clip Widgetでラップする階層を一つ上げました。
これによって、ContainerからCenterまでの階層にフィルターがかかりました。
Clip Widgetの親からBackdropFilterの親まで、任意の階層にフィルターをかけられます。

まとめ

BackdropFilter, ImageFilteredを使ってWidgetをぼかしました。
特定のWidgetの親階層を全て、または子階層を全てぼかす方法と、任意の階層をぼかす方法を知りました。

おまけ

本記事ではあまり触れませんでしたが、ImageFilter, ColorFilterでは画像を反転させたり白黒にしたり、いろいろな事ができます。
勉強しておけば出来ることの幅が広がりそうです!

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More

タグ

Flutter (108)初心者向け (28)イベント (18)Google Apps Script (15)Nextjs (11)可茂IT塾 (8)Firebase (7)riverpod (6)React (6)ChatGPT (5)デザイン (5)新卒 (4)就活 (4)vscode (4)Figma (4)Dart (4)JavaScript (4)お知らせ (4)FlutterWeb (3)Prisma (3)NestJS (3)Slack (3)TypeScript (3)ワーケーション (3)インターン (3)設計 (2)線型計画法 (2)事例 (2)Git (2)Image (2)File (2)Material Design (2)画像 (2)iOS (2)アプリ開発 (2)React Hooks (2)tailwindcss (2)社会人 (2)大学生 (2)RSS (1)Google (1)Web (1)CodeRunner (1)個人開発 (1)Android (1)Unity (1)WebView (1)Twitter (1)フルリモート (1)TextScaler (1)textScaleFactor (1)学生向け (1)supabase (1)Java (1)Spring Boot (1)shell script (1)正規表現 (1)パワーポイント (1)趣味 (1)モンスターボール (1)CSS (1)SCSS (1)Cupertino (1)ListView (1)就活浪人 (1)既卒 (1)保守性 (1)iPad (1)シェアハウス (1)スクレイピング (1)PageView (1)画面遷移 (1)flutter_hooks (1)Gmail (1)GoogleWorkspace (1)ShaderMask (1)google map (1)Google Places API (1)GCPコンソール (1)Google_ML_Kit (1)Vercel (1)Google Domains (1)DeepLeaning (1)深層学習 (1)Google Colab (1)オンラインオフィス (1)オブジェクト指向 (1)クラスの継承 (1)ポリモーフィズム (1)LINE (1)Bitcoin (1)bitFlyer (1)コミュニティー (1)文系エンジニア (1)Freezed (1)permission_handler (1)flutter_local_notifications (1)markdown (1)GlobalKey (1)ValueKey (1)Key (1)アイコン (1)go_router (1)debug (1)datetime_picker (1)Apple Store Connect (1)FlutterGen (1)デバッグ (1)Widget Inspector (1)検索機能 (1)Shader (1)Navigator (1)メール送信 (1)Firebase App Distribution (1)Fastlane (1)Dio (1)CustomClipper (1)ClipPath (1)カスタム認証 (1)アニメーション (1)Arduino (1)ESP32 (1)経験談 (1)フリーランス (1)mac (1)csv (1)docker (1)GithubActions (1)Dialog (1)BI (1)LifeHack (1)ショートカット (1)Chrome (1)高校生 (1)キャリア教育 (1)非同期処理 (1)生体認証 (1)BackdropFilter (1)レビュー (1)getAuth (1)Algolia (1)コンサルティング (1)Symbol (1)

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More