美文网首页
Android 自定义View - PathMeasure

Android 自定义View - PathMeasure

作者: 改名_f64e | 来源:发表于2021-04-13 14:50 被阅读0次

    Api

    /*
      设置path
      path : path对象
      forceClosed : 是否闭合(获取长度是需要)
      (例如一个半圆,不闭合长度是周长的一般,闭合是周长的一半+直径)
    */
    public void setPath(Path path, boolean forceClosed)
    
    /*
      获取路径的长度(闭合和不闭合的长度不一样)
      如果有两个线段,他们之间不相连,那么长度只是第一个线段的,不是两个线段相加
    */
    public float getLength()
    
    /*
      是否是闭合
    */
    public boolean isClosed()
    
    /*
      指定到下一段线段
      当有两个线段,他们不相连的时候,通过这个方法,可以指定到下一段线段
    */
    public boolean nextContour()
    
    测试代码 : 
            mPaint.strokeWidth = 10f
            mPaint.style = Paint.Style.STROKE
            mPath.moveTo(100f, 500f)
            mPath.lineTo(800f, 500f)
    
            mPath.moveTo(100f, 800f)
            mPath.lineTo(900f, 800f)
            mPathMeasure.setPath(mPath, false)
            SystemLog.log("length = ${mPathMeasure.length}")
            mPathMeasure.nextContour()
            SystemLog.log("length = ${mPathMeasure.length}")
    
    System.out: length = 700.0
    System.out: length = 800.0
    
    
    1618297945(1).png
    /*
      distance: 距离Path起始点的距离,取值范围0 <= distance <= getLength()
      pos[]: distance在path上的坐标,即pos[]存的该点的坐标x,y值
      tan[]: distance在path上对应坐标点在path上的方向,tan[0]是邻边边长,tan[1]是对边边长。
              通过Math.atan2(tan[1], tan[0])*180.0/Math.PI 可以得到正切角的弧度值
    */
    public boolean getPosTan(float distance, float pos[], float tan[])
    测试代码:
        private val mRegion: Region = Region()
        private val mPaint: Paint = Paint()
        private val mPath: Path = Path()
        private val mPathMeasure: PathMeasure = PathMeasure()
        private val mPos: FloatArray = FloatArray(2)
        private val mTan: FloatArray = FloatArray(2)
        private var mDistance: Float = 0f
        private var mLength: Float = 0f
        private lateinit var mBitmap: Bitmap
        private val mMatrix: Matrix = Matrix()
        override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    
            mPaint.color = Color.GREEN
            mPaint.strokeWidth = 10f
            mPaint.style = Paint.Style.STROKE
            mPath.addCircle(measuredWidth / 2f, measuredHeight / 2f, 200f, Path.Direction.CW)
            mPathMeasure.setPath(mPath, false)
            mLength = mPathMeasure.length
            mPathMeasure.getPosTan(mDistance, mPos, mTan)
            SystemLog.log("resources = $resources")
            mBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_plane)
        }
    
        override fun onDraw(canvas: Canvas?) {
            canvas?.drawPath(mPath, mPaint)
            canvas?.drawBitmap(mBitmap, mMatrix, mPaint)
            mPathMeasure.getPosTan(mDistance, mPos, mTan)
            mMatrix.reset()
            mMatrix.postRotate(
                (atan2(mTan[1].toDouble(), mTan[0].toDouble()) * 180.0 / Math.PI).toFloat() + 90,
                mBitmap.width / 2f, mBitmap.height / 2f
            )
            mMatrix.postTranslate(mPos[0] - mBitmap.width / 2, mPos[1] - mBitmap.height / 2)
            if (mDistance >= mLength) {
                mDistance = 0f
            } else {
                mDistance += 3
            }
            invalidate()
        }
    
    59052b8dc535cec349c62b95a3c21244[00_00_01--00_00_09].gif
    /*
      用于得到路径上某一长度的位置以及该位置的正切值的矩阵
      distance: 距离 Path 起点的长度,0 <= distance <= getLength
      matrix : 根据 falgs 封装好的matrix
      flags : 规定哪些内容会存入到matrix中
              PathMeasure.POSITION_MATRIX_FLAG(位置)
              PathMeasure.ANGENT_MATRIX_FLAG(正切)
    */
    public boolean getMatrix(float distance, Matrix matrix, int flags)
    在 getPosTan()方法中,我们通过数组获取其中的数据,最后还是封装到了matrix 中
    这个方法是直接封装到 matrix 中,不需要我们自己封装
    同时选中flags : PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.ANGENT_MATRIX_FLAG
    
    /*
      截取path路径上的一段数据
      startD : 开始位置(startD>=0&&startD<=length)
      stopD: 开始位置(stopD>startD &&stopD<=length)
      dst:一个新的path路径,截取后的数据存储在这里
              注意: 截取后的数据是添加到path中,不是替换(覆盖),如果你多次的截取,数据会不断的添加
     startWithMoveTo : 起点是否使用moveTo,
                       true : 起点还是原来path的起点
                       false : 会将截取出来的 Path 片段的起始点移动到 dst 的最后一个点,以保证 dst 的连续性
    */
    public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
    测试代码:
        private val mPaint: Paint = Paint()
        private val mPathCircle: Path = Path()
        private val mPathLine: Path = Path()
        private val mPathMeasureCircle: PathMeasure = PathMeasure()
        private val mPathMeasureLine: PathMeasure = PathMeasure()
        private var mStart: Float = 0f
        private var mLengthCircle: Float = 0f
        private var mLengthLine: Float = 0f
        private var mState: Boolean = true
    
        override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
            mPaint.strokeWidth = 10f
            mPaint.style = Paint.Style.STROKE
            mPathCircle.addCircle(w / 2f, h / 2f, 200f, Path.Direction.CW)
            mPathLine.moveTo(w / 2f + 200f, h / 2f)
            mPathLine.lineTo(w / 2f + 200f + 200f, h / 2f)
            mPathMeasureCircle.setPath(mPathCircle, false)
            mPathMeasureLine.setPath(mPathLine, false)
            mLengthCircle = mPathMeasureCircle.length
            mLengthLine = mPathMeasureLine.length
        }
    
        override fun onDraw(canvas: Canvas?) {
            canvas?.drawPath(mPathCircle, mPaint)
            canvas?.drawPath(mPathLine, mPaint)
            if (mState) {
                if (mStart < mLengthCircle) {
                    mPathCircle.reset()
                    mPathMeasureCircle.getSegment(mStart, mLengthCircle, mPathCircle, true)
                    mStart += 4
                } else if (mStart > mLengthCircle && mStart <= (mLengthCircle + mLengthLine)) {
                    mPathLine.reset()
                    mPathMeasureLine.getSegment(mStart - mLengthCircle, mLengthLine, mPathLine, true)
                    mStart += 4
                } else {
                    mState = false
                }
            } else {
                if (mStart >= mLengthCircle) {
                    mPathLine.reset()
                    mPathMeasureLine.getSegment(mStart - mLengthCircle, mLengthLine, mPathLine, true)
                    mStart -= 4
                } else if (mStart < mLengthCircle && mStart >= 0) {
                    mPathCircle.reset()
                    mPathMeasureCircle.getSegment(mStart, mLengthCircle, mPathCircle, true)
                    mStart -= 4
                } else {
                    mState = true
                }
            }
            invalidate()
        }
    
    a25e050fa91ca61aa6bc1fc6888fbfea[00_00_01--00_00_21].gif

    相关文章

      网友评论

          本文标题:Android 自定义View - PathMeasure

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