😇

FlutterでSwiftUIのような class modifier再現できるのか?

2024/07/04に公開

Tips💡

結論できるしかしあっているのか...
実験なので、これは使い道あるのか???

昔からある方法でできるらしい?

extension WidgetModifier on Widget {
  Widget padding(double value) {
    return Padding(
      padding: EdgeInsets.all(value),
      child: this,
    );
  }

  Widget background(Color color) {
    return Container(
      color: color,
      child: this,
    );
  }

  Widget alignment(Alignment alignment) {
    return Align(
      alignment: alignment,
      child: this,
    );
  }
}

思いつきで書いたコード

// enum & typedef
enum BoxStyle {
  rounded,
  shadow,
}

typedef ApplyBoxStyle = Widget Function(Widget);


extension WidgetModifiers on Widget {

  Widget applyStyle(BoxStyle style) {
    switch (style) {
      case BoxStyle.rounded:
        return borderRadius(10.0);
      case BoxStyle.shadow:
        return boxShadow();
    }
  }

  Widget borderRadius(double radius) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(radius),
      child: this,
    );
  }

  Widget boxShadow() {
    return Container(
      decoration: BoxDecoration(
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            spreadRadius: 1,
            blurRadius: 10,
          ),
        ],
      ),
      child: this,
    );
  }
}

Dart3.0のextetion typeを使うと、onがいらないらしい?

extension type ClassModifier(Widget widget) {
  Widget padding(double value) {
    return Padding(
      padding: EdgeInsets.all(value),
      child: widget,
    );
  }

  Widget background(Color color) {
    return Container(
      color: color,
      child: widget,
    );
  }

  Widget alignment(Alignment alignment) {
    return Align(
      alignment: alignment,
      child: widget,
    );
  }
}

使うときは、.で繋げて使う。 SwiftUIぽくはなってはいる?

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Page'),
      ),
      body: Center(
        child: Column(
          children: [
            const Text('Hello, World!').padding(16).
            background(Colors.blue).
            alignment(Alignment.bottomLeft),
            // WidgetModifiersを使ってスタイルを適用
            const Text('enum typedef').
            padding(16).
            applyStyle(BoxStyle.rounded),
            // ClassModifierを使ってスタイルを適用
            const Text('extension type').padding(16).
            background(Colors.red).
            alignment(Alignment.topRight),
          ],
        ),
      ),
    );
  }
}

SwiftUIだとこのように書く。alignmentは適用されていないけど。

import SwiftUI

struct ShopModalView: View {
    var body: some View {
        VStack {
            Text("ffffff")
                .padding()
                .background(Color.red)
                .frame(alignment: .topLeading)
            Text("ffffff")
                .padding()
                .background(Color.blue)
                .frame(alignment: .topTrailing)
            Text("ffffff")
                .padding()
                .background(Color.green)
                .frame(alignment: .bottomLeading)
        }
    }
}

#Preview {
    ShopModalView()
}

感想

ネットで、FlutterでもSwiftUIのような、class modifierを真似した書き方をする人がいた。これでスタイルを適用すると、「何かメリットがあるのか?」わからないですね。コンポーネントを作るか、スタイルをドットで繋げて使えるようにした方が良いのか、探究してみないとわからない。

Discussion