Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

SwiftUI と Flutter を比較する

こんにちは。中山です。

先日開催された WWDC 2019 で発表されました「 SwiftUI 」。
その、コードで UI を構築していくスタイルが、「どこかで見たことある」と思ったら、そう、「 Flutter 」でした。
今回は、SwiftUI と Flutter のコードを比較して、その特徴を探ってみたいと思います。

Hello World 的な画面

SwiftUI の場合

Apple の Developer サイトに早速用意されていた、SwiftUI の チュートリアルページ を見てみますと、以下のような、Swift UI での、いわゆる「 Hello World 」的な画面は、

 f:id:IntelligentTechnology:20190612231648p:plain:w360

SwiftUI では、以下のように実装します。

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            Text("Joshua Tree National Park")
                .font(.subheadline)
        }
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Flutter の場合

これと同じような画面を Flutter で実装しますと、コードは以下のようになります。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter App Sample',
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                'Turtle Rock',
                style: Theme.of(context).textTheme.title
              ),
              Text(
                'Joshua Tree National Park',
                style: Theme.of(context).textTheme.subhead,
              ),
            ],
          ),
        ),
      )
    );
  }
}

この Flutter のコードで生成される画面は、以下のような感じ。

 f:id:IntelligentTechnology:20190607164608p:plain:w360
 

Flutter のほうが、コード記述量が多いかなー、というところですが、基本的な構成はそれほど違わない印象を受けました。
 

リストビュー画面

SwiftUI の場合

シンプルな静的データを持つリストビューは、SwiftUI の場合、以下のような画面で、

 f:id:IntelligentTechnology:20190612235402p:plain:w360

これは、SwiftUI では、たとえば以下のように実装します。

import SwiftUI

struct MyListItem: Identifiable {
    let id = UUID()
    let title: String
    let subtitle: String
}

let myListItems = [
    MyListItem(title: "item1", subtitle: "description1"),
    MyListItem(title: "item2", subtitle: "description2"),
    MyListItem(title: "item3", subtitle: "description3"),
    MyListItem(title: "item4", subtitle: "description4"),
    MyListItem(title: "item5", subtitle: "description5")
]

struct MyListItemRow: View {
    var myListItem: MyListItem
    
    var body: some View {
        HStack() {
            Spacer()
            VStack(alignment: .leading) {
                Spacer()
                Text(myListItem.title)
                    .font(.title)
                Text(myListItem.subtitle)
                    .font(.subheadline)
                Spacer()
            }
            Spacer()
        }.border(Color.gray, width: 2.0, cornerRadius: 8.0)
    }
}

struct MyListView: View {
    var body: some View {
        List(myListItems) { myListItem in 
            MyListItemRow(myListItem: myListItem)
        }
    }
}

struct MyListView_Preview: PreviewProvider {
    static var previews: some View {
        MyListView()
    }
}

Flutter の場合

Flutter の場合は、これと同じような画面を実装しますと、コードは以下のようになります。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Flutter App Sample';

    final listItems = [
      { 'title': 'item1', 'subtitle': 'description1' },
      { 'title': 'item2', 'subtitle': 'description2' },
      { 'title': 'item3', 'subtitle': 'description3' },
      { 'title': 'item4', 'subtitle': 'description4' },
      { 'title': 'item5', 'subtitle': 'description5' }
    ];

    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(''),
          backgroundColor: Colors.grey[200],
        ),
        body: ListView.builder(
          padding: const EdgeInsets.all(8.0),
          itemCount: listItems.length,
          itemBuilder: (BuildContext context, int index) {
            return Card(
              child: ListTile(
                title: Text(listItems[index]['title']),
                subtitle: Text(listItems[index]['subtitle'])
              ),
            );
          },
        ),
      )
    );
  }
}

この Flutter のコードで生成される画面は、以下のような感じ。

 f:id:IntelligentTechnology:20190613145220p:plain:w360
 

どちらもシンプルではありますが、個人的には、SwiftUI のほうが、とっつきやすいような印象があるかなぁ。
 

画面遷移

SwiftUI の場合

SwiftUI の、シンプルな画面遷移の仕組みは、

 f:id:IntelligentTechnology:20190612235824p:plain:w360
 f:id:IntelligentTechnology:20190612235843p:plain:w360

SwiftUI コードでは以下のように実装します。

import SwiftUI

struct FirstView: View {
    var body: some View {
        NavigationView {
            NavigationButton(destination: SecondView()) {
                Text("Show Second")
                    .font(.title)
            }
        }
    }
}

struct SecondView: View {
    var body: some View {
        Text("Second")
            .font(.title)
    }
}

struct FirstView_Preview: PreviewProvider {
    static var previews: some View {
        FirstView()
    }
}

Flutter の場合

Flutter の場合は、以下のようなコードになります。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Navigation Basics',
    home: FirstRoute(),
  ));
}

class FirstRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Show Second', style: Theme.of(context).textTheme.title),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondRoute()),
            );
          },
        ),
      ),
    );
  }
}

class SecondRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second"),
      ),
      body: Center(
        child: Text('Second', style: Theme.of(context).textTheme.title),
      ),
    );
  }
}

このときの Flutter のアプリの画面はこちら。

 f:id:IntelligentTechnology:20190612182945p:plain:w360
 f:id:IntelligentTechnology:20190612183005p:plain:w360
 

同じことをやってるんですが、SwiftUI のほうが、コードも洗練されてる印象かな。
 

まとめ

Flutter の登場により、UI をコードで書いていくスタイルが表舞台に現れたわけなのですが、正直なところ、Flutter がどの程度、開発現場に受け入れられているのか、というのが未知数であり、なかなか一歩を踏み出せずにいました。
しかし今回 SwiftUI がこのスタイルを踏襲した(ように見える)ことで、「今後はこの方向に進んでよいのだ」と、ある意味、背中を押してくれたような感じがしました。

今回は、シンプルな実装しか試していませんが、それでも、直感的に UI を実装できるこのスタイルは、非常に強力なツールになりうると感じました。