欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

如何實(shí)現(xiàn)自定義View之播放暫停控件-創(chuàng)新互聯(lián)

這篇文章主要介紹如何實(shí)現(xiàn)自定義View之播放暫停控件,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了大慶免費(fèi)建站歡迎大家使用!

首先看一下效果圖:

如何實(shí)現(xiàn)自定義View之播放暫停控件

下面先分析一下原理:

如何實(shí)現(xiàn)自定義View之播放暫停控件

狀態(tài)1是播放狀態(tài),有兩個(gè)小矩形,外面是一個(gè)圓,它需要最終變換成狀態(tài)3的暫停狀態(tài)
狀態(tài)2是兩個(gè)小矩形變成如圖的黑色三角的一個(gè)過(guò)程
我們可以通過(guò)動(dòng)畫來(lái)實(shí)現(xiàn)它,兩個(gè)小矩形分別變成三角形的一半
同時(shí)再給畫布一個(gè)90度的旋轉(zhuǎn)

具體實(shí)現(xiàn):

1.繼承View

class PlayPauseView : View

2.重寫構(gòu)造函數(shù)

constructor(context: Context?) : this(context,null)
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs,0)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
 init(context!!,attrs!!)
}

一般的寫法都是講初始化代碼放在三個(gè)參數(shù)的構(gòu)造函數(shù)里,其它兩個(gè)構(gòu)造函數(shù)分別繼承自參數(shù)更多的一個(gè)本類的構(gòu)造函數(shù),所以這里用的是this關(guān)鍵字

3.初始化參數(shù)

首先我們需要先在values包的attrs文件中先聲明屬性

<declare-styleable name="PlayPauseView">
 <attr name="barWidth" format="dimension"/>
 <attr name="barHeight" format="dimension"/>
 <attr name="barPadding" format="dimension"/>
 <attr name="barColor" format="color"/>
 <attr name="barBgColor" format="color"/>
 <attr name="barClockWise" format="boolean"/>
 <attr name="barPlayingState" format="boolean"/>
</declare-styleable>

然后在構(gòu)造函數(shù)中拿到這些參數(shù)

mBarWidth = typedArray.getDimension(R.styleable.PlayPauseView_barWidth,10 * getDensity())
mBarHeight = typedArray.getDimension(R.styleable.PlayPauseView_barHeight,30 * getDensity())
mPadding = typedArray.getDimension(R.styleable.PlayPauseView_barPadding,10 * getDensity())
//可以通過(guò)上面的三個(gè)參數(shù)計(jì)算出下面的參數(shù)值,所以不再通過(guò)xml設(shè)置
mBarSpace = mBarHeight - mBarWidth * 2
mRadius = mBarWidth + mBarSpace.div(2) + mPadding
mWidth = mRadius * 2
mWidth = mRadius * 2

mBarWidth 是小矩形的寬度,mBarHeight 是小矩形的高度,mPadding 是小矩形距離整個(gè)view的邊界距離(參考上圖中狀態(tài)1中左邊小矩形距離大矩形的距離,距離top和left應(yīng)該是一樣的,這個(gè)值就是mPadding )。

mBarSpace 是兩個(gè)小矩形之間的距離,mRadius 是狀態(tài)1中圓的半徑,mWidth 、mWidth 是狀態(tài)1中大矩形的寬高。(這些參數(shù)都是通過(guò)上面三個(gè)參數(shù)計(jì)算出來(lái)的)

同樣的在初始化這一步,初始化畫筆和兩個(gè)小矩形(半三角)Path

mBgPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mBgPaint!!.color = mBgColor
mBgPaint!!.style = Paint.Style.FILL

mBarPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mBarPaint!!.color = mBarColor
mBarPaint!!.style = Paint.Style.FILL

mLeftPath = Path()
mRightPath = Path()

同時(shí)通過(guò)動(dòng)畫使矩形變成三角的參數(shù) mProgress,在onDraw中會(huì)用到

4.測(cè)量控件

