日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android自定义sleep图,android自定义view实现钟表效果

發(fā)布時間:2025/3/20 Android 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android自定义sleep图,android自定义view实现钟表效果 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文實例為大家分享了android view實現(xiàn)鐘表的具體代碼,供大家參考,具體內(nèi)容如下

先看效果圖:

自定義view大家肯定已經(jīng)不陌生了,所以直接今天直接步入正題:如何利用canvas去繪制出一個鐘表

當然繪制之前我們必須進行測量(重寫onMeasure),根據(jù)自己的規(guī)則去測量,這暫時是將控件限制為一個正方形。

首先我們先把鐘表分解,看它由哪幾部分組成。如上圖:鐘表包括表盤(刻度)和表針還有文字構(gòu)成。

分清結(jié)構(gòu)之后我們再明確canvas需要畫什么,表盤的構(gòu)成其實就是外層一個圓,然后上面是有規(guī)律的線段,表針就是三個長短不一的線段,再加上12個鐘點文字。這樣一分析是不是發(fā)現(xiàn)調(diào)用canvas的drawCircle、drawLine和drawText就可以完成鐘表的繪制了。

既然明確了我們繪制所需要的方法,那么就開始重頭戲了,告訴canvas在哪繪制這些零件。

最外層的圓是最簡單的,我們只需要以控件的中心為圓心,控件的寬度一半為半徑畫一個圓就可以了。

接下來就是難點一了,這些刻度怎么辦呢,其實我們不難發(fā)現(xiàn)其中的規(guī)律,每個刻度之間的弧度是一樣的,那這樣我們是不是可以通過旋轉(zhuǎn)畫布就可以實現(xiàn)這些刻度的繪制呢,答案是肯定的。

難點二,文字又該如何繪制,難道也通過旋轉(zhuǎn)畫布嗎,但是你想一下,假如通過旋轉(zhuǎn)畫布去繪制文字,那有些文字可是會顛倒的,這并不是我們想要的結(jié)果,那該怎么辦,這時候我們只能通過數(shù)學計算老老實實的計算每個文字的起始坐標,這些坐標并沒有想象中的復雜,我們可以根據(jù)中心點的位置和偏移角度(當然還需要考慮文字的寬度)算出。

難點三,繪制表針,其實文字繪制出來,那么同樣可以根據(jù)中心點和偏移角度算出表針的起始坐標和結(jié)束坐標

表心就是一個實體的圓,這個就簡單了。

好像還沒說時分秒是怎么確定的,這當然是通過系統(tǒng)時間獲取的了。說到這里似乎一個靜態(tài)鐘表已經(jīng)繪制出來了,接下來讓它動起來就可以了。在這我們啟動一個線程,讓它隔一秒鐘進行一次重繪即可。

下面我直接貼一下代碼把,代碼是用kotlin實現(xiàn)(這不是重點)的

package com.example.commonui.widget

import android.annotation.SuppressLint

import android.content.Context

import android.graphics.Canvas

import android.graphics.Color

import android.graphics.Paint

import android.os.Handler

import android.os.Message

import android.util.AttributeSet

import android.view.View

import java.util.*

/**

* Created by zhang on 2017/12/20.

*/

