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

Android自定義View實現(xiàn)時鐘功能

 更新時間:2022年09月11日 12:16:04   作者:skylarliuu  
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)時鐘功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

最近在練習(xí)自定義view, 想起之前面試的時候筆試有道題是寫出自定義一個時鐘的關(guān)鍵代碼. 今天就來實現(xiàn)一下. 步驟依然是先分析, 再上代碼.

實現(xiàn)效果

View分析

時鐘主要分為五個部分:

1、中心點: 圓心位置

2、圓盤: 以中心點為圓心,drawCircle畫個圓

3、刻度:

paint有個aip, setPathEffect可以根據(jù)path畫特效, 那么刻度就可以根據(jù)圓的path畫一個矩形path的特效, 并且這個api只會畫特效, 不會畫出圓.

/**
* shape: 特效的path, 這里傳一個矩形
* advance: 兩個特效path之間的間距, 即兩個矩形的left間距
* phase: 特效起始位置的偏移
* style: 原始path拐彎的時候特效path的轉(zhuǎn)換方式,這里用ROTATE跟著旋轉(zhuǎn)即可
*/
PathDashPathEffect(Path shape, float advance, float phase,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Style style)

刻度又分兩種, 粗一點刻度: 3、6、9、12, 和細一點的刻度. 兩種特效又可以用SumPathEffect合起來畫

SumPathEffect(PathEffect first, PathEffect second)?

4、時分秒指針

時分秒指針都是一個圓角矩形, 先把他們的位置計算出來, 然后旋轉(zhuǎn)圓心去繪制不同角度的指針.

5、動畫效果

TimerTask每隔一秒計算時間, 根據(jù)時間去換算當(dāng)前時分秒指針的角度, 動態(tài)變量只有三個角度.

實現(xiàn)源碼

//
// Created by skylar on 2022/4/19.
//
class ClockView : View {
? ? private var mTimer: Timer? = null
? ? private val mCirclePaint: Paint = Paint()
? ? private val mPointerPaint: Paint = Paint()
? ? private val mTextPaint: Paint = Paint()

? ? private val mCirclePath: Path = Path()
? ? private val mHourPath: Path = Path()
? ? private val mMinutePath: Path = Path()
? ? private val mSecondPath: Path = Path()

? ? private lateinit var mPathMeasure: PathMeasure
? ? private lateinit var mSumPathEffect: SumPathEffect

? ? private var mViewWidth = 0
? ? private var mViewHeight = 0
? ? private var mCircleWidth = 6f
? ? private var mRadius = 0f
? ? private var mRectRadius = 20f
? ? private var mHoursDegree = 0f
? ? private var mMinutesDegree = 0f
? ? private var mSecondsDegree = 0f
? ? private var mCurrentTimeInSecond = 0L

? ? constructor(context: Context) : super(context)

? ? constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

? ? constructor(
? ? ? ? context: Context, attrs: AttributeSet?,
? ? ? ? defStyleAttr: Int
? ? ) : super(context, attrs, defStyleAttr)

? ? init {
? ? ? ? mCirclePaint.color = Color.BLACK
? ? ? ? mCirclePaint.isAntiAlias = true
? ? ? ? mCirclePaint.style = Paint.Style.STROKE
? ? ? ? mCirclePaint.strokeWidth = mCircleWidth

? ? ? ? mPointerPaint.color = Color.BLACK
? ? ? ? mPointerPaint.isAntiAlias = true
? ? ? ? mPointerPaint.style = Paint.Style.FILL

? ? ? ? mTextPaint.color = Color.BLACK
? ? ? ? mTextPaint.isAntiAlias = true
? ? ? ? mTextPaint.style = Paint.Style.FILL
? ? ? ? mTextPaint.textSize = 40f
? ? }

? ? override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
? ? ? ? super.onSizeChanged(w, h, oldw, oldh)
? ? ? ? mViewWidth = measuredWidth - paddingLeft - paddingRight
? ? ? ? mViewHeight = measuredHeight - paddingTop - paddingBottom

? ? ? ? mRadius = mViewWidth / 2 - mCircleWidth
? ? ? ? mCirclePath.addCircle(0f, 0f, mRadius, Path.Direction.CW)

? ? ? ? mPathMeasure = PathMeasure(mCirclePath, false)
? ? ? ? val minutesShapePath = Path()
? ? ? ? val quarterShapePath = Path()
? ? ? ? minutesShapePath.addRect(0f, 0f, mRadius * 0.01f, mRadius * 0.06f, Path.Direction.CW)
? ? ? ? quarterShapePath.addRect(0f, 0f, mRadius * 0.02f, mRadius * 0.06f, Path.Direction.CW)
? ? ? ? val minutesDashPathEffect = PathDashPathEffect(
? ? ? ? ? ? minutesShapePath,
? ? ? ? ? ? mPathMeasure.length / 60,
? ? ? ? ? ? 0f,
? ? ? ? ? ? PathDashPathEffect.Style.ROTATE
? ? ? ? )
? ? ? ? val quarterDashPathEffect = PathDashPathEffect(
? ? ? ? ? ? quarterShapePath,
? ? ? ? ? ? mPathMeasure.length / 12,
? ? ? ? ? ? 0f,
? ? ? ? ? ? PathDashPathEffect.Style.ROTATE
? ? ? ? )
? ? ? ? mSumPathEffect = SumPathEffect(minutesDashPathEffect, quarterDashPathEffect)

? ? ? ? val hourPointerHeight = mRadius * 0.5f
? ? ? ? val hourPointerWidth = mRadius * 0.07f
? ? ? ? val hourRect = RectF(
? ? ? ? ? ? -hourPointerWidth / 2,
? ? ? ? ? ? -hourPointerHeight * 0.7f,
? ? ? ? ? ? hourPointerWidth / 2,
? ? ? ? ? ? hourPointerHeight * 0.3f
? ? ? ? )
? ? ? ? mHourPath.addRoundRect(hourRect, mRectRadius, mRectRadius, Path.Direction.CW)

? ? ? ? val minutePointerHeight = mRadius * 0.7f
? ? ? ? val minutePointerWidth = mRadius * 0.05f
? ? ? ? val minuteRect = RectF(
? ? ? ? ? ? -minutePointerWidth / 2,
? ? ? ? ? ? -minutePointerHeight * 0.8f,
? ? ? ? ? ? minutePointerWidth / 2,
? ? ? ? ? ? minutePointerHeight * 0.2f
? ? ? ? )
? ? ? ? mMinutePath.addRoundRect(minuteRect, mRectRadius, mRectRadius, Path.Direction.CW)

? ? ? ? val secondPointerHeight = mRadius * 0.9f
? ? ? ? val secondPointerWidth = mRadius * 0.03f
? ? ? ? val secondRect = RectF(
? ? ? ? ? ? -secondPointerWidth / 2,
? ? ? ? ? ? -secondPointerHeight * 0.8f,
? ? ? ? ? ? secondPointerWidth / 2,
? ? ? ? ? ? secondPointerHeight * 0.2f
? ? ? ? )
? ? ? ? mSecondPath.addRoundRect(secondRect, mRectRadius, mRectRadius, Path.Direction.CW)

? ? ? ? startAnimator()
? ? }

