Flutterで1文字目だけスタイルを変える
Text.rich
とTextSpan
を使う。TextSpanで設定したstyleはchildrenに引き継がれるので、childrenのTextSpanで上書きする。
final String text = "Flutter";
Text.rich( TextSpan( text: text.substring(0, 1), style: TextStyle( fontSize: 36, color: Colors.blue, letterSpacing: 1, ), children: <TextSpan>[ TextSpan( text: text.substring(1), style: TextStyle( fontSize: 18, color: Colors.black87, ), ), ], ), ),
Flutter for Webで404ページを表示させる
MaterialAppのonGenerateRouteプロパティを使うとURL直打ちでも指定のページを表示させられる。同様に未定義のURLが指定された場合に呼ばれるonUnknownRouteを使えばOK。
class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), onGenerateRoute: (settings) { switch (settings.name) { case '/': return MaterialPageRoute( builder: (context) => MyHomePage(), ); } }, initialRoute: '/', onUnknownRoute: (RouteSettings settings) { return MaterialPageRoute( builder: (context) => MyNotFoundPage(), ); }, ); } }
ルーティングの処理順序はこのへんを参照。
# flutter/lib/src/material/app.dart#L57 /// The [MaterialApp] configures the top-level [Navigator] to search for routes /// in the following order: /// /// 1. For the `/` route, the [home] property, if non-null, is used. /// /// 2. Otherwise, the [routes] table is used, if it has an entry for the route. /// /// 3. Otherwise, [onGenerateRoute] is called, if provided. It should return a /// non-null value for any _valid_ route not handled by [home] and [routes]. /// /// 4. Finally if all else fails [onUnknownRoute] is called.
FlutterでAppBarを透過する
AppBarのbackgroundColorを透明にしただけだとAppBarは透明にならない。
ScaffoldのextendBodyBehindAppBarプロパティにtrueを設定すればOK。
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), backgroundColor: Colors.white.withOpacity(0.5), ), extendBodyBehindAppBar: true, body: ListView.builder( padding: const EdgeInsets.all(24), itemCount: 1, itemBuilder: (BuildContext context, int index) { return Container( height: 1000, color: Colors.blue, ); }, ), ); } }
ちなみに、scaffoldの仕様で、extendBodyBehindAppBarがtrueかfalseかでpaddingのtopが変わる。
// flutter/lib/src/material/scaffold.dart#L366 final double top = extendBodyBehindAppBar ? math.max(metrics.padding.top, bodyConstraints.appBarHeight) : metrics.padding.top;
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/scaffold.dart#L366
Flutter for Webで突然main.ddc.dill作成エラーが起きてビルドできなくなった
現象
flutter run -d chrome
実行時、見たことのない怖いエラーが突然発生するように...。
Error creating <project_name>|lib/main.ddc.dill Error creating kernel summary for module:<project_name>|lib/main.ddc.dill
解決
PCを再起動したあと普通に flutter run -d chrome
を実行すると、以下の情報を吐きながらビルドに成功した。
$ flutter run -d chrome Launching lib/main.dart on Chrome in debug mode... Throwing away cached asset graph because the build phases have changed. This most commonly would happen as a result of adding a new dependency or updating your dependencies. Building application for the web...
坂道グループの中からもうすぐ誕生日を迎えるメンバーを教えてくれるLINE Clovaスキルをつくった
『さかたん』というLINE Clovaスキルをだいぶ前に公開しました。
さかたんは、乃木坂46、欅坂46、日向坂46のメンバーの中で、次に誕生日を迎えるメンバーを教えてくれます。
※noteに書いた記事の移植 坂道グループの中からもうすぐ誕生日を迎えるメンバーを教えてくれるLINE Clovaスキルをつくった|あぼぼ|note
使い方
😲「ねぇClova、さかたんを起動して」 🤖「グループ名か、坂道と言ってください」 😲「乃木坂」 🤖「8月20日に、乃木坂の秋元真夏さんが26歳、乃木坂の白石麻衣さんが27歳を迎えます。」
グループ名は「坂」を省略することが可能です。グループを絞らない場合は「全部」とか「坂道」と言ってください。該当するメンバーが複数いる場合は↑のように全員喋ります。
あとは、当日なら
🤖「本日8月10日に、乃木坂の齋藤飛鳥さんが21歳になりました。」
と喋ります。
つくった理由
・特定のメンバーの誕生日ならググればすぐ知れるけど、つぎ誰が何歳になるかはすぐにはわからないなーと思ったから ・Clovaスキル(と乃木坂46が昔コラボしてたので)つくりたかった
技術について
言語はSwiftを使いました。LINEがSwift用のSDKを用意してくれてるのと、ぼくが一番書き慣れている言語なので。Swift以外にNode.jsとかPythonとかKotlinとかgoもありますよ👶
あとは動かすためにDockerとHerokuを使いました。SDKに組み込まれてるので、楽チン!Herokuのssl対応は別途必要です。
Swiftは型名や変数名に日本語が使えます。
enum 坂道: String { case 乃木坂 = "のぎざか" case 欅坂 = "けやきざか" case 日向坂 = "ひなたざか" } struct Member { let name: String let kana: String let birthday: Date let group: 坂道 }
今回一番時間がかかったところは、メンバーのデータを作るところですかね。欅坂46のサイトはコピペできないようになってて大変でした🙄
// MARK: - 乃木坂46 let nogizakaMembers: [Member] = [ // MARK: 1期生 Member("秋元 真夏", "あきもと まなつ", "1993年8月20日", .乃木坂), Member("生田 絵梨花", "いくた えりか", "1997年1月22日", .乃木坂), Member("井上 小百合", "いのうえ さゆり", "1994年12月14日", .乃木坂), Member("齋藤 飛鳥", "さいとう あすか", "1998年8月10日", .乃木坂), ... ]
ほかには、ローカルとheroku上とでタイムゾーンが違うことによるDateFormatterの扱いとかは少し悩みました。
そしてClovaの発話のための処理と、汎用的な坂道グループのデータを分離したので、今後何かしらに応用できるかもしれないし、できないかもしれません。
Clovaスキルの審査について
LINE Clovaスキルストアに自作スキルを公開するには、LINEによる審査に合格する必要があります。さかたんは1回落ちました。
指摘箇所は6箇所で、パッと見結構多いな・・・と思ったんですが、指摘理由が明確で、且つ修正例も載せてくれたりと、どう直せば良いか分かりやすくて助かりました。
審査のスピード感ですが、さかたんの場合、初回の審査結果は申請してから38時間後、2回目は40時間後に返ってきました。つまりそれぞれ2営業日内で審査していただきました。
Clova Developer Centerでスキルごとに統計も見れます。今回の審査員はClova DeskとClova Friends miniの2台でテストしてた、というのがログ見ると分かったりします。
今後の懸念
メンバーが卒業するたびに泣きながらメンテする必要があり、メンタルがもつか心配です。
メンバーの更新だけならLINEの再審査なしで行えるので
『10歳でもわかる問題解決の授業』を読んで
解決策に急がない、というのは大事だな〜。
問題解決の意識を変えること
- 問題解決を一発ですますことは不可能であるということを理解する
- 問題解決はサイクルである。一度意思決定してそれで終わりではない
- テストは複数の選択肢があれば、その中に必ず「正解」がある。実際の問題には、いくら案があろうがその中に"最高の"効果をあげるものがあるという確信は誰も持てない。「この選択肢はこういう効果があった」という実験結果に価値がある
現象ではなく論点を考える
- 現象は表立って目に見えている問題、論点は問題解決に繋がる打ち手を導くもの
- 「算数の成績が良くない」は現象、「計算ミスが多い」「割合の理解不足による間違いが多い」「一度解いたことのある問題が定着していない」は論点
- 「解決策」に急ぐのではなく、「問題設定」を疑ってみること。正しい問題=論点が設定されていないと効果的な打ち手に繋がらない
感想
決定することが苦手だけど、繰り返すことを前提に意思決定を怖がらないようにしていきたい。それから筋のいい仮説をたてたり、検証結果を正しく読み解くために、「解決」を急がないようにしたい。
『ライト、ついてますか』を読んだ
人生や仕事は「問題」の連続です。この本には、問題をどう発見するのか、どう定義するのか、どう解決するのかについてのヒントがたくさん詰まっているなーと思いました。
この本にはこれらの「標語」のようなものがいくつも出てきます。
問題によっては、それを認識するところが一番むずかしいということもある(p55)
結論に飛びつくな、だが第一印象を無視するな(p62)
他人が自分の問題を自分で完全に解けるときに、それを解いてやろうとするな(p89)
もし人々の頭の中のライトがついているなら、ちょっと思い出させてやる方がごちゃごちゃいうより有効なのだ(p104)
この標語だけを見ていくのでも楽しめるのですが、この本では各章、各部がそれぞれケーススタディのようになっていて、その中身こそが重要です。
- 「誰の問題か?」
- 「問題は何か?」
- 「この問題はどこからきたのか?」
という問いが、本全体で何度も繰り返されます。それゆえ重要な問いで、問題を正確に見極めるには不可欠な問いだと思います。
翻訳は少し読みづらいところもあったんですが、内容はよかったです。会社のCTOに教えてもらった本なので、CTOにお礼を言っとこうと思います。