美文网首页
2019-12-23 自定义水波纹View

2019-12-23 自定义水波纹View

作者: Yangxy_Lazy | 来源:发表于2019-12-23 17:00 被阅读0次

    一、Path相关方法的运用

    • moveTo :移到下一次操作的起点位置

    • lineTo :添加上一个点到当前点之间的直线到Path

    • Close:连接第一个点连接到最后一个点,形成一个闭合区域

    • quadTo,cubicTo : (quadTo(x1,y1,x2,y2)中(x1,y1)为控制点的坐标,(x2,y2)为终点的坐标。分别为二次和三次贝塞尔曲线的方法

    二、对于Path的运用(贝塞尔曲线)

    • 贝塞尔曲线由一系列点来控制曲线状态的,这些点分为两类:数据点,控制点

    • 一阶贝塞尔曲线:仅有数据点(A和B),是一条直线

    • 二阶贝塞尔曲线:有两个数据点,一个控制点来描述的曲线

      image-20190308141902907.png
    • 三阶贝塞尔曲线:两个数据点,两个控制点
    image-20190308141943108.png

    三、绘制水波纹View

    
    class WaveView : View{
    
        constructor(context: Context) : super(context) {
            initAttrs(context, null)
            initPaintAndPath()
        }
    
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
            initAttrs(context, attrs)
            initPaintAndPath()
        }
    
        constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
            initAttrs(context, attrs)
            initPaintAndPath()
        }
    
    
        private lateinit var headPaint: Paint
        private lateinit var footPaint: Paint
        private lateinit var borderPaint: Paint
    
        private lateinit var headerPath: Path
        private lateinit var footPath: Path
        private lateinit var circlePath: Path // 主要用于剪切
    
        /**
         * 里波长
         */
        private var headWaveWidth: Float = 600f
    
        /**
         * 里波高度
         */
        private var headWaveHeight: Float = 45f
    
        /**
         * 里波的颜色
         */
        private var headPaintColor: Int = Color.parseColor("#ff0000")
    
    
        /**
         * 外波长
         */
        private var footWaveWidth: Float = 550f
    
        /**
         * 外波高度
         */
        private var footWaveHeight: Float = 35f
    
        /**
         * 外波颜色
         */
        private var footPaintColor: Int = Color.parseColor("#50ff0000")
    
        private var pxWidth: Float = 0f
        private var pxHeight: Float = 0f
    
        /**
         * 外围圆的线的宽度
         */
        private var borderWidth: Float = 10f
    
        /**
         * 外围圆的线的颜色
         */
        private var borderColor: Int = Color.parseColor("#ffffff")
    
        /**
         * 默认第一次重绘时里面波移动的距离
         */
        private var headOffset = 12f
    
        /**
         * 默认第一次重绘时外面波移动的距离
         */
        private var footOffset = 4f
    
        /**
         * 波的目前高度
         */
        private var mChangeY: Float = 0f
    
        /**
         * 波的数量
         */
        private var waveCount: Int = 0
    
        /**
         * 水位最终高度
         */
        private var finalY: Float = 0f
    
        /**
         * 重绘值波峰移动距离的和
         */
        private var moveSumHead: Float = 0f
        private var moveSumFoot: Float = 0f
    
        private var percent: Float = 0f //需要的最终百分比
        private var currentPercent: Float = 0f //当前的百分比
    
        private var timeOffset: Long = 0 // 重绘间隔时间
        private var drawFlag = false
    
    
        private fun initAttrs(mContext: Context, attrs: AttributeSet?) {
            if(attrs == null) return
            val typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.WaveView)
            borderWidth = typedArray.getDimension(R.styleable.WaveView_borderWidth, 10f)
    
            headPaintColor = typedArray.getColor(R.styleable.WaveView_headColor, Color.parseColor("#ff0000"))
            footPaintColor = typedArray.getColor(R.styleable.WaveView_footColor, Color.parseColor("#50ff0000"))
            borderColor = typedArray.getColor(R.styleable.WaveView_borderColor, Color.parseColor("#ffffff"))
    
            headWaveWidth = typedArray.getDimension(R.styleable.WaveView_headWaveWidth, 600f)
            headWaveHeight = typedArray.getDimension(R.styleable.WaveView_headWaveHeight, 45f)
    
            footWaveWidth = typedArray.getDimension(R.styleable.WaveView_footWaveWidth, 550f)
            footWaveHeight = typedArray.getDimension(R.styleable.WaveView_footWaveHeight, 35f)
    
            headOffset = typedArray.getDimension(R.styleable.WaveView_headOffset,12f)
            footOffset = typedArray.getDimension(R.styleable.WaveView_footOffset,4f)
    
            timeOffset = typedArray.getFloat(R.styleable.WaveView_timeOffset,2f).toLong()
    
            typedArray.recycle()
        }
    
        private fun initPaintAndPath() {
            headPaint = Paint(Paint.ANTI_ALIAS_FLAG)
            headPaint.color = headPaintColor
            headPaint.style = Paint.Style.FILL
    
            footPaint = Paint(Paint.ANTI_ALIAS_FLAG)
            footPaint.color = footPaintColor
            footPaint.style = Paint.Style.FILL
    
            borderPaint = Paint(Paint.ANTI_ALIAS_FLAG)
            borderPaint.color = borderColor
            borderPaint.strokeWidth = borderWidth
            borderPaint.style = Paint.Style.STROKE
    
            headerPath = Path()
            footPath = Path()
            circlePath = Path()
    
        }
    
        override fun onDraw(canvas: Canvas?) {
            Log.d("yxy", "onDraw $headWaveWidth" )
            //画边界圆
            drawBorder(canvas ?: return)
    
            //画波浪
            drawWave(canvas ?: return)
    
        }
    
        fun setPercent(percent: Float) {
            this.percent = percent
            //根据百分比设置最终水位
            finalY = (1 - percent) * pxHeight
        }
    
        override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
            super.onSizeChanged(w, h, oldw, oldh)
            pxWidth = measuredWidth.toFloat()
            pxHeight = measuredHeight.toFloat()
    
            mChangeY = Math.min(pxWidth, pxHeight)
            //计算波峰个数
            waveCount = Math.round(pxWidth / headWaveWidth + 1.5f) //保证至少2个波纹
        }
    
        /**
         * 需要圆形以外的不显示,所以需要用到剪切功能
         */
        private fun drawBorder(canvas: Canvas) {
            circlePath.reset()
    
            val radius = (pxWidth - 2 * borderWidth) / 2
            val centerX = radius + borderWidth
            val centerY = radius + borderWidth
    
            // 使用canvas的方法剪切一个圆形显示,其余地方不显示
            circlePath.addCircle(centerX, centerY, radius, Path.Direction.CW)
            canvas.clipPath(circlePath)
            canvas.drawCircle(centerX, centerY, radius, borderPaint)
    
        }
    
        private fun drawWave(canvas: Canvas?) {
            headerPath.reset()
            footPath.reset()
    
            headerPath.moveTo(-headWaveWidth, mChangeY)
            footPath.moveTo(-footWaveWidth, mChangeY)
    
            for (i in 0..waveCount) {
                //headWaveView路径 
                headerPath.quadTo(
                        (-headWaveWidth * 3 / 4) + i * headWaveWidth + moveSumHead,
                        mChangeY - headWaveHeight,
                        (-headWaveWidth / 2) + i * headWaveWidth + moveSumHead,
                        mChangeY
                )
    
                headerPath.quadTo(
                        (-headWaveWidth * 1 / 4) + i * headWaveWidth + moveSumHead,
                        mChangeY + headWaveHeight,
                        i * headWaveWidth + moveSumHead,
                        mChangeY
                )
    
                //footWave路径
                footPath.quadTo(
                        (-footWaveWidth * 3 / 4) + i * footWaveWidth + moveSumFoot,
                        mChangeY - footWaveHeight,
                        (-footWaveWidth / 2) + i * footWaveWidth + moveSumFoot,
                        mChangeY
                )
    
                footPath.quadTo(
                        (-footWaveWidth * 1 / 4) + i * footWaveWidth + moveSumFoot,
                        mChangeY + footWaveHeight,
                        i * footWaveWidth + moveSumFoot,
                        mChangeY
                )
    
            }
            //不断改变高度,实现逐渐水位上涨效果
            mChangeY -= 1
            if (mChangeY < finalY) mChangeY = finalY
            moveSumHead += headOffset
            moveSumFoot -= footOffset
    
            if (moveSumHead >= headWaveWidth) moveSumHead = 0F
            if (moveSumFoot <= 0) moveSumFoot = footWaveWidth
    
            headerPath.lineTo(pxWidth, pxHeight)
            headerPath.lineTo(0f, pxHeight)
            headerPath.close()
    
            footPath.lineTo(pxWidth, pxHeight)
            footPath.lineTo(0f, pxHeight)
            footPath.close()
    
            canvas?.drawPath(headerPath, headPaint)
            canvas?.drawPath(footPath, footPaint)
            currentPercent = 1 - mChangeY / pxHeight
            Log.d("yxy", "percent = $percent,currentPercent = $currentPercent")
            if(drawFlag)postInvalidateDelayed(timeOffset)
        }
    
        fun start(){
            drawFlag = true
            postInvalidate()
        }
    
    }
    
    
    //style
     <declare-styleable name="WaveView">
            <attr name="borderWidth" format="dimension"/>
            <attr name="headColor" format="color"/>
            <attr name="footColor" format="color"/>
            <attr name="borderColor" format="color"/>
            <attr name="headWaveWidth" format="dimension"/>
            <attr name="headWaveHeight" format="dimension"/>
            <attr name="footWaveWidth" format="dimension"/>
            <attr name="footWaveHeight" format="dimension"/>
            <attr name="headOffset" format="dimension"/>
            <attr name="footOffset" format="dimension"/>
            <attr name="timeOffset" format="float"/>
        </declare-styleable>
        
     //布局文件:
        <WaveView
                        android:id="@+id/waveView"
                        android:layout_width="64dp"
                        android:layout_height="64dp"
                        android:layout_centerInParent="true"
                        app:borderColor="@color/white"
                        app:borderWidth="2.5dp"
                        app:footColor="@color/color_value_ff7767"
                        app:footOffset="1dp"
                        app:footWaveHeight="7dp"
                        app:footWaveWidth="53dp"
                        app:headColor="@color/color_value_feb086"
                        app:headOffset="3dp"
                        app:headWaveHeight="5dp"
                        app:headWaveWidth="65dp"
                        app:timeOffset="50" />     

    相关文章

      网友评论

          本文标题:2019-12-23 自定义水波纹View

          本文链接:https://www.haomeiwen.com/subject/xjoznctx.html