Android 레이더 View 효과 구현 예시 코드

22869 단어 android레이더View
스타일 효과
  아니면 효과 부터 볼 까요?


  이것 은 모방 레이더 스캐닝 의 효과 로 이전에 지도 sdk 접속 을 할 때 부터 실현 하고 싶 었 던 효과 이다.그러나 그 전에 졸업 디자인 을 서 두 르 기 때문에 직접 실현 하지 못 했 지만 지금 은 스스로 발견 하 는 것 이 매우 간단 하 다.
  여 기 는 주로 나의 방법 을 공유 합 니 다.
목차
주체 윤곽 의 실현(레이더 의 구조)
애니메이션 의 실현(레이더 스캐닝 효과)
목표 점 의 가입(그림/점)
주체 윤곽 실현
  
  분석 하기 어렵 지 않 습 니 다.이 View 는 주로 외부의 원,중간의 닻 점 원 과 부채 형 회전 구역 으로 구성 되 어 있 습 니 다.그리고 각 부분 은 각 부분의 스타일 을 맞 추기 위해 서로 다른 Paint 로 그 려 야 한다.
  외부 원 과 닻 점 원 의 그리 기 는 비교적 간단 하 다.주요 한 점 은 전체 View 의 너비 와 높이 에 대해 일정한 제한 을 해 야 한다.예 를 들 어 너비 와 높이 가 같 아야 하고 특정한 모델 에서 작은 값 을 취해 전체 RadarView 의 최대 치 를 한정 해 야 한다.그렇다면 어떻게 통제 해 야 할 까?

onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
  View 를 계승 하기 때문에 onMeasure 방법 에서 우 리 는 두 개의 매개 변수 에 따라 Mode 를 얻 을 수 있 고 Mode 에 따라 너비/높이 에 대응 하 는 값 을 지정 한 다음 에 set Measured Dimension 을 통 해 컨트롤 주체 의 너비 와 높이 를 지정 하면 됩 니 다.

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec)
 val vWidth = measureDimension(widthMeasureSpec)
 val vHeight = measureDimension(heightMeasureSpec)
 val size = min(vWidth, vHeight)
 
 setMeasuredDimension(size, size)
}
 
private fun measureDimension(spec: Int) = when (MeasureSpec.getMode(spec)) {
 MeasureSpec.EXACTLY -> {
 // exactly number or match_parent
 MeasureSpec.getSize(spec)
 }
 MeasureSpec.AT_MOST -> {
 // wrap_content
 min(mDefaultSize, MeasureSpec.getSize(spec))
 }
 else -> {
 mDefaultSize
 }
}
  측량 작업 이 완성 되 었 으 니 우 리 는 당연히 가서 그 릴 수 있다.중간 에 있 는 작은 원 이 그렇게 튀 어 나 오지 않도록(크 거나 작 음)scale Factor 의 크기 조정 인 자 를 설정 하여 바깥 원 의 크기 에 따라 크기 를 조정 할 수 있 도록 합 니 다.

override fun onDraw(canvas: Canvas?) {
 super.onDraw(canvas)
 // draw outside circle (background)
 canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2, measuredWidth.toFloat() / 2, mOutlinePaint)
 if (mBorderWidth > 0F && mOutlinePaint.shader == null) {
  drawBorder(canvas)
 }
 
 // mOutlineRect = Rect(0, 0, measuredWidth, measuredHeight)
 canvas?.drawArc(mOutlineRect.toRectF(), mStartAngle, mSweepAngle, true, mSweepPaint)
 
 // draw center circle
 // scaleFactor = 30F
 canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2, measuredWidth.toFloat() / 2 / mScaleFactor, mPaint)
}
 
private fun drawBorder(canvas: Canvas?) {
 Log.i("RadarView", "drawBorder")
 mOutlinePaint.style = Paint.Style.STROKE
 mOutlinePaint.color = mBorderColor
 mOutlinePaint.strokeWidth = mBorderWidth
 canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2,
  (measuredWidth.toFloat() - mBorderWidth) / 2, mOutlinePaint)
 //   
 mOutlinePaint.style = Paint.Style.FILL_AND_STROKE
 mOutlinePaint.color = mBackgroundColor
}
  기준 원 을 그린 후 레이더 스캐닝 시 그 라 데 이 션 효 과 를 실현 하려 면 SweetGradient 를 통 해 조작 할 수 있 습 니 다.중심 점,그 라 데 이 션 색상,색상 분 포 를 지정 하여 그 라 데 이 션 스타일 을 맞 춥 니 다.기본 적 인 실시 간 으로 시작 할 때 gif 가 보 여 주 는 것 입 니 다.첫 번 째 상한 선 에서 부터 회전 하기 때문에 회전 하 는 출발점 을 matrix 를 통 해 시계 반대 방향 으로 90 도 회전 시 켜 얕 은 것 에서 깊 은 것 으로 들 어 가 는 효 과 를 얻는다.

