完整代码可以看: Github 。 其实没什么难度,下面记录几个要点
放个预览图
用的贝塞尔曲线UIBezierPath来画,这个类支持画很多种形状,可以单独去尝试。
UIBezierPath *progress = [UIBezierPath bezierPath]; [progress addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2) radius:RADIUS startAngle:startAngle endAngle:endAngle clockwise:YES]; progress.lineWidth = PROGRESS_WIDTH; [[UIColor redColor] set]; [progress stroke];
参数分别为圆心点、半径、绘制起始角度、绘制结束角度、顺时针方向。如果画一个整圆,角度设为0,2pi即可。这里0度对应3点钟方向,我希望绘制从12点方向开始,设置起始角度为-0.5pi即可。结束角度就根据经过的时间和总的时间的比例进行角度计算。有了以上参数也可以算出在当前角度下的圆周上点的坐标,即可以画出那个圆点。
这里为了绘制看起来更连贯,我选择0.05秒刷新一次界面,而没有参考系统定时器的1秒刷新一次,这样看起来会更舒服。但在显示数字上会遇到1秒的误差,所以我在格式化字符串的时候对剩余时间做了向上去整 ceil() 的操作,具体差别可以通过改代码来尝试。
ceil()
m_timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(setProgress) userInfo:nil repeats:YES];
我一直以为iOS的滚轮是支持内容循环显示的,然而并没有看到相关接口,所以有点迷茫。查过资料后发现原来是用了一个技巧, 即循环设置非常多的滚轮内容,然后默认选择居中的item, 比如设置10000个项,内容是:0,1,2, …, 97, 98, 99, 0, 1, 2, …, 97, 98, 99, …,然后默认显示第5000个条目,这样用户划起来就好像是循环的。因为总的内容很多,用户不会划很多次,所以用户一般不会遇到划到头的情况。于是,我在系统计时器里试了一下,的确是这样的,当我往一个方向划动非常多次后,滚轮还是会到头的。所以这是可行的方法。
//这里可以直接用MAX_ROWS / 2,但下面的计算适合各种情况:取中间位置,取整,再取余根据余数校正起始位置为要显示内容的第一项(即选中居中的 0 的位置) - (void)init { [m_pickerView selectRow:(((NSInteger)((MAX_ROWS / 2) / [m_arrayData count])) * [m_arrayData count]) + (selectedRow % [m_arrayData count]) inComponent:0 animated:NO]; -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component