この記事はレコチョク Advent Calendar 2022の14日目の記事となります。
はじめに
はじめまして、秦基博さんと日向坂46さんに日々癒しと元気をいただいている休井です。
株式会社レコチョクでAndroidの開発をしています。
最近はJetpack Composeを使用してUI作成をすることが多いのですが、何となく難しそうで触れてこなかったCanvas APIについて、実際に使ってみながらご紹介したいと思います。
Canvas APIについて
Androidでは、Jetpack ComposeというUIツールキットが提供されており、宣言的にUIを作成することができます。
CanvasはそのJetpack Composeに含まれるAPIで、画面内の位置(座標)を用いてレイアウトの設定を行うことができるので、かなり自由度高くカスタムレイアウトを作成することができます。
基本的な使い方
- 線を引く
drawLine() を使用します。
startと endで線の開始と終了を指定して線を引くことができます。@Composablefun DrawLine() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightdrawLine(color = Color.Black,start = Offset.Zero,end = Offset(width, height),strokeWidth = 5F)}}
-
四角形を描く
drawRect()を使用します。
topLeftで描画位置を決め、 sizeで大きさを指定して四角形を描くことができます。@Composablefun DrawRect() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightdrawRect(color = Color.Black,topLeft = Offset(width / 3, height / 3),size = Size(width / 3, height / 3))}}角丸の四角形にしたい場合は、 drawRoundRect()を使い cornerRadiusに丸の半径を設定します。
@Composablefun DrawRoundRect() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightdrawRoundRect(color = Color.Black,topLeft = Offset(width / 3, height / 3),size = Size(width / 3, height / 3),cornerRadius = CornerRadius(x = 100F, y = 100F))}}
-
円を描く
drawCircle()を使用します。
centerで描画位置を決め、 radiusで半径を設定して円を描くことができます。@Composablefun DrawCircle() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightdrawCircle(color = Color.Black,radius = 400F,center = Offset(width / 2, height / 2))}}また、楕円を描きたい場合は、 drawOval()を使用します。
topLeftで描画位置を決め、 sizeで大きさを設定して楕円を描くことができます。@Composablefun DrawOval() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightdrawOval(color = Color.Black,topLeft = Offset(width / 4, height / 3),size = Size(width = width / 2, height = height / 5))}}
-
弧を描く
drawArc()を使用します。
startAngleで開始位置( 0Fが3時の方向)を決め、 sweepAngleで弧の角度を設定して弧を描くことができます。
また、 useCenterを trueにすると、扇型に描画することができます。@Composablefun DrawArc() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthdrawArc(color = Color.Black,startAngle = 0F,sweepAngle = 90F,useCenter = true,size = Size(width = width / 2, height = width / 2))drawArc(color = Color.Black,startAngle = 0F,sweepAngle = 90F,useCenter = false,size = Size(width = width / 2, height = width / 2),style = Stroke(width = 5F),topLeft = Offset(0F, width / 2))}}
-
点を描く
drawPoints()を使用します。
pointsで描きたい点の位置をリストで指定して点を描くことができます。
また、 pointModeで描き方、 capで点の形を設定できます。@Composablefun DrawPoints() {Canvas(modifier = Modifier.fillMaxSize()) {val height = size.heightdrawPoints(points = listOf(Offset(300F, height / 2),Offset(500F, height / 2),Offset(700F, height / 2),Offset(900F, height / 2),Offset(1100F, height / 2),),pointMode = PointMode.Points,color = Color.Black,strokeWidth = 50F,cap = StrokeCap.Square)}}
-
パスを決めて描く
drawPath()を使用します。
pathを作成し drawPath()に渡すことで、作成した pathに色を付けることができます。@Composablefun DrawPath() {Canvas(modifier = Modifier.fillMaxSize()) {val width = size.widthval height = size.heightval path = Path()path.moveTo(width / 2, height / 3) // pathの開始位置path.lineTo(width / 2, height / 2) // 開始位置→(width / 2, height / 2)path.lineTo(width, height / 3) // (width / 2, height / 2)→(width, height / 3)drawPath(path = path,color = Color.Black)}}
使ってみた
Canvasでできることと使い方の基本について確認できたので、単純なアナログ時計のレイアウトを描いてみました。
@Composable fun Clock() { Canvas ( modifier = Modifier .size(360.dp) ) { drawCircle( color = Color.Black, radius = 180.dp.toPx(), center = center, style = Stroke(width = 3.dp.toPx()) ) drawPoints( points = listOf( center, Offset(180.dp.toPx(), 12.dp.toPx()), Offset(264.dp.toPx(), 35.dp.toPx()), Offset(325.dp.toPx(), 97.dp.toPx()), Offset(348.dp.toPx(), 180.dp.toPx()), Offset(325.dp.toPx(), 263.dp.toPx()), Offset(264.dp.toPx(), 325.dp.toPx()), Offset(180.dp.toPx(), 348.dp.toPx()), Offset(96.dp.toPx(), 325.dp.toPx()), Offset(35.dp.toPx(), 263.dp.toPx()), Offset(12.dp.toPx(), 180.dp.toPx()), Offset(35.dp.toPx(), 97.dp.toPx()), Offset(96.dp.toPx(), 35.dp.toPx()), ), pointMode = PointMode.Points, color = Color.Black, cap = StrokeCap.Square, strokeWidth = 5.dp.toPx() ) drawLine( color = Color.Black, start = center, end = Offset(center.x, 40.dp.toPx()), strokeWidth = 5.dp.toPx() ) drawLine( color = Color.Black, start = center, end = Offset(center.x + 100.dp.toPx(), center.y), strokeWidth = 5.dp.toPx() ) } } |
centerでCanvasの中心のOffsetを取得したり、 dp.toPx()でDpからピクセルへの変換をしたりもできるので、機種によってレイアウトが崩れるという心配も少なそうですね。
おわりに
今回はJetpack ComposeのCanvas APIの使い方についてご紹介しました。
私自身今回でほぼ初めて触れましたが、シンプルなレイアウトであればさほど難しくなく作れそうです。
アニメーションをつけたり、テキストを入れたりすることもできるようなので、今後勉強して使いこなせるようになりたいと思います。
最後まで読んでいただきありがとうございました。
明日のレコチョク Advent Calendar 2022は15日目 シンプルな掲示板を素のPHPとCakePHPで作って比較する となります。お楽しみに!