private fun setShader(size: Int) {
 val shader = SweepGradient(size.toFloat() / 2, size.toFloat() / 2,
  mScanColors?: mDefaultScanColors, //    setScanColors()     
  floatArrayOf(0F, 0.5F, 1F)) //          
 val matrix = Matrix()
 //      90 
 matrix.setRotate(-90F, size.toFloat() / 2, size.toFloat() / 2)
 shader.setLocalMatrix(matrix)
 mSweepPaint.shader = shader
}
  여기 서 측정 과 그리 기 작업 을 마 쳤 습 니 다.그러면 우 리 는 레이아웃 에서 인용 한 후에 이런 효 과 를 볼 수 있 습 니 다.

  이때,우리 가 측정 할 때 너비 와 높이 의 최소 값 을 그 리 는 기준 크기 로 RadarView 를 주 었 기 때문에 measuredWidth 와 measuredHeight 는 같 지만 레이아웃 에 match 를 지정 하 였 습 니 다.parent 속성 입 니 다.그러면 실제 컨트롤 의 너비 가 높 습 니까?부모 레이아웃 과 일치 합 니까?높이 와 너비 가 설정 되 어 있 으 면 그 려 진 도형 은 왼쪽 에 있 습 니 다).일반적인 레이더 컨트롤 은 모두 가운데 에 표시 되 어야 하기 때문에 나 는 여기 서도 onLayout 방법 을 다시 써 서 가운데 효 과 를 실현 했다.

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
 //       
 var l = left
 var r = right
 var t = top
 var b = bottom
 when {
  width > height -> {
   //                    left    right   
   l = (width - measuredWidth) / 2
   r = width - l
   layout(l, t, r, b)
  }
  height > width -> {
   //                    top    bottom   
   t = (height - measuredHeight) / 2
   b = height - t
   layout(l, t, r, b)
  }
  else -> super.onLayout(changed, left, top, right, bottom)
 }
}
애니메이션 의 실현
  그림 을 그 렸 습 니 다.다음은 어떻게 움 직 여야 할 지 생각 하 는 것 입 니 다.그 려 진 코드 는 생각 하기 어렵 지 않 습 니 다.mStartAngle 의 변 화 를 통 해 그 려 진 각도 회전 을 제어 하 는 것 을 고려 하고 있 습 니 다.ValueAnimator 는 업데이트 할 때마다 value 의 값 을 얻 을 수 있 기 때문에 이 방안 을 선 택 했 습 니 다.

fun start() {
 Log.i("RadarView", "animation start")
 mIsAnimating = true
 mAnimator.duration = 2000
 mAnimator.repeatCount = ValueAnimator.INFINITE
 mAnimator.addUpdateListener {
  val angle = it.animatedValue as Float
  mStartAngle = angle
 
//  Log.i("RadarView", "mStartAngle = $mStartAngle and curValue = ${it.animatedValue}")
  postInvalidate()
 }
 mAnimator.start()
}
  구덩이.
  여기 서 주의해 야 할 점 은 canvas 가 그 릴 때 그 려 진 그림 이 앞 에 그 려 진 그림 에 덮어 쓰기 때문에 그 려 진 순서 에 주의해 야 한 다 는 것 입 니 다.물론 mOutlineRect 의 너비 와 높이 를 measuredWidth-mBorder Width 로 설정 하면 충전 각 도 를 그 릴 때 경 계 를 덮어 쓰 지 않 을 수 있 습 니 다.
  이로써 애니메이션 의 효 과 는 완성 되 었 다.
