Yukii

主にプログラミング(Flutter)についての記事を書いています。

XD to Flutterを使ってみる

本日はAdobeのCC道場を見て気になったので、XD to Flutter
xd.adobelanding.com
を使ってみました。
なんとAdobe XDからFlutterコードをエクスポートすることができるらしいです。

本日はプラグインのインストールと設定、使ってみた感じとこれからの勉強課題について書こうと思います。

使用方法

1. Flutter側の設定とXD側の設定

1-1. プロジェクトを作る

プロジェクトを作りたいディレクトリに行って

flutter create <project名>

完了したら

flutter run

で確認。
そうするといつものカウンターでもアプリができています。
f:id:muscle_girl:20200522160652p:plain:w200

1-2. adobe_xdパッケージの追加

adobe_xdパッケージを追加するためにpubspec.yamlに追記して

flutter pub get
1-3. XD to Flutterのインストール

XD -> プラグイン -> プラグインを見つける... から XD to Flutterを検索してインストール
f:id:muscle_girl:20200522161624p:plain

2. XD to Flutterの使いかた

2-1. UI Panelの使いかた

XD -> プラグイン -> UI Panelを選択して画面の左側にパネルを出す

2-2. Flutterプロジェクトと連携

左のパネルのFLUTTER PROJECTで 1. で作ったプロジェクトを選択する
f:id:muscle_girl:20200522162526p:plain

2-3. アートボードや要素を追加する

XD側でアートボードに名前をつけたり増やしたり、文字や図形を置いてみます。
このときボタンをイメージしてインタラクションも設定しました。
f:id:muscle_girl:20200522163505p:plain

2-4. Widgetをエクスポートする

2-3. でデザインしたものをコードにしたいので Export All Widgets を押します。このときインタラクションの設定も反映したいのでSETTINGで Prototype Interactions のチェックを入れてみました。

3. アプリの動作とコードのチェック

3-1. ファイルの生成

f:id:muscle_girl:20200522164518p:plain:w300
page1とpage2という名前でアートボードを作ったのでそのファイルが生成されているようです。

3-2. ホーム画面について

カウンターデモのままです。main.dartをみるとhomeはデフォルトのままで、page1クラスを呼び出すようになっていませんでした。何か設定が必要なのでしょうか。要確認です。

3-3. page1画面について

ホーム画面に特定のページを設定してエクスポートする方法がわからなかったので、手動で設定してスクリーンを見てみると、XDでデザインした通りの見た目になっていました!
f:id:muscle_girl:20200522165107p:plain:w200
しかし遷移ボタンのつもりで設定した長方形を押しても何も起こりません。
エクスポートしたコードを見てみると
f:id:muscle_girl:20200522165620p:plain:w200
PageLinkというクラス名がついています。
pub.dev
ここも確認したいと思います。

使用してみた感想

良かったところ

1. 初期設定が簡単(XD側のインストールとFlutter側のpackageのインストールのみで再起動等は必要なし)
2. デザインした見た目をそのままアプリで確認できる

わからなかったところ

1. ホームスクリーンの設定方法
2. ボタンをボタンと認識させる方法(RaisedButtonクラス等で書き出す方法や、押した時のアクションを設定する方法)
3. ヘッダー、フッターを設置する方法

脳動脈瘤のCT検査とその結果

二週間前に頭部CTを撮り、昨日その診断結果を聞いてきました。

 

まず、頭部CTを撮った感想から。

。。めっちゃ一瞬だった!

でも造影剤を右腕から入れた瞬間、なぜか股間が熱くなって漏らしたかと思いました(笑)

造影剤入れた手が痛いとか知人に聞いていたのですが、違和感等はありませんでした。

 

 

そして診断。

結論から言うと、

現時点で手術はしなくて良い!

とのことでした。

私の動脈瘤は目の裏にできており、大きさは3mm程度でした。

大きさや場所な形などを見て、すぐ手術というよりは経過観察をしていこうということになりました。

これからは半年毎に頭部CTを撮り、動脈瘤が成長してないか見守ることになります。

 

今後気をつけることについて。

今後は血圧の急上昇を避けるように言われました。

大好きなボディメイクについてですが、

ジムでトレーニングする前後に血圧を測ること。

無呼吸を避けること。具体的には高重量を扱ったり力んだりしないこと。

 

一年以内に動脈瘤が破裂する確率は1%に満たないですがゼロではないので、気をつけながら生活したいと思います。

FlutterでTextFormFieldの枠が表示されない時

今回は、下のスクリーンショットのようにフォームを表示したい時に調べたことを書こうと思います。
f:id:muscle_girl:20200313160816j:plain


やりたいこと
一行の中でテキストフォームの前後にテキストを配置したい。

試してダメだった方法
Rowの中にTextとTextFormFieldをそのまま配置する。

ダメだった理由
Rowの子要素は固有の長さを持っていなければいけません。
TextFieldは固有の値を持っていないためRowの中でうまくいかないというカラクリでした。


