欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實現(xiàn)雷達View效果的示例代碼

 更新時間:2020年06月18日 14:09:28   作者:CarsonWoo  
這篇文章主要介紹了Android實現(xiàn)雷達View效果,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

樣式效果

  還是先來看效果:

  這是一個仿雷達掃描的效果,是之前在做地圖sdk接入時就想實現(xiàn)的效果,但之前由于趕著畢業(yè)設計,就沒有親手去實現(xiàn),不過現(xiàn)在自己擼一個發(fā)現(xiàn)還是挺簡單的。

  這里主要分享一下我的做法。

目錄

主體輪廓的實現(xiàn)(雷達的結構)

動畫的實現(xiàn)(雷達掃描的效果)

目標點的加入(圖片/點)

主體輪廓實現(xiàn)

  

  不難分析得出,這個View主要由外部的一個圓,中間的錨點圓以及扇形旋轉區(qū)域組成。而且每個部分理應由不同的Paint去繪制,以方便去定制各部分的樣式。

  外部圓以及錨點圓的繪制較為簡單,主要的點還是要對整個View的寬高進行一定的限制,例如寬高必須相等且在某種模式下,取小的那個值來限定整個RadarView的最大值。那么該如何去控制呢?

onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)

  由于我們繼承自View,在onMeasure方法中,我們可以根據(jù)兩個參數(shù)來獲取Mode,并且根據(jù)Mode來指定寬/高對應的值,再通過setMeasuredDimension去指定控件主體的寬高即可。

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
 }
}

  測量工作完成了,我們自然可以去繪制了。為了不讓中間的小圓看起來那么突兀(偏大或偏小),這里設置了一個scaleFactor的縮放因子,使其能根據(jù)外圓的尺寸來進行縮放。

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
}

  繪制了基準圓以后,要實現(xiàn)雷達掃描時那種漸變的效果,我們可以通過SweepGradient來操作。通過指定中心點,漸變顏色,以及顏色的分布,來定制掃描漸變的樣式,默認的即時開頭時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方法,來實現(xiàn)居中的效果。

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)
 }
}

動畫的實現(xiàn)

  完成了繪制,接下來就是思考該如何讓他動起來了。由繪制的代碼不難想到,我這里考慮的是通過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 - mBorderWidth,那么就能保證繪制填充角度時,不會把邊界覆蓋。

  至此,動畫的效果便完成了。

目標點的加入

  首先,前兩點已經(jīng)能滿足大多的雷達掃描需求了。這里這個添加目標點(target)純粹是我自己想加入的功能,因為覺得可以結合地圖sdk的MapView來共同使用,目前也只是開發(fā)階段,擴展性可能考慮得還不是特別充足,也還沒應用到具體項目中。但是,總覺得自己想的功能也該試著去實踐一下~

  這里主要運用的圓的計算公式:

  x^{2} + y^{2} = r^2

  由于Android的坐標系的原點是在左上角,y軸過頂點向下延伸。由我們的繪制可知,此繪制圖像在坐標系中的位置大概如下圖所示:

  那么,對應的公式就為:

(x - cx)^{2} + (y - cy)^{2} < r^2

  要注意的是,這里r的計算會根據(jù)圖/點的設置來動態(tài)計算,具體例子通過代碼來進行分析。

// 隨機落點
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內(nèi)的距離計算工具再與RadarView的坐標做一個比例轉換,從而達到雷達內(nèi)顯示該點具體方位。

  關于落點的分布,目前提供了5種類型:分別是全象限隨機、第一象限、第二象限、第三象限與第四象限隨機。

Github

  若須直接調(diào)用,可移步至 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?) {
  // 取消傳統(tǒng)背景設置
//  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)) {
    // 在圓內(nèi)
    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
 }
 
}

調(diào)用方式

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)
 }
}

總結

到此這篇關于Android實現(xiàn)雷達View效果的文章就介紹到這了,更多相關android 雷達View效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Android ListView組件詳解及示例代碼

    Android ListView組件詳解及示例代碼

    本文主要介紹Android ListView,這里整理了ListView 組件的資料,并附示例代碼和實現(xiàn)效果圖,有需要的朋友可以參考下
    2016-08-08
  • Android實現(xiàn)秒表功能

    Android實現(xiàn)秒表功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)簡易秒表功能,具備啟停功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Android運用onTouchEvent自定義滑動布局

    Android運用onTouchEvent自定義滑動布局

    這篇文章主要為大家詳細介紹了Android運用onTouchEvent寫一個上下滑動的布局,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android Studio注釋模板介紹

    Android Studio注釋模板介紹

    這篇文章主要介紹了Android Studio注釋模板介紹,之前Eclipse敲/**加回車,模板就出來了,而Android Studio卻不可以自定義,現(xiàn)在我給大家介紹下用live templates替代,需要的朋友可以參考下
    2015-07-07
  • Android上傳文件到Web服務器 PHP接收文件

    Android上傳文件到Web服務器 PHP接收文件

    這篇文章主要為大家詳細介紹了Android上傳文件到Web服務器,PHP接收文件的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android拍攝照片后返回縮略圖的方法

    Android拍攝照片后返回縮略圖的方法

    這篇文章主要介紹了Android拍攝照片后返回縮略圖的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • android自定義view實現(xiàn)推箱子小游戲

    android自定義view實現(xiàn)推箱子小游戲

    這篇文章主要為大家詳細介紹了android自定義view實現(xiàn)推箱子小游戲,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Android Jetpack架構組件Lifecycle詳解

    Android Jetpack架構組件Lifecycle詳解

    這篇文章主要介紹了Android Jetpack架構組件Lifecycle詳解,Lifecycle是Jetpack架構組件中用來感知生命周期的組件,使用Lifecycles可以幫助我們寫出和生命周期相關更簡潔更易維護的代碼。對此感興趣的小伙伴可以來學習一下
    2020-07-07
  • Android RecyclerView實現(xiàn)數(shù)據(jù)列表展示效果

    Android RecyclerView實現(xiàn)數(shù)據(jù)列表展示效果

    這篇文章主要為大家詳細介紹了Android RecyclerView實現(xiàn)數(shù)據(jù)列表展示效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android中使用PagerSlidingTabStrip實現(xiàn)導航標題的示例

    Android中使用PagerSlidingTabStrip實現(xiàn)導航標題的示例

    本篇文章主要介紹了Android中使用PagerSlidingTabStrip實現(xiàn)導航標題的示例,具有一定的參考價值,有興趣的可以了解一下。
    2017-01-01

最新評論