경로를 따라 그리는 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() } }