2021年5月9日日曜日

Jetpack Compose : Canvas Composable を使う

View の onDraw() で描画して Custom View を作る、というのを Compose でやりたいときは Canvas Composable を使います。

Canvas に渡す onDraw lamnda は Receiver が DrawScope になっています。
DrawScope からは描画エリアの大きさとして size: Size が取れます。

また、DrawScope は Density を継承しているので、Dp.toPx() とかも呼び出せます。
  1. @Composable  
  2. fun CircleProgress(  
  3.     progress: Int,  
  4.     modifier: Modifier,  
  5.     colorProgress: Color = MaterialTheme.colors.primary,  
  6.     colorBackground: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f)  
  7.         .compositeOver(MaterialTheme.colors.surface),  
  8.     strokeWidth: Dp = 8.dp,  
  9. ) {  
  10.     Canvas(modifier = modifier) {  
  11.         val stroke = Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Round)  
  12.   
  13.         val diameter = min(size.width, size.height) - stroke.width  
  14.         val topLeft = Offset((size.width - diameter) / 2, (size.height - diameter) / 2)  
  15.         val circleSize = Size(diameter, diameter)  
  16.   
  17.         drawArc(  
  18.             color = colorBackground,  
  19.             startAngle = -90f,  
  20.             sweepAngle = 360f,  
  21.             useCenter = false,  
  22.             style = stroke,  
  23.             topLeft = topLeft,  
  24.             size = circleSize,  
  25.         )  
  26.   
  27.         drawArc(  
  28.             color = colorProgress,  
  29.             startAngle = -90f,  
  30.             sweepAngle = 360f / 100 * progress,  
  31.             useCenter = false,  
  32.             style = stroke,  
  33.             topLeft = topLeft,  
  34.             size = circleSize,  
  35.         )  
  36.     }  
  37. }  
  38.   
  39. @Preview  
  40. @Composable  
  41. fun CircleProgressPreview() {  
  42.     var progress by remember { mutableStateOf(0) }  
  43.     val animateProgress by animateIntAsState(targetValue = progress, animationSpec = tween())  
  44.   
  45.     Column(  
  46.         horizontalAlignment = Alignment.CenterHorizontally,  
  47.         modifier = Modifier.padding(16.dp)  
  48.     ) {  
  49.         Button(onClick = {  
  50.             progress = Random.nextInt(0101)  
  51.         }) {  
  52.             Text("Change Progress")  
  53.         }  
  54.   
  55.         Spacer(modifier = Modifier.height(16.dp))  
  56.   
  57.         CircleProgress(  
  58.             progress = animateProgress,  
  59.             modifier = Modifier.size(120.dp)  
  60.         )  
  61.     }  
  62. }  
animate**AsState などでアニメーションも簡単にできます。



0 件のコメント:

コメントを投稿