Android自定义View 实现窗帘控件
生活随笔
收集整理的這篇文章主要介紹了
Android自定义View 实现窗帘控件
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
需求分析
這里只作簡單介紹,最后會分享源碼地址
實現
定義好所需要的自定義view屬性,這樣可以支持定制化的顏色以及滑塊圖標
<declare-styleable name="CurtainView"><!-- 窗簾最小范圍 --><attr name="min" format="integer" /><!-- 窗簾最大范圍 --><attr name="max" format="integer" /><!-- 窗簾當前進度 --><attr name="progress" format="integer" /><!-- 最小進度為窗簾兩邊的距離,應該要大于thumb一半的寬度--><attr name="min_progress" format="float" /><!-- 動畫時長 --><attr name="duration" format="integer" /><!-- 窗簾桿的顏色 --><attr name="curtain_rod_color" format="color" /><!-- 窗簾桿的高度 --><attr name="curtain_rod_height" format="dimension" /><!-- 窗簾葉子的顏色 --><attr name="curtain_leaves_color" format="color" /><!-- 窗簾滑塊 --><attr name="curtain_thumb" format="reference" /><!-- 窗簾類型 單開簾還是雙開簾 --><attr name="curtain_type" format="boolean" /></declare-styleable>編寫自定義View-CurtainView
val obtainStyledAttributes =context.obtainStyledAttributes(attributeSet, R.styleable.CurtainView)setMin(obtainStyledAttributes.getInt(R.styleable.CurtainView_min, mMin))setMax(obtainStyledAttributes.getInt(R.styleable.CurtainView_max, mMax))setDurtain(obtainStyledAttributes.getInt(R.styleable.CurtainView_duration, mDuration))setProgress(obtainStyledAttributes.getInt(R.styleable.CurtainView_progress, mProgress))setMinProgress(obtainStyledAttributes.getFloat(R.styleable.CurtainView_min_progress,minProgress))setProgressColor(obtainStyledAttributes.getInt(R.styleable.CurtainView_curtain_leaves_color,mProgressColor))setRodColor(obtainStyledAttributes.getInt(R.styleable.CurtainView_curtain_rod_color,mRodColor))setRodHeight(obtainStyledAttributes.getDimension(R.styleable.CurtainView_curtain_rod_height,rodHeight))setThumb(obtainStyledAttributes.getDrawable(R.styleable.CurtainView_curtain_thumb))setDouble(obtainStyledAttributes.getBoolean(R.styleable.CurtainView_curtain_type, isDoubled))obtainStyledAttributes.recycle()mPaint.strokeCap = Paint.Cap.ROUNDmPaint.style = Paint.Style.FILLrodPath = Path()//這里就是繪制窗簾桿所需的PathleftRect = RectF()rightRect = RectF()thumbRect = Rect()leftPath = Path()//窗簾葉左邊路徑rightPath = Path()//窗簾葉右邊路徑將定義的自定義屬性添加設置進來,并初始化好一些需要用到的東西,如畫筆,所需的矩形、路徑等.實際上難點主要在窗簾位置的計算,ondraw方法反而很簡單
mPaint.color = mProgressColorcanvas.drawPath(leftPath!!, mPaint)if (isDoubled) {canvas.drawPath(rightPath!!, mPaint)}mPaint.color = mRodColorcanvas.drawPath(rodPath, mPaint)mThumbDrawable?.apply {bounds = thumbRect!!draw(canvas)}因為窗簾桿的大小只需要計算一次,不需要修改,因此我們直接在onSizeChanged計算好就行了
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {super.onSizeChanged(w, h, oldw, oldh)mWidth = (w + paddingLeft + paddingRight).toFloat()mHeight = (h + paddingTop + paddingBottom).toFloat()middleLine = (mWidth / 2).toInt()thumbHeightHalf = mThumbDrawable!!.intrinsicHeight / 2//順時針方向添加圓角rodPath.addRoundRect(RectF(0F, 0F, mWidth, rodHeight),floatArrayOf(radius, radius, radius, radius, 0F, 0F, 0F, 0F),Path.Direction.CCW)computeProgressRect()}thumbHeightHalf 是我們設置滑塊的高度的一半,然后主要是窗簾葉位置的計算,代碼如下所示,矩形的大小根據設置的mMax,mProgress ,minProgress的三個值來決定
/*** 矩形的大小根據設置的 minProgress,mMax,mProgress 的三個值來決定*/private fun computeProgressRect() {var rectMargin = if (!isDoubled) {(mWidth - minProgress) / (mMax - mMin) * mProgress + minProgress} else {(middleLine - minProgress) / (mMax - mMin) * mProgress + minProgress}if (isDoubled) {//矩形邊距不能超過中線if (rectMargin > middleLine) {rectMargin = middleLine.toFloat()}}leftRect?.let {it.set(0F, rodHeight,rectMargin, mHeight)leftPath?.apply {//每次設置路徑前都需要先重置,否則不會生效reset()addRoundRect(it,floatArrayOf(0F, 0F, 0F, 0F, radius, radius, radius, radius),Path.Direction.CCW)}}if (isDoubled) {rectMargin =mWidth - minProgress - (mWidth - minProgress - middleLine) / (mMax - mMin) * mProgressif (rectMargin < middleLine) {rectMargin = middleLine.toFloat()}rightRect?.let {it.set(rectMargin,rodHeight,mWidth,mHeight)rightPath?.apply {//每次設置路徑前都需要先重置,否則不會生效reset()addRoundRect(it,floatArrayOf(0F, 0F, 0F, 0F, radius, radius, radius, radius),Path.Direction.CCW)}}}if (isDoubled) {thumbRect?.set((leftRect!!.right - thumbHeightHalf).roundToInt(),((mHeight - rodHeight) / 2 - thumbHeightHalf + rodHeight).toInt(),(leftRect!!.right + thumbHeightHalf).roundToInt(),((mHeight - rodHeight) / 2 + thumbHeightHalf + rodHeight).toInt())} else {//單開簾時需要判斷滑塊是否超出view的寬度thumbRect?.set(if (leftRect!!.right > mWidth - thumbHeightHalf) {(leftRect!!.right - thumbHeightHalf * 2).roundToInt()} else {(leftRect!!.right - thumbHeightHalf).roundToInt()},((mHeight - rodHeight) / 2 - thumbHeightHalf + rodHeight).toInt(),if (leftRect!!.right > mWidth - thumbHeightHalf) {(leftRect!!.right).roundToInt()} else {(leftRect!!.right + thumbHeightHalf).roundToInt()},((mHeight - rodHeight) / 2 + thumbHeightHalf + rodHeight).toInt())}}mProgress 需要根據手指滑動計算出來這里重寫onTouchEvent方法
override fun onTouchEvent(event: MotionEvent): Boolean {if (!isEnabled) {return false}when (event.action) {MotionEvent.ACTION_DOWN -> {moved = false//只有手指在滑塊中才能滑動mThumbDrawable?.let {if (it.bounds.contains(event.x.toInt(), event.y.toInt())) {isTouch = trueif (null != mOnProgressChangeListener) {mOnProgressChangeListener!!.onStartTrackingTouch(this)}}}}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {if (null != mOnProgressChangeListener && moved) {isTouch = falsemOnProgressChangeListener!!.onStopTrackingTouch(this)}}MotionEvent.ACTION_MOVE -> {var x = event.xif (x > minProgress && isTouch) {if (isDoubled) {if (x > middleLine) {x = middleLine.toFloat()}} else {if (x > mWidth) {x = mWidth}}moved = trueval ctrlProgress = if (isDoubled) {((x - minProgress) * (mMax - mMin) / (middleLine - minProgress)).toInt()} else {((x - minProgress) * (mMax - mMin) / (mWidth - minProgress)).toInt()}if (ctrlProgress != mProgress) {mProgress = ctrlProgresscomputeProgressRect()//滑動時計算矩形,然后刷新postInvalidate()if (null != mOnProgressChangeListener) {mOnProgressChangeListener!!.onProgressChanged(this, ctrlProgress, true)}}}}}return true}實現了上面兩步之后,現在的窗簾就可以根據手指滑動而移動了
然后我們給這個View添加上屬性動畫,當外部設置進度時,也能夠進行窗簾的移動了
到這里就已經實現了一個可以跟隨手指滑動而移動,并可以自定義窗簾桿、葉子、滑塊以及控制是單開還是雙開的窗簾了。
最后提供庫的使用,以及源碼地址,歡迎Star
使用
源碼中也有使用方法,可以直接查看
源碼地址鏈接: 點擊這里,歡迎Star
2022.07.04
- 添加新版本v1.0.2,支持設置圖片作為窗簾的葉子,具體修改訪問上面的github地址
CSDN下載地址
哈哈,終于寫完了,感謝看我文章的人,有幫助的,點個贊,給個Star啊
總結
以上是生活随笔為你收集整理的Android自定义View 实现窗帘控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在苹果iPhone或iPad上启用S
- 下一篇: iOS大神读源码