有时候UIKit的标准控件并不能满足我们的需求,因此我们可以通过自定义控件得到满足我们需求的控件,例如这篇文章将教你如何自定义一个圆形的进度条,并且用户可以通过拖动进度条上的手柄来改变进度值。主要参考了这篇文章:HOW TO BUILD A CUSTOM CONTROL IN IOS。广告时间:我的一个免费APP:午睡闹钟 使用了这个控件,欢迎大家在AppStore搜索午睡闹钟进行下载使用。

我们的自定义控件继承自UIControl类,它是UIView的子类,是所有UIKit控件(UIButton, UISlider, UISwitch等等等)的父类。UIControl实例的作用是创建相应的逻辑来将action分发到相应的target,90%的情况下,它会根据自身的状态(例如Highlighted, Selected和Disabled等)来绘制用户界面。

UIControl主要完成三个重要任务:

  • 绘制用户界面
  • 跟踪用户的交互操作
  • Target-Action模式

因此,对于这篇文章中要完成的圆形进度条,我们将要完成以下任务:

绘制一个用户可以通过拖动手柄滑块来进行交互的用户界面,用户的操作会被转化为target对应的actions,控件将滑块的frame origin转换为0-360之间的一个值,并用于target/action上。下面将分三步进行讲解,这三步对应上面提到的三个重要任务。

1.1绘制用户界面

如图,我们将通过Core Graphics来绘制灰色的进度条背景、红色的进度条、滑块手柄,关于Core Graphics的基础知识,本文不作详细介绍.。

- (void)drawRect:(CGRect)rect {[super drawRect:rect];CGContextRef context = UIGraphicsGetCurrentContext();//1.绘制灰色的背景CGContextAddArc(context, self.frame.size.width/2, self.frame.size.height/2, radius, 0, M_PI*2, 0);[[UIColor grayColor] setStroke];CGContextSetLineWidth(context, _lineWidth);CGContextSetLineCap(context, kCGLineCapButt);CGContextDrawPath(context, kCGPathStroke);//2.绘制进度CGContextAddArc(context, self.frame.size.width/2, self.frame.size.height/2,radius,0, ToRad(_angle), 0);[[UIColor redColor] setStroke];CGContextSetLineWidth(context, _lineWidth);CGContextSetLineCap(context, kCGLineCapRound);CGContextDrawPath(context, kCGPathStroke);//3.绘制拖动小块CGPoint handleCenter =  [self pointFromAngle: (self.angle)];CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 3,[UIColor blueColor].CGColor);[[UIColor redColor] setStroke];CGContextSetLineWidth(context, _lineWidth*2);CGContextAddEllipseInRect(context, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth*2, _lineWidth*2));CGContextDrawPath(context, kCGPathStroke);
}

其中pointFromAngle方法是从给定的角度得到圆环上对应的经纬度,只是简单的使用了一下基本的三角函数关系:

-(CGPoint)pointFromAngle:(int)angleInt{//中心点CGPoint centerPoint = CGPointMake(self.frame.size.width/2 - _lineWidth, self.frame.size.height/2 - _lineWidth);//根据角度得到圆环上的坐标CGPoint result;result.y = round(centerPoint.y + radius * sin(ToRad(angleInt))) ;result.x = round(centerPoint.x + radius * cos(ToRad(angleInt)));return result;
}

1.2跟踪用户的交互操作

完成了1.1,现在我们已经绘制好了用户界面,但是它还不能响应我们的触摸事件。我们只要重写(override)UIControl的三个方法,就可以跟踪用户操作。

1.2.1开始跟踪触摸事件

当用户在UIControl的bound内进行触摸,beginTrackingWithTouch方法会被调用,此方法会返回BOOL类型,返回Yes表示要继续跟踪触摸事件。

-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{[super beginTrackingWithTouch:touch withEvent:event];return YES;
}

1.2.2 持续跟踪触摸时间

上面的方法返回了Yes,表示要继续跟踪触摸事件,所以当用户在屏幕上拖动时,continueTrackingWithTouch会被调用,该方法返回的BOOL值表示是否继续跟踪touch事件。通过该方法我们将根据用户触摸的位置更新手柄的位置。