목표 점 의 가입
  우선 앞의 두 가 지 는 대부분의 레이더 스캐닝 수 요 를 만족 시 킬 수 있 었 다.여기에 목표 점(target)을 추가 하 는 것 은 순 전 히 제 가 가입 하고 싶 은 기능 입 니 다.지도 sdk 의 MapView 와 결합 하여 공동으로 사용 할 수 있다 고 생각 하기 때 문 입 니 다.현재 도 개발 단계 일 뿐 확장 성 을 충분히 고려 하지 못 했 을 수도 있 고 구체 적 인 프로젝트 에 도 적용 되 지 않 았 을 수도 있 습 니 다.하지만 내 가 생각 하 는 기능 도 실천 해 봐 야 한다 고 생각 합 니 다~
  여기 서 주로 사용 하 는 원 의 계산 공식:
   x^{2} + y^{2} = r^2
  안 드 로 이 드 좌표계 의 원점 은 왼쪽 상단 에 있 기 때문에 y 축 은 정점 을 넘 어 아래로 뻗 습 니 다.그림 을 그립 니 다.이 그림 은 좌표계 에 있 는 위 치 를 다음 그림 과 같이 그립 니 다.

  그러면 대응 하 는 공식 은 다음 과 같다.
(x - cx)^{2} + (y - cy)^{2} < r^2
  주의해 야 할 것 은 여기 r 의 계산 은 그림/점 의 설정 에 따라 동태 적 으로 계산 하고 구체 적 인 예 는 코드 를 통 해 분석 할 것 이다.

//     
fun addTarget(size: Int, type: TYPE = TYPE.RANDOM) {
 val list = ArrayList<PointF>()
 val r = measuredWidth.toFloat() / 2
 val innerRect = Rect((r - r / mScaleFactor).toInt(), (r - r / mScaleFactor).toInt(),
  (r + r / mScaleFactor).toInt(), (r + r / mScaleFactor).toInt())
 //      
 val circle = PointF(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2)
 while (list.size < size) {
  val ranX = Random.nextDouble(0.0, r * 2.0).toFloat()
  val ranY = Random.nextDouble(0.0, r * 2.0).toFloat()
  val ranPointF = PointF(ranX, ranY)
  if (innerRect.contains(ranPointF.toPoint())) {
   continue
  }
  //    
  if (!mNeedBitmap &&
   (ranX - circle.x).pow(2) + (ranY - circle.y).pow(2) <
    (r - mTargetRadius - mBorderWidth).toDouble().pow(2.0)) {
   //    
   addTargetFromType(type, list, ranX, ranY, r, ranPointF)
  } else if (mNeedBitmap &&
   (ranX - circle.x).pow(2) + (ranY - circle.y).pow(2) <
    (r - mBorderWidth - max(mBitmap.width, mBitmap.height) / 2).toDouble().pow(2)) {
   //  
   addTargetFromType(type, list, ranX, ranY, r, ranPointF)
  } else {
   continue
  }
 }
 mTargetList = list
 for (target in list) {
  Log.i("RadarView", "target = [${target.x}, ${target.y}]")
 }
 invalidate()
}
  이 를 통 해 알 수 있 듯 이 target 이 일반 점 일 때 r 의 계산 은 targetRadius,즉 목표 점 의 반지름 을 줄 이 는 동시에 경계 폭 도 줄 여야 한다.그림 과 같다.
  
  target 이 그림 일 때 너비 가 일정 하지 않 기 때문에 경 계 를 제외 하고 큰 변 을 빼 야 합 니 다.그러면 r 의 계산 은 다음 과 같 습 니 다.

  또한 그림 의 크기 가 너무 크 지 않도록 기본 값 과 크기 조정 요 소 를 사용 하여 그림 의 완전 성과 너무 커서 발생 하 는 시각 적 추 화 를 피한다.
  타 점 의 위치 에 대해 현재 무 작위 타 점 을 채택 하고 있 습 니 다.만약 에 지도 스 캔 점 에 응용 하면 지도 sdk 안의 거리 계산 도 구 를 통 해 RadarView 의 좌표 와 비례 전환 을 하여 레이더 에 이 점 의 구체 적 인 위 치 를 표시 할 수 있 습 니 다.
  타 점 의 분포 에 대해 현재 5 가지 유형 을 제공 했다.그것 이 바로 전상 한 랜 덤,제1 상한,제2 상한,제3 상한 과 제4 상한 랜 덤 이다.
Github
  직접 호출 해 야 한다 면,이동 할 수 있 습 니 다. https://github.com/CarsonWoo/RadarView
전체 코드

class RadarView : View {
 
