LoginSignup
7
2

More than 1 year has passed since last update.

【Android】Canvas APIの使い方

Last updated at Posted at 2022-12-13

この記事はレコチョク Advent Calendar 2022の14日目の記事となります。

はじめに

はじめまして、秦基博さんと日向坂46さんに日々癒しと元気をいただいている休井です。
株式会社レコチョクでAndroidの開発をしています。

最近はJetpack Composeを使用してUI作成をすることが多いのですが、何となく難しそうで触れてこなかったCanvas APIについて、実際に使ってみながらご紹介したいと思います。

Canvas APIについて

Androidでは、Jetpack ComposeというUIツールキットが提供されており、宣言的にUIを作成することができます。
CanvasはそのJetpack Composeに含まれるAPIで、画面内の位置(座標)を用いてレイアウトの設定を行うことができるので、かなり自由度高くカスタムレイアウトを作成することができます。

基本的な使い方

線を引く

drawLine() を使用します。
startendで線の開始と終了を指定して線を引くことができます。

  @Composable
  fun DrawLine() {
      Canvas(
          modifier = Modifier
              .fillMaxSize()
      ) {
          val width = size.width
          val height = size.height
          drawLine(
              color = Color.Black,
              start = Offset.Zero,
              end = Offset(width, height),
              strokeWidth = 5F
          )
      }
  }

 

四角形を描く

drawRect()を使用します。
topLeftで描画位置を決め、sizeで大きさを指定して四角形を描くことができます。

    @Composable
    fun DrawRect() {
        Canvas(
            modifier = Modifier
                .fillMaxSize()
        ) {
            val width = size.width
            val height = size.height
            drawRect(
                color = Color.Black,
                topLeft = Offset(width / 3, height / 3),
                size = Size(width / 3, height / 3)
            )
        }
    }

 

角丸の四角形にしたい場合は、drawRoundRect()を使いcornerRadiusに丸の半径を設定します。

@Composable
fun DrawRoundRect() {
  Canvas(
      modifier = Modifier
          .fillMaxSize()
  ) {
      val width = size.width
      val height = size.height
      drawRoundRect(
          color = Color.Black,
          topLeft = Offset(width / 3, height / 3),
          size = Size(width / 3, height / 3),
          cornerRadius = CornerRadius(x = 100F, y = 100F)
      )
  }
}

円を描く

drawCircle()を使用します。
centerで描画位置を決め、radiusで半径を設定して円を描くことができます。

@Composable
fun DrawCircle() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val width = size.width
        val height = size.height
        drawCircle(
            color = Color.Black,
            radius = 400F,
            center = Offset(width / 2, height / 2)
        )
    }
}

 

また、楕円を描きたい場合は、drawOval()を使用します。
topLeftで描画位置を決め、sizeで大きさを設定して楕円を描くことができます。

@Composable
fun DrawOval() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val width = size.width
        val height = size.height
        drawOval(
            color = Color.Black,
            topLeft = Offset(width / 4, height / 3),
            size = Size(width = width / 2, height = height / 5)
        )
    }
}

弧を描く

drawArc()を使用します。
startAngleで開始位置(0Fが3時の方向)を決め、sweepAngleで弧の角度を設定して弧を描くことができます。
また、useCentertrueにすると、扇型に描画することができます。

@Composable
fun DrawArc() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val width = size.width
        drawArc(
            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で点の形を設定できます。

@Composable
fun DrawPoints() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val height = size.height
        drawPoints(
            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に色を付けることができます。

@Composable
fun DrawPath() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val width = size.width
        val height = size.height
        val 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で作って比較する となります。お楽しみに!

この記事はレコチョクのエンジニアブログの記事を転載したものとなります。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2