class ClockView(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {

companion object {

private const val DEFAULT_WIDTH = 200 //默認寬度

}

private lateinit var mBlackPaint: Paint//黑色畫筆

private lateinit var mRedPaint: Paint //紅色畫筆

private lateinit var mBlackPaint2: Paint//黑色畫筆

private lateinit var mTextPaint: Paint

private var hour: Int? = null

private var minute: Int? = null

private var second: Int? = null

private val textArray = arrayOf("12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11")

private var refreshThread: Thread? = null

private var mHandler = @SuppressLint("HandlerLeak")

object : Handler() {

override fun handleMessage(msg: Message?) {

super.handleMessage(msg)

when (msg?.what) {

0 -> {

invalidate()

}

}

}

}

init {

initPaints()

}

/**

* 初始化畫筆

*/

private fun initPaints() {

mBlackPaint = Paint()

with(mBlackPaint) {

color = Color.BLACK

strokeWidth = 5f

isAntiAlias = true

style = Paint.Style.STROKE

}

//用于畫表心

mBlackPaint2 = Paint()

with(mBlackPaint2) {

color = Color.BLACK

isAntiAlias = true

style = Paint.Style.FILL

}

mRedPaint = Paint()

with(mRedPaint) {

color = Color.RED

strokeWidth = 5f

isAntiAlias = true

}

mTextPaint = Paint()

with(mTextPaint) {

color = Color.BLACK

textSize = 30f

isAntiAlias = true

}

}

override fun onDraw(canvas: Canvas?) {

super.onDraw(canvas)

//獲取當前時間

getCurrentTime()

//先畫最外層的圓圈

drawOuterCircle(canvas)

//畫刻度

drawScale(canvas)

//繪制文字

drawTimeText(canvas)

//繪制表針

drawHand(canvas)

//繪制表心

drawCenter(canvas)

}

private fun getCurrentTime() {

val calendar = Calendar.getInstance()

hour = calendar.get(Calendar.HOUR)

minute = calendar.get(Calendar.MINUTE)

second = calendar.get(Calendar.SECOND)

}

private fun drawOuterCircle(canvas: Canvas?) {

mBlackPaint.strokeWidth = 5f

canvas?.drawCircle(measuredWidth / 2.toFloat(), measuredHeight / 2.toFloat(), (measuredWidth / 2 - 5).toFloat(), mBlackPaint)

}

private fun drawCenter(canvas: Canvas?) {

canvas?.drawCircle(measuredWidth / 2.toFloat(), measuredHeight / 2.toFloat(), 20f, mBlackPaint2)

}

private fun drawHand(canvas: Canvas?) {

drawSecond(canvas, mRedPaint)

mBlackPaint.strokeWidth = 10f

drawMinute(canvas, mBlackPaint)

mBlackPaint.strokeWidth = 15f

drawHour(canvas, mBlackPaint)

}

private fun drawTimeText(canvas: Canvas?) {

val textR = (measuredWidth / 2 - 50).toFloat()//文字構(gòu)成的圓的半徑

for (i in 0..11) {

//繪制文字的起始坐標

val startX = (measuredWidth / 2 + textR * Math.sin(Math.PI / 6 * i) - mTextPaint.measureText(textArray[i]) / 2).toFloat()

val startY = (measuredHeight / 2 - textR * Math.cos(Math.PI / 6 * i) + mTextPaint.measureText(textArray[i]) / 2).toFloat()

canvas?.drawText(textArray[i], startX, startY, mTextPaint)

}

}

private fun drawScale(canvas: Canvas?) {

var scaleLength: Float?

canvas?.save()

//0..59代表[0,59]

for (i in 0..59) {

if (i % 5 == 0) {

//大刻度

mBlackPaint.strokeWidth = 5f

scaleLength = 20f

} else {

//小刻度

mBlackPaint.strokeWidth = 3f

scaleLength = 10f

}

canvas?.drawLine(measuredWidth / 2.toFloat(), 5f, measuredWidth / 2.toFloat(), (5 + scaleLength), mBlackPaint)

canvas?.rotate(360 / 60.toFloat(), measuredWidth / 2.toFloat(), measuredHeight / 2.toFloat())

}

//恢復原來狀態(tài)

canvas?.restore()

}

/**

* 繪制秒針

*/

private fun drawSecond(canvas: Canvas?, paint: Paint?) {

//秒針長半徑 (表針會穿過表心 所以需要根據(jù)兩個半徑計算起始和結(jié)束半徑)

val longR = measuredWidth / 2 - 60

val shortR = 60

val startX = (measuredWidth / 2 - shortR * Math.sin(second!!.times(Math.PI / 30))).toFloat()

val startY = (measuredWidth / 2 + shortR * Math.cos(second!!.times(Math.PI / 30))).toFloat()

val endX = (measuredWidth / 2 + longR * Math.sin(second!!.times(Math.PI / 30))).toFloat()

val endY = (measuredWidth / 2 - longR * Math.cos(second!!.times(Math.PI / 30))).toFloat()

canvas?.drawLine(startX, startY, endX, endY, paint)

}

/**

* 繪制分針

*/

private fun drawMinute(canvas: Canvas?, paint: Paint?) {

//半徑比秒針小一點

val longR = measuredWidth / 2 - 90

val shortR = 50

val startX = (measuredWidth / 2 - shortR * Math.sin(minute!!.times(Math.PI / 30))).toFloat()

val startY = (measuredWidth / 2 + shortR * Math.cos(minute!!.times(Math.PI / 30))).toFloat()

val endX = (measuredWidth / 2 + longR * Math.sin(minute!!.times(Math.PI / 30))).toFloat()

val endY = (measuredWidth / 2 - longR * Math.cos(minute!!.times(Math.PI / 30))).toFloat()

canvas?.drawLine(startX, startY, endX, endY, paint)

}

/**

* 繪制時針

*/

private fun drawHour(canvas: Canvas?, paint: Paint?) {

//半徑比秒針小一點

val longR = measuredWidth / 2 - 120

val shortR = 40

val startX = (measuredWidth / 2 - shortR * Math.sin(hour!!.times(Math.PI / 6))).toFloat()

val startY = (measuredWidth / 2 + shortR * Math.cos(hour!!.times(Math.PI / 6))).toFloat()

val endX = (measuredWidth / 2 + longR * Math.sin(hour!!.times(Math.PI / 6))).toFloat()

val endY = (measuredWidth / 2 - longR * Math.cos(hour!!.times(Math.PI / 6))).toFloat()

canvas?.drawLine(startX, startY, endX, endY, paint)

}

/**

* 進行測量

*/

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec)

val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)