在onMeasure方法中測(cè)量控件的寬高,主要是在xml中wrap_content或者具體數(shù)值的時(shí)候

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec)
 val widthMode = MeasureSpec.getMode(widthMeasureSpec)
 val heightMode = MeasureSpec.getMode(heightMeasureSpec)
 val measureWidth = MeasureSpec.getSize(widthMeasureSpec)
 val measureHeight = MeasureSpec.getSize(heightMeasureSpec)

 when(widthMode){
  MeasureSpec.EXACTLY ->{
  mWidth = Math.min(measureWidth,measureHeight).toFloat()
  mHeight = Math.min(measureWidth,measureHeight).toFloat()
  setMeasuredDimension(mWidth.toInt(),mHeight.toInt())
  }

  MeasureSpec.AT_MOST -> {
  mWidth = mRadius * 2
  mHeight = mRadius * 2
  setMeasuredDimension(mWidth.toInt(),mHeight.toInt())
  }

  MeasureSpec.UNSPECIFIED -> {

  }
 }

 }

5.繪制

override fun onDraw(canvas: Canvas?) {
 super.onDraw(canvas)
 //需要重新設(shè)置,否則畫出來(lái)的圖形會(huì)保留上一次的
 mLeftPath!!.rewind()
 mRightPath!!.rewind()

 mRadius = mWidth.div(2)
 //先畫一個(gè)圓
 canvas!!.drawCircle(mWidth.div(2),mHeight.div(2),mRadius,mBgPaint)

 //核心代碼
 //順時(shí)針
 if(isClockWise){
  mLeftPath!!.moveTo(mPadding + (mBarWidth + mBarSpace.div(2)) * mProgress ,mPadding)
  mLeftPath!!.lineTo(mPadding ,mPadding + mBarHeight)
  mLeftPath!!.lineTo(mPadding + mBarWidth + mBarSpace.div(2) * mProgress,mPadding + mBarHeight)
  mLeftPath!!.lineTo(mPadding + mBarWidth + mBarSpace.div(2) * mProgress,mPadding)
  mLeftPath!!.close()

  mRightPath!!.moveTo(mPadding + mBarWidth + mBarSpace - mBarSpace.div(2) * mProgress,mPadding)
  mRightPath!!.lineTo(mPadding + mBarWidth + mBarSpace - mBarSpace.div(2) * mProgress,mPadding + mBarHeight)
  mRightPath!!.lineTo(mPadding + mBarWidth * 2 + mBarSpace ,mPadding + mBarHeight)
  mRightPath!!.lineTo(mPadding + mBarWidth * 2 + mBarSpace - (mBarWidth + mBarSpace.div(2)) * mProgress,mPadding)
  mRightPath!!.close()
 }
 //逆時(shí)針
 else{
  mLeftPath!!.moveTo(mPadding,mPadding)
  mLeftPath!!.lineTo(mPadding + (mBarWidth + mBarSpace.div(2)) * mProgress,mPadding + mBarHeight)
  mLeftPath!!.lineTo(mPadding + mBarWidth + mBarSpace.div(2) * mProgress,mPadding + mBarHeight)
  mLeftPath!!.lineTo(mPadding + mBarWidth + mBarSpace.div(2) * mProgress,mPadding)
  mLeftPath!!.close()

  mRightPath!!.moveTo(mPadding + mBarWidth + mBarSpace - mBarSpace.div(2) * mProgress,mPadding)
  mRightPath!!.lineTo(mPadding + mBarWidth + mBarSpace - mBarSpace.div(2) * mProgress,mPadding + mBarHeight)
  mRightPath!!.lineTo(mPadding + mBarWidth * 2 + mBarSpace - (mBarWidth + mBarSpace.div(2)) * mProgress,mPadding + mBarHeight)
  mRightPath!!.lineTo(mPadding + mBarWidth * 2 + mBarSpace,mPadding)
  mRightPath!!.close()
 }

 var corner = 0
 if(isClockWise){
  corner = 90
 }else{
  corner = -90
 }

 val rotation = corner * mProgress
 //旋轉(zhuǎn)畫布
 canvas.rotate(rotation,mWidth.div(2),mHeight.div(2))

 canvas.drawPath(mLeftPath!!,mBarPaint)
 canvas.drawPath(mRightPath!!,mBarPaint)
 }

