何の記事か
私が運用している、Flutterで点線の描画を簡単に行えるようにするパッケージdotted_lineに、グラデーションで点線を描画できる機能を追加しました。
この記事では、点線にグラデーションを付ける機能をどのように実現したかをご紹介します。
何故作ったのか
きっかけはコントリビューターが挙げてくださったIssueでした。
「グラデーションを追加したらもっと良くなるよ」との提案に賛同して開発に取り組み始めました。
どう実現したか
グラデーションといえば、最初に描画された色から徐々に別の色に変化していくものを想像すると思います。
これをRGBA値に当てはめると、始点のRGBA値と終点のそれとの差分を割り出し、その差分を点線の数で割った値が点線の点1つ単位の変化量と捉えらることができます。
その変化量分だけ各点ごとのRGBA値を増加させていけば、点線でグラデーションを描画できるというわけです。
例)255個の点で描画される点線において、白(R:255, G:255, B:255)から黒(R:0, G:0, B:0)に向かってグラデーションする場合
以下は、RGBそれぞれで共通
255(始点) - 0(終点) = 255(差分)
255(差分) / 255(点の数) = 1(点1つ単位の変化量)
これをコードに落とし込むとこうなります。
// 各点に設定する色を算出するメソッド。
// List.generateメソッドのgenerator内で呼ばれて、各点のindexが受け取れる前提
Color _calculateGradientColor(
Color startColor,
Color endColor,
int maxItemCount,
int index,
) {
// RGBAごとに始点と終点の差分を算出
var diffAlpha = (endColor.alpha - startColor.alpha);
var diffRed = (endColor.red - startColor.red);
var diffGreen = (endColor.green - startColor.green);
var diffBlue = (endColor.blue - startColor.blue);
// RGBAごとに点1つ単位の変化量を算出
var amountOfChangeInAlphaPerItem = diffAlpha ~/ maxItemCount;
var amountOfChangeInRedPerItem = diffRed ~/ maxItemCount;
var amountOfChangeInGreenPerItem = diffGreen ~/ maxItemCount;
var amountOfChangeInBluePerItem = diffBlue ~/ maxItemCount;
// 始点の色に対して点の数だけ変化量を上乗せした色を返却
return startColor
.withAlpha(startColor.alpha + amountOfChangeInAlphaPerItem * index)
.withRed(startColor.red + amountOfChangeInRedPerItem * index)
.withGreen(startColor.green + amountOfChangeInGreenPerItem * index)
.withBlue(startColor.blue + amountOfChangeInBluePerItem * index);
}
これにより、下の画像のようなグラデーションが実現できました。
1個目は赤から青にグラデーションさせていて、2個目は赤と青の点線のアルファ値をグラデーションさせています。
余談
前述のコードのメソッド名を見ていただくと分かるのですが、今回はこの機能のメソッド名やプロパティ名をgradientとしています。
後から知ったのですが、英語のグラディエント(gradient)とグラデーション(gradation)は厳密には別の意味らしく、グラディエントは勾配でグラデーションは段階的な変化だそうです。
つまり、今回の実装は厳密にいうとgradationに当たりそうです。
