经过半年的艰苦卓绝的奋战。我的项目终于完成了第一个测试版本。最近1.0版本会在App Store里面上架。不得不感叹这个项目耗时的确有一点长。一般的app项目都不会很大,耗时也不会太久。我们的这个项目主要用途是对公司产品的运维,故其中文名叫运维宝。我们公司的产品是监控类设备。因此运维宝的主要功能分为基础信息模块、视频预览模块、视频回放模块。和设置模块。基础信息模块主要是设备的基础信息和一些对监控设备储存数据的简单操作。视频预览模块可以看到监控的实时画面、回放模块主要是对过去一段监控时间的监控视频数据的回放。项目由两个工程组成,一个工程集成到另一个工程里面。一个工程主要负责UI布局。另一个工程则负责底层数据的获取,和设备的的一些交互。UI布局的肯定是用objective_c开发的。底层是用c++和objective_c混编实现的。我主要负责的是表现层的开发。别以为UI简单。的确要比底层简单点,但是我们这个项目UI也不是那么简单。这都是拜UI设计师所赐。太多的自定义。简单列举一二:自定义日历、自定义时间选择器(里面比较复杂、所以我给他取了这个名字)。在这个项目中我的确成长了很多。至少不再认为UI都简单。说了这么多废话,还是言归正传。分享我在这个项目中的一些自定义控件的实现思想。今天我解析自定义时间选取器中时间轴的实现。先给大家展示一下UI效果图。
效果图一
效果图二
首先对这个时间轴的功能进行简单的描述。效果图上由两个按钮,这两个按钮的作用是对时间轴刻度的调整。就是我们能看到的区域可能是一个小时、也可能是24个小时,当然也可能是12个小时。其实这个时间轴总共还是有二十四个小时,只是当我们的可见区域时一个小时的时候那么其他的23段我们看不见而已。所以我们需要把这个时间轴画到UIScrollView上。说到底我们是怎么画出这个时间轴的呢?我是把这个时间轴抽象成一把尺子,而这把尺子是由n个单元组成。可见区域表示一个单元,如果可见区域表示24个小时那么尺子的总长就是由一个单元组成。如果可见区域是表示一个小时那么尺子总长度就是24个单元组成,也就是尺子的总长有24个可见区域。可见单元n=24*60*60/60*60*实际表示的时间(即是可见区域表示的时间,是24个小时还是1个小时,还是其他值)。那么尺子的总长度L=可见区域的长度*n。代码示列如下。
//
// N9MTimerShaftScrollView.m
// N9MPad
//
// Created by 刘超 on 14-8-5.
// Copyright (c) 2014年 frank. All rights reserved.
//
#import "N9MTimerShaftScrollView.h"
@implementation N9MTimerShaftScrollView
- (id)initWithFrame:(CGRect)frame
{
self = [superinitWithFrame:frame];
if (self) {
// Initialization code
self.pagingEnabled=YES;
self.showsHorizontalScrollIndicator=NO;
self.showsVerticalScrollIndicator=NO;
self.scrollsToTop=NO;
self.bounces=NO;
self.tag=10;
_timerShaftView=[[N9MTimerShaftViewalloc]init];
[selfaddSubview:_timerShaftView];
}
returnself;
}
-(void)updateScaleValudeForHour:(NSInteger)hour addSliderShortScaleCount:(NSInteger)count{
_unitConut=(24*60*60)/(60*60*hour);
NSLog(@"%f",self.frame.size.width);
_timerShaftWidth=(self.frame.size.width)*_unitConut;
self.contentSize=CGSizeMake(_timerShaftWidth, 0);
[_timerShaftViewsetFrame:CGRectMake(0, 0,_timerShaftWidth, self.frame.size.height)];
[_timerShaftViewupdateScaleValudeForHour:hour addSliderShortScaleCount:count];
}
-(void)updateContentOffsetToRight{
NSLog(@"%f",self.contentOffset.x);
if (self.contentOffset.x<_timerShaftWidth-self.frame.size.width) {
self.contentOffset =
CGPointMake(self.contentOffset.x+1,self.contentOffset.y);
}
}
-(void)updateContentOffsetToLeft{
NSLog(@"%f",self.contentOffset.x);
if (self.contentOffset.x>0) {
self.contentOffset =
CGPointMake(self.contentOffset.x-1,self.contentOffset.y);
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
@end
时间轴一个有24个小时,一个小时为一个单位刻度,那么单位刻度的长k=总长度L/24。知道了尺子的总长度,有知道一个单位刻度的长度,而且还知道一个单位个度里面有几个小刻度,那么这个时间轴就能画出来了。代码示列如下。//
// N9MTimerShaftView.m
// N9MPad
//
// Created by 刘超 on 14-8-7.
// Copyright (c) 2014年 frank. All rights reserved.
//
#import "N9MTimerShaftView.h"
@implementation N9MTimerShaftView
- (id)initWithFrame:(CGRect)frame
{
self = [superinitWithFrame:frame];
if (self) {
// Initialization code
self.labelFontWidth=[UIFontsystemFontOfSize:25.0f];
self.laelFontHeight=[UIFontsystemFontOfSize:25.0f];
}
returnself;
}
-(void)drawRect:(CGRect)rect{
_unitConut=(24*60*60)/(60*60*self.hour);
_scaleCount=(24*60*60)/(60*60*1);
NSInteger startpointX=0;//刻度尺的起点横坐标
float timerShaftWidth=self.frame.size.width;
float scaleWidth=self.frame.size.width/_scaleCount;
[selfdrawRectSliderStartpointAbscissa:startpointXtimeSliderWidth:timerShaftWidth addScaleWidth:scaleWidth addScaleCount:_scaleCountaddSliderShortScaleCount:self.shortScaleCount];
}
-(void)updateScaleValudeForHour:(NSInteger)hour addSliderShortScaleCount:(NSInteger)count{
self.hour=hour;
self.shortScaleCount=count;
[selfsetNeedsDisplay];
}
-(void)drawRectSliderStartpointAbscissa:(float)abscissa timeSliderWidth:(float)sliderWidth addScaleWidth:(float)scaleWidth addScaleCount:(NSInteger)scaleCount addSliderShortScaleCount:(NSInteger)shortScaleCount{
float sliderY=self.frame.size.height-14;
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColorcolorWithRed:124/255.0 green:61/255.0blue:0 alpha:1.0].CGColor);//线条颜色
CGContextMoveToPoint(context,0+abscissa,sliderY+14);//线条起始点
CGContextAddLineToPoint(context,sliderWidth+abscissa,sliderY+14);//线条结束点
CGContextStrokePath(context);//结束,也就是开始画
CGContextSetLineWidth(context, 3.0);//线的宽度
for (int i=0; i<scaleCount+1; i++) {
CGPoint pointA;
pointA.x=scaleWidth*i+abscissa;
pointA.y=sliderY;
CGPoint pointB;
pointB.x=scaleWidth*i+abscissa;
pointB.y=sliderY+14;
CGContextMoveToPoint(context,pointA.x,pointA.y);//线条起始点
CGContextAddLineToPoint(context,pointB.x,pointB.y);//线条结束点
CGContextStrokePath(context);//结束,也就是开始画
NSString*title;
if (i<10) {
title=[NSStringstringWithFormat:@"0%d",i];
}else{
title=[NSStringstringWithFormat:@"%d",i];
}
CGPoint pointC;
pointC.x=scaleWidth*i+abscissa-7;
pointC.y=self.frame.size.height*1/2-5;
if (i==0) {
pointC.x=scaleWidth*i+abscissa-2;
}elseif (i==scaleCount){
pointC.x=scaleWidth*i+abscissa-15;
}
[selfdrawThermometersLablesStartpoint:pointCLableTitle:title];
if (i!=scaleCount) {
for (int j=0; j<shortScaleCount; j++) {
float minScaleWidth=scaleWidth/(shortScaleCount+1);
CGPoint pointC;
pointC.x=scaleWidth*i+minScaleWidth*(j+1)+abscissa;
pointC.y=sliderY+7;
CGPoint pointD;
pointD.x=scaleWidth*i+minScaleWidth*(j+1)+abscissa;
pointD.y=sliderY+14;
CGContextMoveToPoint(context,pointC.x,pointC.y);//线条起始点
CGContextAddLineToPoint(context,pointD.x,pointD.y);//线条结束点
CGContextStrokePath(context);//结束,也就是开始画
}
}
}
}
-(void)drawThermometersLablesStartpoint:(CGPoint)point LableTitle:(NSString*)title{
NSDictionary*attributes=@{NSFontAttributeName: [UIFontsystemFontOfSize:15] ,NSForegroundColorAttributeName:[UIColorcolorWithRed:124/255.0 green:61/255.0blue:0 alpha:1.0]};
CGRect labelLocation=CGRectMake(point.x, point.y, [self widthOfString:titlewithFont:self.labelFontWidth], [selfwidthOfString:title withFont:self.laelFontHeight]);
if ( [[UIDevicecurrentDevice].systemVersiondoubleValue]>=7.0) {
[title drawInRect:labelLocationwithAttributes:attributes];
}else{
[title drawInRect:labelLocationwithFont:self.labelFontWidth];
[[UIColorwhiteColor]set];
}
}
- (CGFloat)widthOfString:(NSString *)string withFont:(UIFont*)font {
NSDictionary *attributes = [NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName, nil];
return [[[NSAttributedStringalloc] initWithString:stringattributes:attributes] size].width;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
@end
关于是怎么用代码画出来这个时间轴在这里更多的是说的一种思想。要画出这个时间轴,还必须了解iOS重绘drawRect的相关知识。在这里我都不详细介绍了 。