如何實(shí)現(xiàn)自定義View之播放暫停控件

通過(guò)這張圖來(lái)看一下核心代碼(順時(shí)針)
A點(diǎn)的坐標(biāo)(mPadding + (mBarWidth + mBarSpace.div(2)) * mProgress ,mPadding)
mPadding 是小矩形距離大矩形的距離,A點(diǎn)最終會(huì)到F點(diǎn),兩者相差一個(gè)矩形 + 兩個(gè)矩形間隔/2的距離(就是 mBarWidth + mBarSpace.div(2) 的距離),通過(guò)乘以一個(gè)從0到1的mProgress的變化即可
同理可得 D到F,B到E,C到E的變化坐標(biāo)

右側(cè)的矩形也是如此計(jì)算,如果是逆時(shí)針旋轉(zhuǎn),三角形是倒過(guò)來(lái)的,原理也是一樣的

6.動(dòng)畫

上面提到過(guò)我們需要一個(gè)從0到1的mProgress的變化(從播放到暫停),或者需要一個(gè)從1到0的mProgress(從暫停到播放)

動(dòng)畫核心代碼如下:

val valueAnimator = ValueAnimator.ofFloat(if (isPlaying) 1f else 0f, if (isPlaying) 0f else 1f)
valueAnimator.duration = 200
 valueAnimator.addUpdateListener {
 mProgress = it.animatedValue as Float
 invalidate()
 }

 return valueAnimator

mProgress 不斷地變化,然后調(diào)用invalidate(),不斷地調(diào)用onDraw()方法

7.監(jiān)聽

setOnClickListener {
 if(isPlaying){
 pause()
 mPlayPauseListener!!.pause()
 }else{
 play()
 mPlayPauseListener!!.play()
 }
}

private fun play() {
 getAnimator().cancel()
 setPlaying(true)
 getAnimator().start()
 }

private fun pause() {
 getAnimator().cancel()
 setPlaying(false)
 getAnimator().start()
}

mPlayPauseListener是對(duì)外提供的接口,可以在Activity中拿到播放或者暫停的狀態(tài),以供我們下一步的操作

8.使用

最后附上這個(gè)自定義View目前有的屬性:

app:barHeight="30dp"//矩形條的寬度
app:barWidth="10dp"//矩形條的高度
app:barPadding="20dp"//矩形條距離原點(diǎn)(邊界)的距離
app:barClockWise="true"//是否是順時(shí)針轉(zhuǎn)動(dòng)
app:barPlayingState="false"//默認(rèn)的狀態(tài),播放或者暫停
app:barBgColor="@color/colorRed"//控件背景色
app:barColor="@color/black"//按鈕顏色

在Activity或者Fragment中的使用:

 val playPauseView = findViewById<PlayPauseView>(R.id.play_pause_view)
 //控件的點(diǎn)擊事件
 playPauseView.setPlayPauseListener(this)

 //需要實(shí)現(xiàn)的方法
 override fun play() {
 Toast.makeText(this,"現(xiàn)在處于播放狀態(tài)",Toast.LENGTH_SHORT).show()
 }

 override fun pause() {
 Toast.makeText(this,"現(xiàn)在處于暫停狀態(tài)",Toast.LENGTH_SHORT).show()
 }

至此,這個(gè)自定義View大致上完成了,還有一些細(xì)節(jié)就不再這里細(xì)說(shuō)了。如果你有興趣深入了解,可以看一下這里:自定義View集合中的PlayPauseView,如果能隨手點(diǎn)個(gè)Star也是極好的。

以上是“如何實(shí)現(xiàn)自定義View之播放暫停控件”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

新聞標(biāo)題:如何實(shí)現(xiàn)自定義View之播放暫停控件-創(chuàng)新互聯(lián)
文章路徑:http://www.chinadenli.net/article38/diddsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站標(biāo)簽優(yōu)化小程序開發(fā)手機(jī)網(wǎng)站建設(shè)電子商務(wù)網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)