-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{[super continueTrackingWithTouch:touch withEvent:event];//获取触摸点CGPoint lastPoint = [touch locationInView:self];//使用触摸点来移动小块[self movehandle:lastPoint];//发送值改变事件[self sendActionsForControlEvents:UIControlEventValueChanged];return YES;
}

其中,我们调用了movehandle:方法来更新滑动手柄的位置:

-(void)movehandle:(CGPoint)lastPoint{//获得中心点CGPoint centerPoint = CGPointMake(self.frame.size.width/2,self.frame.size.height/2);//计算中心点到任意点的角度float currentAngle = AngleFromNorth(centerPoint,lastPoint,NO);int angleInt = floor(currentAngle);//保存新角度self.angle = angleInt;//重新绘制[self setNeedsDisplay];
}

AngleFromNorth(CGPoint p1,CGPoint p2,BOOL flipped)方法是计算中心点到任意点的角度,

是从苹果是示例代码clockControl中拿来的函数,比较复杂(数学没学好...),就直接当作苹果提供的一个方法来调用就行。

static inline float AngleFromNorth(CGPoint p1, CGPoint p2, BOOL flipped) {CGPoint v = CGPointMake(p2.x-p1.x,p2.y-p1.y);float vmag = sqrt(SQR(v.x) + SQR(v.y)), result = 0;v.x /= vmag;v.y /= vmag;double radians = atan2(v.y,v.x);result = ToDeg(radians);return (result >=0  ? result : result + 360.0);
}

1.2.3结束跟踪

当结束跟踪时,这个方法会被调用,我们的例子中不需要override这个方法

现在,圆形滑块控件可以工作了,拖动滑动手柄看看。

1.3 Target-Action模式

如果希望自己定制的控件与UIControl行为保持一致,那么当控件的值发生变化时,需要进行通知处理:使用sendActionsForControlEvents方法,并制定特定的事件类型,值改变对应的事件一般是UIControlEventValueChanged。

苹果已经预定义了许多事件类型(Xcode中,在UIControlEventValueChanged上cmd + 鼠标单击)。如果你的控件是继承自UITextField,那么我们可能会对UIControlEventEdigitingDidBegin感兴趣,如果要做一个touch Up action,可以使用UIControlTouchUpInside。在本文前部分的continueTrackingWithTouch方法里面,我们已经调用了sendActionsForControlEvents方法。这样处理之后,当控件值发生变化时,每一个对象(观察者——注册该事件)都会收到响应的通知。

2.使用自定义控件

除了通过用户触摸事件来改变进度,有时我们还想通过代码进行修改,我们只要自己实现存储角度的属性angle的set方法:
-(void)changeAngle:(int)angle{_angle = angle;[self sendActionsForControlEvents:UIControlEventValueChanged];[self setNeedsDisplay];
}

好了,现在我们在viewcontroller中使用我们的控件:

    JXCircleSlider *slider = [[JXCircleSlider alloc] initWithFrame:CGRectMake(0, 0, 250, 250)];slider.center = self.view.center;[slider addTarget:self action:@selector(newValue:) forControlEvents:UIControlEventValueChanged];[slider changeAngle:120];[self.view addSubview:slider];

我们先进行初始化,然后设置为居中显示,注册了值改变响应事件,当进度值改变时,会调用一下方法

-(void)newValue:(JXCircleSlider*)slider{NSLog(@"newValue:%d",slider.angle);
}

项目源代码:https://github.com/dolacmeng/JXCircleSlider

最终效果如下:

【iOS】自定义控件入门:可拖动的环形进度相关推荐

  1. iOS通过CAShapeLayer和UIBezierPath画环形进度条

    UIBezierPath可以绘制矢量路径,而CAShapeLayer是Layer的子类,可以在屏幕进行绘制,本文主要思想是:CAShapeLayer按照UIBezierPath的矢量路径进行绘制. 效 ...

  2. iOS 自定义控件 progressView(环形进度条)

    转帖:http://blog.csdn.net/xiangzhang321/article/details/42688133 之前做项目的时候有用到环形进度条,先是在网上找了一下第三方控件,发现好用是 ...

  3. WPF自定义控件(教程含源码)-圆形进度条、环形进度条

    使用环形进度条显示用量百分比 控件效果如下 控件的关键属性如下: Background:控制背景圆环的原色. Stroke:控制进度圆环颜色.以及中间文本颜色. Value:进度百分比,double类 ...

  4. 自定义控件——环形进度条

    系统提供的环形进度条无法显示进度,且不会停止转动,所以要用到能显示进度的进度条时,只能自己定义一个控件. API Demos里面有提供类似的画法,API Demos --> Graphics - ...

  5. iOS 一分钟学会环形进度条

    有几篇博客写到了怎么实现环形进度条,大多是使用Core Graph来实现,实现比较麻烦且效率略低.只是一个小小的进度条而已,我们当然是用最简单而且效率高的方式来实现. 先制作一个不带颜色渐变的进度条 ...

  6. [Swift通天遁地]一、超级工具-(2)制作美观大方的环形进度条

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  7. 进度条上的小圆点怎么做_傲视网:【AE教程】如何制作环形进度条(第一讲)...

    原标题:傲视网:[AE教程]如何制作环形进度条(第一讲) 大家好,福利来啦!这里将分享如何制作环形进度条,教你如何从入门到精通学AE. 环形进度条是个特殊的动画,在旋转的基础上还要选择性地显示部分区域 ...

  8. 【WPF】环形进度条

    WPF中自带有长条形的进度条,大部分场景都算适用,但是仍然有一部分空间小的场景不太合适,此时我们想到安卓上常用的环形进度条,美观,又不占空间. 那么WPF中的环形进度条控件在哪呢? 很遗憾,自带组件中 ...

  9. Android花样loading进度条(四)-渐变色环形进度条

    背景 Android花样loading进度条系列文章主要讲解如何自定义所需的进度条,包括水平.圆形.环形.圆弧形.不规则形状等. 本篇我们对配文字环形进度条稍加变换,将圆环颜色改为渐变色的形式,使得进 ...

最新文章

  1. android view控件的显示和隐藏动画效果
  2. php mysql隔离_mysql隔离级别有几种
  3. python多种推导式的实现
  4. 常见HTTP状态码列表
  5. 第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波9 - 直方图处理 - 直方图匹配(规定化)灰度图像,彩色图像都适用
  6. ea建模 教学_周末特惠:EA促销开启,吉你太美首次打折 + EA旗下多款游戏登陆Steam,EA access即将推出...
  7. Android中应用程序获得系统签名权限(platform.x509.pem platform.pk8)下载地址
  8. 将有道云词典单词本导入到墨墨背单词
  9. flash activex java_Adobe flash player ActiveX和NPAPI和PPAPI 这三个软件有什么区别?哪个是不必要的?...
  10. python经典编程题分别取个位十位百位
  11. [转载] 新妖女传说:奸魔
  12. CRM项目(idea)-1-环境搭建.
  13. 各种int的取值范围
  14. 海龟python同心圆_python turtle画4个同心圆方法
  15. Eclipse学习1-Eclipse简介
  16. ISP Tuning之路:初识ADRC
  17. layui富文本编辑器(layedit)的使用
  18. GUI设计之马的遍历
  19. php 翻页电子书,ThinkPHP5.0-快速入门手册(新手教程版)
  20. 使用LogParser和WCAT进行iis压力测试

热门文章

  1. less里面calc() 语法
  2. spdlog源码阅读 (1): sinks
  3. python -socket -client
  4. Linux服务器安装JDK、Tomcat配置web网站
  5. ios 绘制不规则 图形
  6. c# 获取客户端IP地址方法
  7. Intellij IDEA单元测试提示Test events were not received
  8. 不同版本浏览器前端标准兼容性对照表以及CORS解决跨域和CSRF安全问题解决方案
  9. HTTP长连接服务器端推技术
  10. ASP.NET 2.0 中的新增安全功能