Android 自定义View -- 圆形进度条,文字旋转

转载请标明出处:http://blog.csdn.net/u012724947/article/details/53237191

最近公司招聘打个广告:
公司属于外企福利待遇好,
每周英语课,
关键时单身妹子多[色][色]
详情 [点击全栈JavaScript工程师]

英文版 《Full Stack JavaScript Developer》

Android 自定义View – 圆形进度条,文字旋转

作为一名Android开发人员从码农 -> 程序员 -> 工程师进步的过程中必然少不了一些重要的过程, 好久没有自定义View了也是最近项目需要 ,这是Android版本的定义,如果需要查看IOS请点击《 IOS Swift自定义View – 圆形进度条,文字旋转》 ,欢迎大家提出宝贵意见,共同学习和进步,文章暂时没写全,以后补上,需要代码联系本人谢谢
Android 自定义View -- 圆形进度条,文字旋转_第1张图片

效果展示

Android 自定义View -- 圆形进度条,文字旋转_第2张图片

分析

实现的方法有很多种,万变不离其宗, 我们学习的是方法而不是死记硬背,或者拿来主义

1. 我们先用代码在Android中绘制一个圆形

//创建画笔  
Paint paint = new Paint();
//设置红色
paint.setColor(Color.RED);
//设置画笔的锯齿效果。 true是去除, 画出的圆会更加光滑
paint.setAntiAlias(true);
//这是画圆形
canvas.drawCircle(100, 100, 100, paint);

2. 绘制一个矩形,然后在顶部绘制一个“+”,底部绘制一个“-”

// 设置矩形为灰色  
paint.setColor(Color.GRAY);
//设置矩形填满  
paint.setStyle(Paint.Style.FILL);
//绘制矩形 
canvas.drawRect(60, 90, 160, 100, paint);// 长方形  

//绘制文字
canvas.drawText("+", 10, 80, paint); 
canvas.drawText("-", 10, 80, paint); 

3. 分别绘制左右的小球

//绘制小球,和刚才画圆一样
canvas.drawCircle(10, 10, 10, paint);

4. 通过旋转计算滑动的长度(这里要考验大家的高中数学了 哈哈哈)

三角函数
Android 自定义View -- 圆形进度条,文字旋转_第3张图片

角度是如何计算呢(这里我们需要区分在第几象限)
我们监听手势的x,y坐标 (与圆心构成三角形,长a,高b)
计算 所以 tan角度 = b / a (第三象限) 其它的也一样
圆上的点基本可以表示
最近Android Studio 出现问题展示把它卸载了 先上swift3.0 的代码 原理都一样应该大家也可以看懂

func LeftRoundAction(_ sender: UIPanGestureRecognizer){
        if(CurrLeftProgress>=0 && CurrLeftProgress<=100){
            let translation = sender.translation(in: self)

            if(sender.state == UIGestureRecognizerState.possible){
            }else if(sender.state == UIGestureRecognizerState.began){
                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

            }else if(sender.state == UIGestureRecognizerState.changed){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.ended){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

                leftEX = translation.x + leftEX
                leftEY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.cancelled){
            }else if(sender.state == UIGestureRecognizerState.failed){
            }else if(sender.state == UIGestureRecognizerState.recognized){
            }

            //两种情况 y > r or y < r 计算角度 和 新的坐标

            var a:CGFloat=0;
            var b:CGFloat=0;

            if(leftY > centerY){
                a = leftY - centerY
                b = centerX - leftX
            }else{
                a = centerX - leftY
                b = centerY - leftX
            }

            let tanA = a / b;

            if(leftY > centerY){
                leftY = centerY + radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) - atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }else{
                leftY = centerY - radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) +  atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }
            leftX = centerX - radius * cos(atan(tanA)) - smallRoundR

            if(angleLeft >= startAngle && angleLeft <= endAngle){
                leftRound?.frame = CGRect(x: leftX, y: leftY, width: smallRoundR * 2, height: smallRoundR * 2)
                //change

                self.bar?.leftProgress(angleRight: angleRight, angleLeft: angleLeft)

                CurrLeftProgress = (angleLeft - startAngle) * maxLeftProgress / (endAngle - startAngle)

                if(CurrLeftProgress>100){
                    CurrLeftProgress = 100
                }else if(CurrLeftProgress<0){
                    CurrLeftProgress = 0
                }
            }
            print("\(TAG)   ------->2  CurrLeftProgress \(CurrLeftProgress)")

            if(sender.state == UIGestureRecognizerState.began){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.changed){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.ended){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }
        }
    }

5. 通过计算使小球只能在圆环上移动

