Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Flutterで湯婆婆を実装してみる

はじめに

実装

シンプルにStatefulWidgetでゴリゴリ書いてます。
1時間くらいで書けました。

ざつーにレスポンシブ対応版に差し替えました。(2020/11/12 追記)

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';

void main() {
  runApp(MyApp());
}

enum ScreenType { lg, sm }

ScreenType screenType(BuildContext context) {
  var width = MediaQuery.of(context).size.width;
  if (width > 768) {
    return ScreenType.lg;
  } else {
    return ScreenType.sm;
  }
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fu婆婆',
      theme: ThemeData(
        primarySwatch: Colors.brown,
      ),
      home: MyHomePage(title: 'Fu婆婆'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _yubabaText = "契約書だよ。\nそこに名前を書きな。";

  var _nameController = TextEditingController();

  String _zeitaku(String name) {
    if (name == null && name.isEmpty) {
      return "";
    }

    final rand = Random();
    int index = rand.nextInt(name.length);
    return name.substring(index, index + 1);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: <Widget>[
          Container(
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/chihiro016.jpg'),
                fit: BoxFit.cover,
              ),
            ),
          ),
          SingleChildScrollView(
            child: screenType(context) == ScreenType.sm
                ? Center(
                    child: Column(
                      children: [
                        _buildYubabaTextBox(context),
                        _buildContract(context),
                      ],
                    ),
                  )
                : Center(
                    child: Stack(
                      children: <Widget>[
                        Align(
                          alignment: Alignment.topLeft,
                          child: _buildYubabaTextBox(context),
                        ),
                        Align(
                          alignment: Alignment.bottomRight,
                          child: _buildContract(context),
                        ),
                      ],
                    ),
                  ),
          ),
        ],
      ),
    );
  }

  Widget _buildYubabaTextBox(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(30),
      padding: EdgeInsets.all(30),
      decoration: new BoxDecoration(
        color: Colors.white.withAlpha(200),
        borderRadius: BorderRadius.all(Radius.circular(10)),
        border: Border.all(color: Colors.black.withAlpha(200), width: 5),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            _yubabaText,
            softWrap: true,
            style: TextStyle(fontSize: 30),
          ),
        ],
      ),
    );
  }

  Widget _buildContract(BuildContext context) {
    return Container(
      width: 500,
      height: 400,
      margin: EdgeInsets.all(20),
      color: Color(0xffe3ab7a).withAlpha(220),
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Padding(
                padding: EdgeInsets.all(50),
                child: Text(
                  '契約書',
                  style: TextStyle(fontSize: 50),
                )),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                SizedBox(
                    width: 50,
                    child: Text(
                      '甲',
                      style: TextStyle(fontSize: 30),
                    )),
                SizedBox(
                  width: 300,
                  child: Text(
                    '油屋当主 湯婆婆',
                    style: TextStyle(fontSize: 30),
                  ),
                ),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                SizedBox(
                  width: 50,
                  child: Text(
                    '乙',
                    style: TextStyle(fontSize: 30),
                  ),
                ),
                SizedBox(
                    width: 300,
                    child: TextField(
                      controller: _nameController,
                      cursorColor: Colors.brown,
                      style: TextStyle(fontSize: 30),
                      maxLength: 30,
                      decoration: InputDecoration(
                        hintText: '名前を入力',
                      ),
                    )),
              ],
            ),
            Padding(
              padding: EdgeInsets.all(30),
              child: RaisedButton(
                child: Padding(
                  padding: EdgeInsets.all(5),
                  child: Text(
                    '契約',
                    style: TextStyle(fontSize: 30, color: Colors.red),
                  ),
                ),
                color: Color(0xffe3ab7a),
                shape: const OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(10)),
                  borderSide: BorderSide(color: Colors.red),
                ),
                onPressed: () {
                  var name = _nameController.text;
                  if (name == null || name.isEmpty) {
                    return;
                  }
                  var newName = _zeitaku(name);

                  setState(
                    () {
                      _yubabaText =
                          'フン。\n$nameというのかい。\n贅沢な名だねぇ。\n\今からお前の名前は$newNameだ。\nいいかい、$newNameだよ。\n分かったら返事をするんだ、$newName!!\n';
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

全コードはここ→GitHub

Hosting

今回は手軽に触ることができるようにWebアプリとしてビルドしFirebaseでHostingしました。
↓からどうぞ。
https://flutter-baba.web.app/#/

画面

image.png
image.png
※ 湯婆婆の画像はジブリ公式からお借りしています。(常識の範囲内だと思ってます・・・)

おわりに

今回、突発的にFlutterで実装してみました。
改めてですが、Flutterは素早くアプリが作れて良き良きの良きですね。
それと、私は普段Android系の開発をしているのですが、Flutter+Firebaseを活用すれば手軽にWebアプリを開発できるってのもありがたいです。
モバイルアプリだとこういうネタアプリのためだと配布がめんどいので。
Flutterやったことないって人はぜひ一度触ってみてください。

追記

simontanz
札幌でSEやってます。 業務のメインはAndroid系のJava。 最近FlutterとFirebase、オブジェクト指向UI設計とかを勉強中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away