경로를 따라 그리는 Path Animation
05 Aug 2019 | Android먼저 View를 상속받는 캔버스(Canvas)를 가진 클래스를 하나 구현합니다. 그리고 setPercentage 메소드를 만들어줍니다.
클래스 외부에서 애니메이션을 동작시킬 때 필요한 progress 관련 메소드입니다.
class PathView(context: Context, attrs: AttributeSet) : View(context, attrs) {
companion object {
private const val CORNER_ROUND = 40F
}
private val wayPointList = ArrayList<PointF>()
private val paint = Paint()
private var progress = 0F
private var pathLength = 0F
init {
paint.apply {
color = context.getColor(R.color.path_color)
style = Paint.Style.STROKE
isAntiAlias = true
strokeWidth = 8.0F
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
initDummyData()
}
private fun initDummyData() {
wayPointList.add(PointF(190F, 1715F))
wayPointList.add(PointF(270F, 1715F))
wayPointList.add(PointF(270F, 650F))
wayPointList.add(PointF(460F, 650F))
wayPointList.add(PointF(460F, 500F))
}
fun setPath(pointList: ArrayList<Point>) {
wayPointList.clear()
for (p in pointList) {
val x = MapCoordinateConverter.getCanvasXFromWorldX(p.x).toFloat()
val y = MapCoordinateConverter.getCanvasXFromWorldX(p.y).toFloat()
wayPointList.add(PointF(x, y))
}
invalidate()
}
fun setPercentage(percentage: Float) {
if (percentage < 0.0f || percentage > 1.0f) {
throw IllegalArgumentException("setPercentage not between 0.0f and 1.0f")
}
progress = percentage
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
drawPath(canvas)
}
private fun drawPath(canvas: Canvas?) {
val p = createPath()
val measure = PathMeasure(p, false)
pathLength = measure.length
val total = pathLength - pathLength * progress
val pathEffect = DashPathEffect(floatArrayOf(pathLength, pathLength), total)
val cornerPathEffect = CornerPathEffect(CORNER_ROUND)
paint.pathEffect = ComposePathEffect(cornerPathEffect, pathEffect)
canvas?.drawPath(p, paint)
}
private fun createPath(): Path {
val p = Path()
if(wayPointList.size > 0) {
p.moveTo(wayPointList[0].x, wayPointList[0].y)
for (pf in wayPointList) {
p.lineTo(pf.x, pf.y)
}
}
return p
}
}
위에서 만든 클래스를 외부에서 사용할 때는 다음과 같이 작성하면 됩니다.
class MapView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
private val pathView = PathView(context, attrs)
init {
val layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
addView(pathView, layoutParams)
}
fun start() {
playPathAnimation(pathView)
}
fun setPath(pointList: ArrayList<Point>) {
pathView.setPath(pointList)
}
private fun playPathAnimation(target: View) {
val anim = ObjectAnimator.ofFloat(target, "percentage", 0.0f, 1.0f)
anim.duration = 3000
anim.interpolator = LinearInterpolator()
anim.start()
}
}