画图不容易,还是喜欢在纸上用笔胡乱画
长(width) 高(height) 半径(r)
X坐标:± r * cos角度 + width / 2
Y坐标:± r * sin角度 + height / 2

func LeftRoundAction(_ sender: UIPanGestureRecognizer){
        if(CurrLeftProgress>=0 && CurrLeftProgress<=100){
            let translation = sender.translation(in: self)

            if(sender.state == UIGestureRecognizerState.possible){
            }else if(sender.state == UIGestureRecognizerState.began){
                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

            }else if(sender.state == UIGestureRecognizerState.changed){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.ended){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

                leftEX = translation.x + leftEX
                leftEY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.cancelled){
            }else if(sender.state == UIGestureRecognizerState.failed){
            }else if(sender.state == UIGestureRecognizerState.recognized){
            }

            //两种情况 y > r or y < r 计算角度 和 新的坐标

            var a:CGFloat=0;
            var b:CGFloat=0;

            if(leftY > centerY){
                a = leftY - centerY
                b = centerX - leftX
            }else{
                a = centerX - leftY
                b = centerY - leftX
            }

            let tanA = a / b;

            if(leftY > centerY){
                leftY = centerY + radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) - atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }else{
                leftY = centerY - radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) +  atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }
            leftX = centerX - radius * cos(atan(tanA)) - smallRoundR

            if(angleLeft >= startAngle && angleLeft <= endAngle){
                leftRound?.frame = CGRect(x: leftX, y: leftY, width: smallRoundR * 2, height: smallRoundR * 2)
                //change

                self.bar?.leftProgress(angleRight: angleRight, angleLeft: angleLeft)

                CurrLeftProgress = (angleLeft - startAngle) * maxLeftProgress / (endAngle - startAngle)

                if(CurrLeftProgress>100){
                    CurrLeftProgress = 100
                }else if(CurrLeftProgress<0){
                    CurrLeftProgress = 0
                }
            }
            print("\(TAG)   ------->2  CurrLeftProgress \(CurrLeftProgress)")

            if(sender.state == UIGestureRecognizerState.began){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.changed){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.ended){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }
        }
    }

说明:上述教大家一些图形的基本绘制,和一些原理,帮助大家学习,真正的这种代码和效果在下面。

全部代码

//
//  SeekBarView.swift
//  Pacsafe
//
//  Created by NOA-Labs on 11/30/16.
//  Copyright © 2016 NOA-Labs. All rights reserved.
//

import UIKit

class SeekBarView: UIView {

    let TAG:String = "SeekBarView"

    @IBOutlet var contentView: UIView!

    var gestureRight:UIPanGestureRecognizer? = nil
    var gestureLeft:UIPanGestureRecognizer? = nil

    var seekbarDelegate:SeekBarViewDelegate? = nil


    var leftRound:RoundView?
    var rightRound:RoundView?

    var bar:BarView?

    //小球的半径
    let smallRoundR:CGFloat = 21

    //起始角度
    let startAngle:CGFloat = 0.08
    let endAngle:CGFloat = 3.0

    //右边的角度
    var angleRight:CGFloat = 0
    //左边的角度
    var angleLeft:CGFloat = 0
    //长度
    var width:CGFloat = 0
    //宽度
    var height:CGFloat = 0

    var leftX:CGFloat = 0,leftY:CGFloat = 0;
    var leftEX:CGFloat = 0,leftEY:CGFloat = 0;

    var rightX:CGFloat = 0,rightY:CGFloat = 0;
    var rightEX:CGFloat = 0,rightEY:CGFloat = 0;

    var centerX:CGFloat = 0,centerY:CGFloat = 0;

    var radius:CGFloat = 0

    let maxLeftProgress:CGFloat = 100
    let maxRightProgress:CGFloat = 100