解決策
TextFormFieldをFlexibleまたはExpandedで囲んで、TextFormFieldの幅をRowに伝えてあげました。
ちなみに、
Expandedとは、Row(Column)の中のWidgetを固定の比率で配置するWidgetです。
Flexibleとは、Widgetに応じて柔軟に比率を変更した状態で,それぞれのWidgetを配置します。よってFlexibleを利用した場合,childの要素の幅に応じて柔軟に比率を変更して表示することになります。


参考資料はこちら
stackoverflow.com
qiita.com

コード
実際、上のスクリーンショットを表現するためのコードは以下になります。

Row(
        children: <Widget>[
          SizedBox(
            width: 80.0,
            child: Text(
              "年齢",
            ),
          ),
          Expanded(
            flex: 1,
            child: TextFormField(
                maxLines: 1,
                keyboardType: TextInputType.number,
                autofocus: false,
                decoration: InputDecoration(
                  hintText: 'Age',
                  border: OutlineInputBorder(
                    borderRadius: const BorderRadius.all(
                      const Radius.circular(0.0),
                    ),
                    borderSide: BorderSide(
                      width: 0.0,
                    ),
                  ),
                ),
                validator: (value) {
                 // validateの実装を書く
                },
                onSaved: (value) {
                 // saveした時実装したい関数を書く
                }),
          ),
          Padding(
            padding: EdgeInsets.only(left: 10),
          ),
          SizedBox(
            width: 20.0,
            child: Text(
              "歳",
            ),
          ),
        ],
      ),

Flutterでフッターにページナビを設置する

今回はフッターにページナビを設置してみたいと思います。((イメージ)スクショのピンク枠の部分)
f:id:muscle_girl:20200229085547p:plain

実装にはBottomNavigationBar Widgetを使いました。

今回は各ページごとにファイルが分かれている状況下で、下層ページでページナビを実装したいと思います。

 
1. 準備
main.dartにナビゲーションルートを設定しておきます。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'タイトル',
      home: FirstScreen(),
      routes: {
        '/screen1': (BuildContext context) =>
            FirstScreen(),
         '/screen2': (BuildContext context) =>
            SecondScreen(),
        '/screen3': (BuildContext context) =>
            ThirdScreen(),
      },
    );
  }
}

2. 下層ページにBottomNavigationBar Widgetを設置します。(抜粋)

class _SecondScreenState extends State<SecondScreen> {

 // ページ切り替え用のコントローラを定義
  PageController _pageController;
 // 現在のページインデックス
  int _currentIndex = 1; // 初期ページの指定。今回は2番目のページを初期表示にしたいので_currentIndexを1とする。
 // ナビゲーションの遷移先をリスト化
  List<String> _screen = ["/screen1", "/screen2", "/screen3"];

  // ページ下部に並べるナビゲーションメニューの一覧
  List<BottomNavigationBarItem> myBottomNavBarItems() {
    return [
      BottomNavigationBarItem(
        icon: Icon(Icons.person_outline),
        title: Text('Input Data'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.add_circle_outline),
        title: Text('Record'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.show_chart),
        title: Text('Chart'),
      ),
    ];
  }

  // ナビゲーションメニューがタップされた時の処理
  onTapFooterIcon(int index) {
    setState(() {
      _currentIndex = index;
    });
   // 遷移
    switch (index) {
      case 0:
        Navigator.of(context).pushNamed(_screen[0]);
        break;
      case 1:
        // 現在のページなので遷移しないようにコメントアウト
        // Navigator.of(context).pushNamed(_screen[1]);
        break;
      case 2:
        Navigator.of(context).pushNamed(_screen[2]);
        break;
    }
  }

  @override
  void initState() {
    super.initState();
    // コントローラ作成
    _pageController = PageController(
      initialPage:
          _currentIndex, 
    );
  }

  @override
  void dispose() {
    // コントローラ破棄
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'スクリーン2',
            ),
          ],
        ),
      ),
     // フッターナビゲーションメニュー
      bottomNavigationBar: BottomNavigationBar(
        // 現在のページインデックス
        currentIndex: _currentIndex,
        // ナビゲーションメニューがタップされた時の処理
        onTap: onTapFooterIcon,
        // ナビゲーションメニューのアイテムリスト
        items: myBottomNavBarItems(),
      ),
    );
  }
}


これでフッターに3ページ分のナビゲーションボタンが設置されました。

参考サイト
apps-gcp.com
flutter.keicode.com
www.virment.com
stackoverflow.com

Flutterでフッターにページナビを設置する

今回はフッターにページナビを設置してみたいと思います。(スクショのピンク枠の部分)

実装にはBottomNavigationBar Widgetを使いました。

今回は各ページごとにファイルが分かれている状況下で、下層ページでページナビを実装したいと思います。

 
1. 準備
main.dartにナビゲーションルートを設定しておきます。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'タイトル',
      home: FirstScreen(),
      routes: {
        '/screen1': (BuildContext context) =>
            FirstScreen(),
         '/screen2': (BuildContext context) =>
            SecondScreen(),
        '/screen3': (BuildContext context) =>
            ThirdScreen(),
      },
    );
  }
}

