Umi Uyuraのブログ

プログラミング関連の作業ログ

Titanium Alloy with StylusでFontを設定

Titanium™ Advent Calendar 2013の18日目です。

枠が開いているようだったので、僭越ながら2回目書かせていただきます。

私のAlloyでの開発スタイル

私が最近Titaniumに取り組むときは、@ryugoo_さんのこちらの記事を参考にさせていただきつつ、Alloy with Jade & Stylusで作っています。

この組み合わせだと、さらにCoffeeScriptを加えるというのが定番のようですが、私はJS歴が短いこともあり、まずは素のJSを理解せねばということで、まだ使っていません。

Alloy with Slylusの問題

さて、Jade & Stylusだけでも、UI周りのコーディングは非常にわかりやすくなるわけですが、1点だけ問題がありました。

それは、Stylusの中でFontの設定が書けない点です。

例えばLabelに対してfontSizeやfontWeightを設定したい場合、.tssであれば以下のように書くと思います。

"Label": {
  font: {
    fontSize: 20,
    fontWeight: "bold"
  }
}

これを、Stylusを使うので、

Label
  font
    fontSize 20
    fontWeight "bold"

のように書けば良いのかと思いきや、これをStylusに通すと、

"Label font": {
  fontSize: 20,
  fontWeight: "bold"
}

のようになってしまいます。

それもそのはずで、そもそもCSSは階層構造になることがないので、意図したような解釈をしてくれないということのようです。

改良記法で対応

そこで若干強引ですが、alloy.jmk内にてfont指定部分を書き換える処理を加える事で、fontの指定もできるようにしてみました。

前提として、解析を簡単にするために、fontへは以下の形式に指定することにします。

font <key> <value>, <key> <value>, ...

例えば、LabelにfontSizeのみ指定する場合、

Label
  font fontSize 24

例えば、fontSizeとfontWeightを指定する場合、

Label
  font fontSize 24, fontWeight "bold"

要するに、fontというキーに対して、指定するキーとバリューの組み合わせをカンマ区切りの値として指定するという感じです。

上記2種類を書いた.stylを通すと、それぞれ以下の様に.tssに出力されます。

"Label": {
  font: {
    fontSize:24
  }
}
"Label": {
  font: {
    fontSize:24,
    fontWeight:"bold"
  }
}

これで、font指定もStylusっぽく書けるようになります。

変更した部分は、Stylusのを解析してreturn tssしていた箇所で、さらに上記の改良記法を解析する処理を入れてみました。

  var compileTSS = function(root, target) {
    var data = fs.readFileSync(path.join(root, target), "utf8"),
        tss;

    styl.render(data, function(err, css) {
      css = css.replace(/;/gi, ",");
      css = css.replace(/\}/gi, "},");
      css = css.replace(/(.+?).?\{/gi, "\"$1\": {");
      css = css.replace(/,\n\},/gi, "\n\}");
      css = css.replace(/\}\n\"/gi, "\},\n\"");
      css = css.replace(/['"]expr(.+?)['"]/gi, "expr$1");
      css = css.replace(/['"]Ti(.+?)['"]/gi, "Ti$1");
      css = css.replace(/['"]Titanium(.+?)['"]/gi, "Titanium$1");
      css = css.replace(/['"]Alloy(.+?)['"]/gi, "Alloy$1");
      tss = css;
    });
    
    // return tss;

    var tss2 = [];
    tss.split("\n").forEach(function(line) {
      if (line.match(/font:/)) {
        var fontObj = RegExp.rightContext.replace(/(^\s+)|(\s+$)/g, "");
        var closeBrace = "  }";
        if (fontObj.match(/,$/)) {
          closeBrace = closeBrace + ",";
          fontObj = fontObj.replace(/,$/, "");
        }

        tss2.push("  font: {");
        var fontObjArray = fontObj.split(",");
        for (var i = 0; i < fontObjArray.length; i++) {
          var f = fontObjArray[i].replace(/(^\s+)|(\s+$)/g, "").replace(/ /, ":");
          if (1 < fontObjArray.length && i < (fontObjArray.length - 1)) {
            f = f + ",";
          }
          tss2.push("    " + f);
        }

        tss2.push(closeBrace);
      } else {
        tss2.push(line);
      }
    });

    return tss2.join("\n");
  }

上記対応部分を抽出したalloy.jmkとしては、以下の様な感じになります。

Alloy with StylusでFontも設定(改良記法)できるようにしたもの

もっとスマートに書けそうな気もしますが、とりあえず意図通りに動いたので、ひとまずそのままです。

あまり実戦投入していないので、不具合があるケースがあるかもしれませんので、そのときはそっと教えてください。

一応、これを使ったプロジェクトのサンプルとして、Titanium™ Advent Calendar 2013の3日目に掲載したumi-uyura/TiAnimateStudyでも使っています。

index.styl

TableViewを普通に使うと、iOSに比べてAndroidでは文字が小さ目になってしまうので、AndroidのみfontSizeを少し大きくする、という使い方をしています。

ということで、参考になれば幸いです。


明日は@dasa_101さんです。
よろしくお願いします!