 enum class TYPE { RANDOM, FIRST, SECOND, THIRD, FOURTH }
 
 private val mPaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG) }
 
 private val mSweepPaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG) }
 
 private val mOutlinePaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG) }
 
 private val mTargetPaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG) }
 
 private val mDefaultSize = 120// px
 
 // limit the size of bitmap
 private var mBitmapMaxSize = 0F
 
 private var mBitmapWHRatio = 0F
 
 private val mScaleFactor = 30F
 
 private var mStartAngle = 0F
 private val mSweepAngle = -60F
 
 private var mScanColors: IntArray? = null
 
 private val mDefaultScanColors = intArrayOf(Color.parseColor("#0F7F7F7F"),
  Color.parseColor("#7F7F7F7F"),
  Color.parseColor("#857F7F7F"))
 
 private val mDefaultBackgroundColor = Color.WHITE
 
 private var mBackgroundColor: Int = mDefaultBackgroundColor
 
 private var mBorderColor: Int = Color.BLACK
 
 private var mBorderWidth = 0F
 
 private var mTargetColor: Int = Color.RED
 
 private var mTargetRadius = 10F
 
 private lateinit var mOutlineRect: Rect
 
 private val mAnimator = ValueAnimator.ofFloat(0F, 360F)
 
 private var mTargetList: ArrayList<PointF>? = null
 
 private var mIsAnimating = false
 
 private var mNeedBitmap = false
 
 private var mBitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
 
 constructor(context: Context): this(context, null)
 
 constructor(context: Context, attributeSet: AttributeSet?) : super(context, attributeSet)
 
 init {
  mPaint.color = Color.GRAY
  mPaint.strokeWidth = 10F
  mPaint.style = Paint.Style.FILL_AND_STROKE
  mPaint.strokeJoin = Paint.Join.ROUND
  mPaint.strokeCap = Paint.Cap.ROUND
 
  mSweepPaint.style = Paint.Style.FILL
 
  mOutlinePaint.style = Paint.Style.FILL_AND_STROKE
  mOutlinePaint.color = mBackgroundColor
 
  mTargetPaint.style = Paint.Style.FILL
  mTargetPaint.color = mTargetColor
  mTargetPaint.strokeWidth = 10F
 }
 
 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  val vWidth = measureDimension(widthMeasureSpec)
  val vHeight = measureDimension(heightMeasureSpec)
  val size = min(vWidth, vHeight)
 
  setShader(size)
 
  setMeasuredDimension(size, size)
 
  setParamUpdate()
 }
 
 override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
  //       
  var l = left
  var r = right
  var t = top
  var b = bottom
  when {
   width > height -> {
    //                    left    right   
    l = (width - measuredWidth) / 2
    r = width - l
    layout(l, t, r, b)
   }
   height > width -> {
    //                    top    bottom   
    t = (height - measuredHeight) / 2
    b = height - t
    layout(l, t, r, b)
   }
   else -> super.onLayout(changed, left, top, right, bottom)
  }
 }
 
 private fun setShader(size: Int) {
  val shader = SweepGradient(size.toFloat() / 2, size.toFloat() / 2,
   mScanColors?: mDefaultScanColors,
   floatArrayOf(0F, 0.5F, 1F))
  val matrix = Matrix()
  matrix.setRotate(-90F, size.toFloat() / 2, size.toFloat() / 2)
  shader.setLocalMatrix(matrix)
  mSweepPaint.shader = shader
 }
 
 fun setScanColors(colors: IntArray) {
  this.mScanColors = colors
  setShader(measuredWidth)
  invalidate()
 }
 
 fun setRadarColor(@ColorInt color: Int) {
  this.mBackgroundColor = color
  this.mOutlinePaint.color = color
  invalidate()
 }
 
 fun setRadarColor(colorString: String) {
  if (!colorString.startsWith("#") || colorString.length != 7 || colorString.length != 9) {
   Log.e("RadarView", "colorString parse error, please check your enter param")
   return
  }
  val color = Color.parseColor(colorString)
  setRadarColor(color)
 }
 
 fun setBorderColor(@ColorInt color: Int) {
  this.mBorderColor = color
  invalidate()
 }
 
 fun setBorderColor(colorString: String) {
  if (!colorString.startsWith("#") || colorString.length != 7 || colorString.length != 9) {
   Log.e("RadarView", "colorString parse error, please check your enter param")
   return
  }
  val color = Color.parseColor(colorString)
  setBorderColor(color)
 }
 
 fun setRadarGradientColor(colors: IntArray) {
  val shader = SweepGradient(measuredWidth.toFloat() / 2,
   measuredHeight.toFloat() / 2, colors, null)
  mOutlinePaint.shader = shader
  invalidate()
 }
 
 fun setBorderWidth(width: Float) {
  this.mBorderWidth = width
  invalidate()
 }
 
 private fun setParamUpdate() {
  mOutlineRect = Rect(0, 0, measuredWidth, measuredHeight)
 
  mBitmapMaxSize = measuredWidth.toFloat() / mScaleFactor
 }
 
 private fun measureDimension(spec: Int) = when (MeasureSpec.getMode(spec)) {
  MeasureSpec.EXACTLY -> {
   // exactly number or match_parent
   MeasureSpec.getSize(spec)
  }
  MeasureSpec.AT_MOST -> {
   // wrap_content
   min(mDefaultSize, MeasureSpec.getSize(spec))
  }
  else -> {
   mDefaultSize
  }
 }
 
 override fun setBackground(background: Drawable?) {
  //         
//  super.setBackground(background)
 }
 
 override fun onDraw(canvas: Canvas?) {
  super.onDraw(canvas)
  // draw outside circle (background)
  canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2, measuredWidth.toFloat() / 2, mOutlinePaint)
  if (mBorderWidth > 0F && mOutlinePaint.shader == null) {
   drawBorder(canvas)
  }
 
  canvas?.drawArc(mOutlineRect.toRectF(), mStartAngle, mSweepAngle, true, mSweepPaint)
 
  if (!mTargetList.isNullOrEmpty() && !mIsAnimating) {
   drawTarget(canvas)
  }
 
  // draw center circle
  canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2, measuredWidth.toFloat() / 2 / mScaleFactor, mPaint)
 }
 
 private fun drawBorder(canvas: Canvas?) {
  Log.i("RadarView", "drawBorder")
  mOutlinePaint.style = Paint.Style.STROKE
  mOutlinePaint.color = mBorderColor
  mOutlinePaint.strokeWidth = mBorderWidth
  canvas?.drawCircle(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2,
   (measuredWidth.toFloat() - mBorderWidth) / 2, mOutlinePaint)
  //   
  mOutlinePaint.style = Paint.Style.FILL_AND_STROKE
  mOutlinePaint.color = mBackgroundColor
 }
 
 private fun drawTarget(canvas: Canvas?) {
  mTargetList?.let {
   Log.e("RadarView", "draw target")
   for (target in it) {
    if (mNeedBitmap) {
     canvas?.drawBitmap(mBitmap, target.x - mBitmap.width / 2,
      target.y - mBitmap.height / 2, mTargetPaint)
    } else {
     canvas?.drawCircle(target.x, target.y, mTargetRadius, mTargetPaint)
    }
   }
  }
 }
 
 fun setBitmapEnabled(enabled: Boolean, drawable: Drawable) {
  //                      onMeasure      maxSize   0
  post {
   this.mNeedBitmap = enabled
   this.mBitmapWHRatio = drawable.intrinsicWidth.toFloat() / drawable.intrinsicHeight.toFloat()
   mBitmap = if (mBitmapWHRatio >= 1) {
    //     
    drawable.toBitmap(
     width = min(mBitmapMaxSize, drawable.intrinsicWidth.toFloat()).toInt(),
     height = (min(mBitmapMaxSize, drawable.intrinsicWidth.toFloat()) / mBitmapWHRatio).toInt(),
     config = Bitmap.Config.ARGB_8888)
   } else {
    //     
    drawable.toBitmap(
     height = min(mBitmapMaxSize, drawable.intrinsicHeight.toFloat()).toInt(),
     width = (min(mBitmapMaxSize, drawable.intrinsicHeight.toFloat()) * mBitmapWHRatio).toInt(),
     config = Bitmap.Config.ARGB_8888
    )
   }
  }
 }
 
 //     
 fun addTarget(size: Int, type: TYPE = TYPE.RANDOM) {
  val list = ArrayList<PointF>()
  val r = measuredWidth.toFloat() / 2
  val innerRect = Rect((r - r / mScaleFactor).toInt(), (r - r / mScaleFactor).toInt(),
   (r + r / mScaleFactor).toInt(), (r + r / mScaleFactor).toInt())
  //      
  val circle = PointF(measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2)
  while (list.size < size) {
   val ranX = Random.nextDouble(0.0, r * 2.0).toFloat()
   val ranY = Random.nextDouble(0.0, r * 2.0).toFloat()
   val ranPointF = PointF(ranX, ranY)
   if (innerRect.contains(ranPointF.toPoint())) {
    continue
   }
   //    
   if (!mNeedBitmap &&
    (ranX - circle.x).pow(2) + (ranY - circle.y).pow(2) <
     (r - mTargetRadius - mBorderWidth).toDouble().pow(2.0)) {
    //    
    addTargetFromType(type, list, ranX, ranY, r, ranPointF)
   } else if (mNeedBitmap &&
    (ranX - circle.x).pow(2) + (ranY - circle.y).pow(2) <
     (r - mBorderWidth - max(mBitmap.width, mBitmap.height) / 2).toDouble().pow(2)) {
    addTargetFromType(type, list, ranX, ranY, r, ranPointF)
   } else {
    continue
   }
  }
  mTargetList = list
  for (target in list) {
   Log.i("RadarView", "target = [${target.x}, ${target.y}]")
  }
  invalidate()
 }
 
 private fun addTargetFromType(type: TYPE, list: ArrayList<PointF>, ranX: Float, ranY: Float,
         r: Float, ranPointF: PointF) {
  when (type) {
   TYPE.RANDOM -> {
    list.add(ranPointF)
   }
   TYPE.FOURTH -> {
    if (ranX in r.toDouble()..2 * r.toDouble() && ranY in r.toDouble()..2 * r.toDouble()) {
     list.add(ranPointF)
    }
   }
   TYPE.THIRD -> {
    if (ranX in 0.0..r.toDouble() && ranY in r.toDouble()..2 * r.toDouble()) {
     list.add(ranPointF)
    }
   }
   TYPE.SECOND -> {
    if (ranX in 0.0..r.toDouble() && ranY in 0.0..r.toDouble()) {
     list.add(ranPointF)
    }
   }
   TYPE.FIRST -> {
    if (ranX in r.toDouble()..2 * r.toDouble() && ranY in 0.0..r.toDouble()) {
     list.add(ranPointF)
    }
   }
  }
 }
 
 fun start() {
  Log.i("RadarView", "animation start")
  mIsAnimating = true
  mAnimator.duration = 2000
  mAnimator.repeatCount = ValueAnimator.INFINITE
  mAnimator.addUpdateListener {
   val angle = it.animatedValue as Float
   mStartAngle = angle
 
   Log.i("RadarView", "mStartAngle = $mStartAngle and curValue = ${it.animatedValue}")
   postInvalidate()
  }
  mAnimator.start()
 }
 
 fun start(startVal: Float, endVal: Float) {
  mIsAnimating = true
  mAnimator.setFloatValues(startVal, endVal)
  mAnimator.duration = 2000
  mAnimator.repeatCount = ValueAnimator.INFINITE
  mAnimator.addUpdateListener {
   mStartAngle = it.animatedValue as Float
 
   Log.i("RadarView", "mStartAngle = $mStartAngle and curValue = ${it.animatedValue}")
   postInvalidate()
  }
  mAnimator.start()
 }
 
 fun stop() {
  mIsAnimating = false
  if (mAnimator.isRunning) {
   mAnimator.cancel()
   mAnimator.removeAllListeners()
  }
  mStartAngle = 0F
 }
 
}
호출 방식

override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 
 radar_view.setBorderWidth(5F)
 radar_view.setRadarColor(Color.TRANSPARENT)
 radar_view.setBitmapEnabled(true, resources.getDrawable(R.mipmap.ic_launcher_round))
//  radar_view.setScanColors(intArrayOf(Color.RED, Color.LTGRAY, Color.CYAN))
//  radar_view.setRadarGradientColor(intArrayOf(Color.RED, Color.GREEN, Color.BLUE))
 
 btn_start.setOnClickListener {
  radar_view.start()
//  workThreadAndCallback()
 }
 
 btn_stop.setOnClickListener {
  radar_view.stop()
  radar_view.addTarget(7)
 }
}
총결산
안 드 로 이 드 가 레이더 뷰 효 과 를 실현 하 는 것 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.안 드 로 이 드 레이더 뷰 효과 에 관 한 더 많은 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기