? ? override fun onDraw(canvas: Canvas?) {
? ? ? ? super.onDraw(canvas)
? ? ? ? if (canvas == null) {
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? canvas.translate((mViewWidth / 2).toFloat(), (mViewHeight / 2).toFloat())

? ? ? ? //畫圓盤
? ? ? ? mCirclePaint.pathEffect = null
? ? ? ? canvas.drawPath(mCirclePath, mCirclePaint)

? ? ? ? //畫刻度
? ? ? ? mCirclePaint.pathEffect = mSumPathEffect
? ? ? ? canvas.drawPath(mCirclePath, mCirclePaint)

? ? ? ? //時分秒指針
? ? ? ? mPointerPaint.color = Color.BLACK

? ? ? ? canvas.save()
? ? ? ? canvas.rotate(mHoursDegree)
? ? ? ? canvas.drawPath(mHourPath, mPointerPaint)
? ? ? ? canvas.restore()

? ? ? ? canvas.save()
? ? ? ? canvas.rotate(mMinutesDegree)
? ? ? ? canvas.drawPath(mMinutePath, mPointerPaint)
? ? ? ? canvas.restore()

? ? ? ? canvas.save()
? ? ? ? canvas.rotate(mSecondsDegree)
? ? ? ? canvas.drawPath(mSecondPath, mPointerPaint)
? ? ? ? canvas.restore()

? ? ? ? //畫中心點
? ? ? ? mPointerPaint.color = Color.WHITE
? ? ? ? canvas.drawCircle(0f, 0f, mRadius * 0.02f, mPointerPaint)
? ? }


? ? private fun startAnimator() {
? ? ? ? val cal = Calendar.getInstance()
? ? ? ? val hour = cal.get(Calendar.HOUR) ?//小時
? ? ? ? val minute = cal.get(Calendar.MINUTE) ?//分
? ? ? ? val second = cal.get(Calendar.SECOND) ?//秒
? ? ? ? mCurrentTimeInSecond = (hour * 60 * 60 + minute * 60 + second).toLong()

? ? ? ? if (mTimer == null) {
? ? ? ? ? ? mTimer = Timer()
? ? ? ? } else {
? ? ? ? ? ? mTimer?.cancel()
? ? ? ? ? ? mTimerTask.cancel()
? ? ? ? }
? ? ? ? mTimer?.schedule(mTimerTask, 0, 1000)
? ? }

? ? private var mTimerTask: TimerTask = object : TimerTask() {
? ? ? ? override fun run() {
? ? ? ? ? ? mCurrentTimeInSecond++
? ? ? ? ? ? computeDegree()
? ? ? ? ? ? invalidate()
? ? ? ? }
? ? }

? ? //12小時 00:00:00 ~ 12:00:00
? ? private fun computeDegree() {
? ? ? ? val secondsInOneRoll = 12 * 60 * 60
? ? ? ? val currentSeconds = mCurrentTimeInSecond % secondsInOneRoll

? ? ? ? var leftSeconds = currentSeconds
? ? ? ? val hours = currentSeconds / 60 / 60
? ? ? ? leftSeconds = currentSeconds - hours * 60 * 60
? ? ? ? val minutes = leftSeconds / 60
? ? ? ? leftSeconds -= minutes * 60
? ? ? ? val seconds = leftSeconds % 60

? ? ? ? mHoursDegree = hours * 30f
? ? ? ? mMinutesDegree = minutes * 6f
? ? ? ? mSecondsDegree = seconds * 6f

? ? }
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決Android加殼過程中mprotect調(diào)用失敗的原因分析

    解決Android加殼過程中mprotect調(diào)用失敗的原因分析

    本文探討的主要內(nèi)容是mprotect調(diào)用失敗的根本原因,以及在加殼實現(xiàn)中的解決方案,通過本文的闡述,一方面能夠幫助遇到同類問題的小伙伴解決心中的疑惑,另一方面能夠給大家提供可落地的實現(xiàn)方案,需要的朋友可以參考下
    2022-01-01
  • 淺談Android App開發(fā)中Fragment的創(chuàng)建與生命周期

    淺談Android App開發(fā)中Fragment的創(chuàng)建與生命周期

    這篇文章主要介紹了Android App開發(fā)中Fragment的創(chuàng)建與生命周期,文中詳細地介紹了Fragment的概念以及一些常用的生命周期控制方法,需要的朋友可以參考下
    2016-02-02
  • 深入理解Android中的xmlns:tools屬性

    深入理解Android中的xmlns:tools屬性

    關(guān)于xmlns:tools屬性的介紹網(wǎng)上有很多,小編覺得有必要整理一篇介紹較為詳細的內(nèi)容給大家,下面這篇文章就很深入的介紹了關(guān)于Android中的xmlns:tools屬性,有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • Android獲取手機號碼和運營商信息的方法

    Android獲取手機號碼和運營商信息的方法

    這篇文章主要介紹了Android獲取手機號碼和運營商信息的方法,以實例形式完整講述了獲取手機號碼和運營商信息的技巧,代碼中包含完整的注釋說明,需要的朋友可以參考下
    2015-01-01
  • Android BottomSheetDialog實現(xiàn)底部對話框的示例

    Android BottomSheetDialog實現(xiàn)底部對話框的示例

    這篇文章主要介紹了Android BottomSheetDialog實現(xiàn)底部對話框的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • Android實現(xiàn)短信發(fā)送功能

    Android實現(xiàn)短信發(fā)送功能

    這篇文章主要介紹了Android實現(xiàn)短信發(fā)送功能,對Android實現(xiàn)短信發(fā)送的每一步都進行了詳細的介紹,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Android中子線程和UI線程通信詳解

    Android中子線程和UI線程通信詳解

    這篇文章主要介紹了Android中子線程和UI線程通信詳解,本文講解了一些概念、使用、及代碼實例,需要的朋友可以參考下
    2015-06-06
  • 淺談Android中多線程切換的幾種方法

    淺談Android中多線程切換的幾種方法

    本篇文章主要介紹了淺談Android中多線程切換的幾種方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 利用Jetpack?Compose實現(xiàn)繪制五角星效果

    利用Jetpack?Compose實現(xiàn)繪制五角星效果

    這篇文章主要為大家介紹了Jetpack?Compose如何使用自定義操作符實現(xiàn)繪制五角星效果,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-04-04
  • android中AutoCompleteTextView的簡單用法(實現(xiàn)搜索歷史)

    android中AutoCompleteTextView的簡單用法(實現(xiàn)搜索歷史)

    本篇文章主要介紹了android中AutoCompleteTextView的簡單用法(自動提示),有需要的可以了解一下。
    2016-11-11

最新評論