2. 下層ページにBottomNavigationBar Widgetを設置します。(抜粋)

class _SecondScreenState extends State<SecondScreen> {

// ページ切り替え用のコントローラを定義
  PageController _pageController;
// 現在のページインデックス
  int _currentIndex = 1; // 初期ページの指定。今回は2番目のページが初期表示したいので_currentIndexを1とする。
// ナビゲーションの遷移先をリスト化
  List<String> _screen = ["/screen1", "/screen2", "/screen3"];

  // ページ下部に並べるナビゲーションメニューの一覧
  List<BottomNavigationBarItem> myBottomNavBarItems() {
    return [
      BottomNavigationBarItem(
        icon: Icon(Icons.[アイコンの指定]),
        title: Text('[アイコンの下に表示されるタイトル]'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.[アイコンの指定]),
        title: Text('[アイコンの下に表示されるタイトル]'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.[アイコンの指定]),
        title: Text('[アイコンの下に表示されるタイトル]'),
      ),
    ];
  }

// ページ下部に並べるナビゲーションメニューの一覧
  List<BottomNavigationBarItem> myBottomNavBarItems() {
    return [
      BottomNavigationBarItem(
        icon: Icon(Icons.person_outline),
        title: Text('Input Data'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.add_circle_outline),
        title: Text('Record'),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.show_chart),
        title: Text('Chart'),
      ),
    ];
  }

  @override
  void initState() {
    super.initState();
    // コントローラ作成
    _pageController = PageController(
      initialPage:
          _currentIndex, 
    );
  }

  @override
  void dispose() {
    // コントローラ破棄
    _pageController.dispose();
    super.dispose();
  }

  onTapFooterIcon(int index) {
    setState(() {
      _currentIndex = index;
    });
   // 遷移
    switch (index) {
      case 0:
        Navigator.of(context).pushNamed(_screen[0]);
        break;
      case 1:
        // Navigator.of(context).pushNamed(_screen[1]);
        break;
      case 2:
        Navigator.of(context).pushNamed(_screen[2]);
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'スクリーン2',
            ),
          ],
        ),
      ),

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
      // ページ下部のナビゲーションメニュー
      bottomNavigationBar: BottomNavigationBar(
        // 現在のページインデックス
        currentIndex: _currentIndex,
        // onTapでナビゲーションメニューがタップされた時の処理を定義
        onTap: onTapFooterIcon,
        // 定義済のナビゲーションメニューのアイテムリスト
        items: myBottomNavBarItems(),
      ),
    );
  }
}

チューブメインの家トレメニュー

MRIで脳動脈瘤が見つかってから2週間弱。

大学病院で専門の先生に見てもらってから、今月末のCT検査までどう過ごしたらいいか模索しています。

 

先生からは

「血圧が急上昇したり、力むことは避けたい。

それ以外なら、普通の生活しててよいですよ。なんなら走ってもいいし。」

と言われました。

 

しかし、精密検査するまではやっぱり不安。

他の人のトレを見てると、高重量扱うときや追い込んでる時ってけっこう力んでそうと感じたし。ポージングもけっこう力いるし。。

 

そこで、精密検査して結果を聞くまでの一ヶ月半はジムを休会して、コンテスト出場も見送って、負荷をあまりかけないトレーニングを家ですることに。

筋量落としたくないけど、動脈瘤が万が一破裂したら終わりだし。。

 

最低、検査結果まではチューブやバンドを使った家トレメニューを組んでお家で筋トレします。

 

メニューはこちら。

 

5分割して毎日回します。

 

上記メニューを毎日やりつつ食事管理もして、ジムに復帰できた時にコンテストに程遠い身体に成り果てないように頑張りたいと思います。

 

 

アプリを作成途中でディレクトリ名等を変更したくなった。

現在、自主制作でiOSアプリをFlutterで作成しているのですが、なんというミス!

ディレクトリ等に使っているアプリ名をスペルミスしてました!

スペルミスは

に及んでいました。

 

ファイル名はすぐ直せます。
ファイル名を変更したらそのファイルを読み込んでいる部分(importの部分)を変更するだけ。

 

GitHubリポジトリ名も直せます。

  1. GitHubの対象のレポジトリを訪れて、Setting -> Repository nameの部分を変更
  2. 自分のローカルでFinderから対象ディレクトリ内の .git > configを開き
[remote "origin"]
    url = https://github.com/hisurga/[新しいリポジトリ名].git
    fetch = +refs/heads/*:refs/remotes/origin/*

参考記事はこちら
qiita.com


ファイル名はちょっと悩みました。
ファイル名を変更してそのままXcodeで実行しようとするとbuildに失敗します。
ターミナルで

flutter build ios

をしてからXcodeで実行しなおしたら上手くbuildできました。
その際、Xcodeのbundle identifierにスペルミスがあったので変更しときました(汗)。

参考記事はこちら
stackoverflow.com