val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)

val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)

val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec)

val result = if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {

DEFAULT_WIDTH

} else {

Math.min(widthSpecSize, heightSpecSize)

}

setMeasuredDimension(result, result)

}

override fun onAttachedToWindow() {

super.onAttachedToWindow()

//啟動線程 刷新界面

refreshThread = Thread(Runnable {

while (true) {

try {

Thread.sleep(1000)

mHandler.sendEmptyMessage(0)

} catch (e: InterruptedException) {

break

}

}

})

refreshThread?.start()

}

override fun onDetachedFromWindow() {

super.onDetachedFromWindow()

mHandler.removeCallbacksAndMessages(null)

//中斷線程

refreshThread?.interrupt()

}

}

在這送上幾點建議,1.盡量不要再ondraw里面創(chuàng)建對象,因為view可能會多次重繪,每次都創(chuàng)建新的對象會造成不必要的內(nèi)存浪費

2.onmeasure方法會調(diào)用多次,請保證你的邏輯覆蓋性,否則可能會出現(xiàn)沒有按照你的預期得到寬高

3.線程的謹慎使用

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

總結(jié)

以上是生活随笔為你收集整理的Android自定义sleep图,android自定义view实现钟表效果的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久草视频免费在线 | 国内精品视频一区 | 伊人国产在线 | 在线免费观看网站入口在哪 | 精品久久网站 | 日本一级网站 | 国产97超碰 | 福利一区二区视频 | 三年中国片在线高清观看 | 伊人免费视频二 | 亚洲黄在线 | 波多野结衣在线观看一区二区 | 日本一区二区三区在线观看视频 | 国产aⅴ精品一区二区果冻 台湾性生生活1 | 一卡二卡三卡四卡 | 午夜剧场福利 | 伊人久久一区二区 | 国产乱码精品一区二区三区中文 | 欧美美女在线 | 四虎国产 | 9色视频在线观看 | 免费看av在线 | 亚洲大片在线观看 | 日韩福利视频在线观看 | 欧美视频黄色 | 2019毛片 | 亚洲图片一区二区 | 右手影院亚洲欧美 | 欧美成人hd | 4388成人网 | 丁香花在线影院观看在线播放 | 无遮挡毛片 | 大地资源二中文在线影视观看 | 一级免费av| 性欧美大战久久久久久久久 | 亚洲丝袜在线视频 | 樱桃国产成人精品视频 | 超碰666| 欧美黑粗硬| 四虎永久在线观看 | 国产永久在线 | 亚洲欧美婷婷 | 亚洲av女人18毛片水真多 | 国模私拍一区二区 | 韩国三级视频在线观看 | 99国产超薄肉色丝袜交足 | 成人小视频在线 | 国产精品入口66mio男同 | 欧美日韩乱 | 爆操白虎 | 日韩高清不卡一区 | 已满十八岁免费观看全集动漫 | 人人妻人人做人人爽 | 亚洲精品香蕉 | 农夫色综合| 亚洲精品色午夜无码专区日韩 | 无码人妻久久一区二区三区 | 嫩草影院在线免费观看 | 日本精品网 | 天天夜碰日日摸日日澡性色av | a天堂最新地址 | 国产午夜在线播放 | 好吊色免费视频 | 五月婷婷视频在线观看 | 在线中文字幕第一页 | 久久成人国产精品入口 | 成人午夜免费电影 | 国内毛片毛片毛片 | 少妇人妻好深好紧精品无码 | 雷电将军和丘丘人繁衍后代视频 | 日本少妇毛茸茸高潮 | 日韩一区二区视频在线 | 国产精品国产三级国产三级人妇 | 超污网站在线观看 | 午夜中文字幕 | 在线精品亚洲欧美日韩国产 | 国产视频高清 | 亚洲熟妇无码另类久久久 | 亚欧美在线 | 伊人网伊人网 | 综合久久综合久久 | 日韩免费成人av | 桃色视频| 奇米影视999| 亚洲AV无码国产日韩久久 | 91伦理视频 | 日韩影院一区二区 | 91avcom| 久久久久久久黄色片 | 综合网在线视频 | 中文精品久久久久人妻不卡 | 91在线播放视频 | 久久97超碰 | 亚洲一区久久久 | 国产精品高清无码 | 女人久久久久 | 素人av在线 | 色婷婷国产精品久久包臀 | 九九九九热|