    var CurrLeftProgress:CGFloat = 67
    var CurrRightProgress:CGFloat = 70


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initFromXIB()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initFromXIB()
    }

    func initFromXIB() {
        let bundle = Bundle(for: type(of: self))
        //nibName是你定义的xib文件名
        let nib = UINib(nibName: "SeekBarView", bundle: bundle)
        contentView = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
        contentView.frame = bounds

        gestureRight = UIPanGestureRecognizer(target: self, action: #selector(SeekBarView.RightRoundAction))

        gestureLeft = UIPanGestureRecognizer(target: self, action: #selector(SeekBarView.LeftRoundAction))

        self.addSubview(contentView)

        print("\(TAG)   ------->  initFromXIB \(self.frame)")

        // 根据当前的进度 计算应该旋转的角度
        angleRight=startAngle + (endAngle - startAngle) / maxRightProgress * CurrRightProgress
        angleLeft=startAngle + (endAngle - startAngle) / maxLeftProgress * CurrLeftProgress
    }

    func RightRoundAction(_ sender: UIPanGestureRecognizer){

        if(CurrRightProgress>=0 && CurrRightProgress<=100){
            let translation = sender.translation(in: self)

            if(sender.state == UIGestureRecognizerState.possible){
            }else if(sender.state == UIGestureRecognizerState.began){
                rightX = translation.x + rightEX
                rightY = translation.y + rightEY
            }else if(sender.state == UIGestureRecognizerState.changed){
                rightX = translation.x + rightEX
                rightY = translation.y + rightEY
            }else if(sender.state == UIGestureRecognizerState.ended){
                rightX = translation.x + rightEX
                rightY = translation.y + rightEY

                rightEX = translation.x + rightEX
                rightEY = translation.y + rightEY
            }else if(sender.state == UIGestureRecognizerState.cancelled){
            }else if(sender.state == UIGestureRecognizerState.failed){
            }else if(sender.state == UIGestureRecognizerState.recognized){
            }

            //两种情况 y > r or y < r 计算角度 和 新的坐标

            var a:CGFloat=0;
            var b:CGFloat=0;

            if(rightY > centerY){
                a = rightY - centerY
                b = rightX - centerX
            }else{
                a = centerY - rightY
                b = rightX - centerX
            }

            let tanA = a / b;

            if(rightY > centerY){
                rightY = centerY + radius * sin(atan(tanA)) - smallRoundR

                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) - atan(tanA)

                if (abs(self.angleRight - angle) < 0.3 || self.angleRight == 0){
                    self.angleRight = angle
                }else{
                    return
                }
            }else{
                rightY = centerY - radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) + atan(tanA)

                if (abs(self.angleRight - angle) < 0.3 || self.angleRight == 0){
                    self.angleRight = angle
                }else{
                    return
                }
            }
            rightX = centerX + radius * cos(atan(tanA)) - smallRoundR



            if(angleRight >= startAngle && angleRight <= endAngle){
                rightRound?.frame = CGRect(x:rightX, y:rightY, width: smallRoundR * 2, height: smallRoundR * 2)

                bar?.leftProgress(angleRight: angleRight, angleLeft: angleLeft)
            }


            CurrRightProgress = (angleRight - startAngle) * maxRightProgress / (endAngle - startAngle)

            print("\(TAG)   ------->1  CurrRightProgress \(CurrRightProgress)")
            if(CurrRightProgress>100){
                CurrRightProgress = 100
            }else if(CurrRightProgress<0){
                CurrRightProgress = 0
            }

            if(sender.state == UIGestureRecognizerState.began){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.REIGHT, progress: CurrRightProgress)
            }else if(sender.state == UIGestureRecognizerState.changed){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.REIGHT, progress: CurrRightProgress)
            }else if(sender.state == UIGestureRecognizerState.ended){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.REIGHT, progress: CurrRightProgress)
            }
        }
    }

    func LeftRoundAction(_ sender: UIPanGestureRecognizer){
        if(CurrLeftProgress>=0 && CurrLeftProgress<=100){
            let translation = sender.translation(in: self)

            if(sender.state == UIGestureRecognizerState.possible){
            }else if(sender.state == UIGestureRecognizerState.began){
                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

            }else if(sender.state == UIGestureRecognizerState.changed){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.ended){

                leftX = translation.x + leftEX
                leftY = translation.y + leftEY

                leftEX = translation.x + leftEX
                leftEY = translation.y + leftEY
            }else if(sender.state == UIGestureRecognizerState.cancelled){
            }else if(sender.state == UIGestureRecognizerState.failed){
            }else if(sender.state == UIGestureRecognizerState.recognized){
            }

            //两种情况 y > r or y < r 计算角度 和 新的坐标

            var a:CGFloat=0;
            var b:CGFloat=0;

            if(leftY > centerY){
                a = leftY - centerY
                b = centerX - leftX
            }else{
                a = centerX - leftY
                b = centerY - leftX
            }

            let tanA = a / b;

            if(leftY > centerY){
                leftY = centerY + radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) - atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }else{
                leftY = centerY - radius * sin(atan(tanA)) - smallRoundR
                let angle = CGFloat(M_PI_2 - M_PI_2 * 0.025) +  atan(tanA)

                if (abs(self.angleLeft - angle) < 0.3 || self.angleLeft == 0){
                    self.angleLeft = angle
                }else{
                    return
                }
            }
            leftX = centerX - radius * cos(atan(tanA)) - smallRoundR

            if(angleLeft >= startAngle && angleLeft <= endAngle){
                leftRound?.frame = CGRect(x: leftX, y: leftY, width: smallRoundR * 2, height: smallRoundR * 2)
                //change

                self.bar?.leftProgress(angleRight: angleRight, angleLeft: angleLeft)

                CurrLeftProgress = (angleLeft - startAngle) * maxLeftProgress / (endAngle - startAngle)

                if(CurrLeftProgress>100){
                    CurrLeftProgress = 100
                }else if(CurrLeftProgress<0){
                    CurrLeftProgress = 0
                }
            }
            print("\(TAG)   ------->2  CurrLeftProgress \(CurrLeftProgress)")

            if(sender.state == UIGestureRecognizerState.began){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.changed){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }else if(sender.state == UIGestureRecognizerState.ended){
                self.seekbarDelegate?.fetchChangeProgress(direction: SeekBarViewDirectionStyle.LEFT, progress: CurrLeftProgress)
            }
        }
    }

    override func draw(_ rect: CGRect) {
        print("\(TAG)   ------->2  draw \(self.frame)")
    }

    override func draw(_ layer: CALayer, in ctx: CGContext) {

        self.width = frame.width
        self.height = frame.height


        // 绘制静态的背景
        let progress = ProgressBarView(frame:CGRect.init(x: 0, y: 0, width:self.width, height:self.height))
        self.contentView.addSubview(progress)


        //根据当前的角度 计算当前的坐标

        if(self.width>self.height){
            self.radius = self.height / 2
        }else{
            self.radius = self.width / 2
        }

        self.leftX = self.width / 2 - self.radius * sin(angleLeft) - smallRoundR
        //Y轴需要区分上半部分和下半部分
        if(angleLeft<1.504){// 下半部分
            self.leftY = self.height / 2 + self.radius * cos(angleLeft + CGFloat(M_PI_2 * 0.025)) - smallRoundR
        }else{//上半部分
            self.leftY = self.height / 2 - self.radius * cos(CGFloat(M_PI) - angleLeft - CGFloat(M_PI_2 * 0.025)) - smallRoundR
        }

        self.rightX = self.width / 2 + self.radius * sin(angleRight) - smallRoundR

        //Y轴需要区分上半部分和下半部分
        if(angleRight<1.504){// 下半部分
            self.rightY = self.height / 2 + self.radius * cos(angleRight + CGFloat(M_PI_2 * 0.025)) - smallRoundR
        }else{//上半部分
            self.rightY = self.height / 2 - self.radius * cos(CGFloat(M_PI) - angleRight - CGFloat(M_PI_2 * 0.025)) - smallRoundR
        }

        print("\(TAG)   ------->1  angleLeft \(self.angleLeft)    angleRight:\(angleRight)")

        leftEX = leftX
        leftEY = leftY

        rightEX = rightX
        rightEY = rightY


        centerY = self.height / 2
        centerX = self.width / 2

        print("\(TAG)   ------->1  frame:\(self.frame)")

        // 绘制动态的当前进度
        if(bar == nil){
            bar = BarView(frame:CGRect.init(x: 0, y: 0, width: self.width, height: self.height))
            bar?.setProgress(angleRight:angleRight,angleLeft:angleLeft)
            bar?.backgroundColor = UIColor.clear
            self.contentView.addSubview(bar!)
        }else{
            bar?.setProgress(angleRight:angleRight,angleLeft:angleLeft)
        }

        //draw round
        if(leftRound == nil){
            leftRound = RoundView(frame:CGRect(x: leftX, y: leftY, width: smallRoundR * 2, height: smallRoundR * 2))
            leftRound?.backgroundColor=UIColor.clear
            self.addSubview(leftRound!)

            leftRound?.isUserInteractionEnabled = true
            leftRound?.addGestureRecognizer(gestureLeft!)
        }else{
            leftRound?.frame = CGRect(x: leftX, y: leftY, width: smallRoundR * 2, height: smallRoundR * 2)
        }

        if(rightRound == nil){
            rightRound = RoundView(frame:CGRect(x: rightX, y: rightY, width: smallRoundR * 2, height: smallRoundR * 2))
            self.addSubview(rightRound!)
            rightRound?.backgroundColor=UIColor.clear

            rightRound?.isUserInteractionEnabled = true
            rightRound?.addGestureRecognizer(gestureRight!)
        }else{
            rightRound?.frame = CGRect(x: rightX, y: rightY, width: smallRoundR * 2, height: smallRoundR * 2)
        }
    }
}

Android自定义View圆形进度条 Demo下载
[email protected]

你可能感兴趣的:(《Android开发笔记》)