40个迹象表明你还是PHP菜鸟
2011-10-30 12:25
357 查看
BuildingtheSectors[/b](构建扇区)[/b]
要让轮子停在当前扇区的中间点,你首先需要把轮子分为几个扇区。当用户的手指离开屏幕时我们要做一下内容:
1.计算弧度值
2.基于上一步的弧度值找出扇区
3.旋转一个弧度到扇区的中间点
举个例子,入股被选中的扇区是zero并且用户只是轻微往上或往下拖拽了轮子,你想让轮子转会到zero扇区的中间点。尽管这有一点棘手,让我们一步一步的来做。
首先,让我们对容器container的世界有一个更好的理解。
在SMRotaryWheel.m[/b]中continueTrackingWithTouch[/b]方法的顶部下列代码:
这记录了用户的手指拖拽的每个时刻容器container的旋转弧度。你会注意掉如果轮子被顺时针拖拽,弧度会是正值直到弧度值大于PI弧度(180度),或者如果你愿意,当标号为“0”的扇区处在圆中心点水平线以下的象限时,当你超过180度,你会看到负值,就像下面屏幕输出的。
这是你在计算扇区边界时必须考虑的:它们的最大值、中间值和最小值。被选中的扇区必会在最左边的位置,0扇区被初始化的位置。你要找到这个问题的答案:当弧度值是x的时候,哪个扇区是被定位器标识的?
要回答这个问题,你需要逆向思考。下面的图片显示了一个有八个扇区的轮子。
圆圈周围的数值表示每隔扇区的最大和最小弧度值。例如,不论何时只要容器container的弧度值在-0.39和0.39之间,轮子就应停在扇区0的中间点位置。
再者,你必须考虑象限(正或负)来正确的加减角度差。有一个特殊,你必须处理跨两个象限的扇区0和扇区4。对于扇区0,中间点是0弧度,它还算较为简单。然而对于扇区4,中间点是PI或-PI,因为中间点跨越正负象限的分界线。所以,事情变得有点复杂。
你可以从下面这张图片看到,如果有奇数个扇区,那么扇区中间点的弧度值会稍简单点。
为了保证灵活和全面,这篇教程会考虑偶数和奇数个扇区的情况,并提供各自的程序代码。但是首先,我们要定义一个新类来表示扇区,并存储每个扇区弧度的最大值、中间值和最小值。
用IOS\CocoaTouch\Objective-Cclass模版创建一个新文件。起名类SMSector,并且继承自NSObject。现在来到SMSector.h[/b]文件并用下面的代码替换其中的内容:
转移到SMSector.m[/b]文件,并用下面的实现代码替换其中的内容:
在SMRotaryWheel.h导入SMSector类:
然后增加一个新属性property,名叫sectors:
来到SMRotaryWheel.m[/b]并添加两个新的帮助方法定义来创建扇区(在已经有的caculateDistanceFromCenter的下边):
然后,synthesize这个新的属性property:
下一步,在drawWheel[/b]方法的最后,添加下面的代码这样当你创建转轮的时候扇区就会被初始化。
让我们开始一个比较简单的情况,当有奇数个扇区时。在SMRotaryWheel.m[/b]的底部(@end的上面)添加下面的方法实现代码:
让我们一步步的分析上面的代码:
首先,我们定义了每隔扇区弧度值的长度(或者叫宽度如果你愿意)。
然后,我们用初始中间点声明了一个变量。既然我们的起始点是0弧度,那它就是我们第一个中间点。
然后我们重复设置每个扇区的最大、中间和最小弧度值。
当计算最小和最大弧度值时,你要加上或减去扇区宽度的一半来得到正确的结果。记得角度变化范围是从-PI到PI,这样才正常,如果一个值超出了PI或-PI,那意味着你改变了象限。你既然是顺时针定位轮子,你就得考虑弧度最小值小于PI的情况,并且改变中间点的标记。
最后,一旦创建一个扇区,我们把这个扇区添加到预先定义的扇区数组中。
现在在SMViewController.m[/b]中修改viewDidLoad[/b]方法的section#2处设置sections值为3,正如下面代码:
如果你现在编译并运行,控制台应该显示以下的结果:
这些数值跟上面被分为三部分的轮子的数值是相同的。所以你的计算工作非常精确!
AnimatingtheSelectionCentering[/b](旋转到扇区中心)[/b]
最后一步是实现校准当前扇区的中心点,让我们温习下这是什么意思。
当用户的手指离开屏幕你必须计算x值,当前的弧度值,并且根据这个值确定选中的扇区。然后你得计算x和扇区中心点的差值,并用它来构建一个仿射变换。
首先在SMRotaryWheel.h[/b]中添加一个新属性property来记录当天扇区:
然后,在SMRotaryWheel.m[/b]中synthesize这个新属性property:
要处理手指离开屏幕的事件,你要重写endTrackingWithTouch:withEvent:[/b]方法(重写touchedEnded:withEvent:[/b]方法如果你扩展UIView)。
在SMRotaryWheel.m[/b],在continueTrackingWithTouch:withEvent:[/b]方法的下面添加下列代码来处理奇数个扇区:
这个方法相当的简单。它计算当前的弧度冰雨最小和最大弧度进行比较来确定正确的扇区。然后计算出差值并创建一个新的仿射变换,为了让效果看起来很自然,设置这个旋转动画持续0.2秒。
通过修改SMViewController.m[/b]中iewDidLoad的section#2出的代码重新创建了三个扇区,编译、运行……哈哈!它工作了!抓住轮子并按你的意愿拖拽,你会看到当你停止拖拽并把手指抬起时,它选中了右边的扇区。
现在这些代码适合于所有带有奇数个扇区的轮子。要考虑偶数个扇区,你必须重做section#3出的循环类检测异常的情况,在这种情况下,弧度最小值是正的,最大值是负的。用下面的代码替换掉endTrackingWithTouch:withEvent:[/b]中的sections#4,#5和#6部分:
编译、运行,并体验通过改变扇区数来免费进行的实验吧!
要让轮子停在当前扇区的中间点,你首先需要把轮子分为几个扇区。当用户的手指离开屏幕时我们要做一下内容:
1.计算弧度值
2.基于上一步的弧度值找出扇区
3.旋转一个弧度到扇区的中间点
举个例子,入股被选中的扇区是zero并且用户只是轻微往上或往下拖拽了轮子,你想让轮子转会到zero扇区的中间点。尽管这有一点棘手,让我们一步一步的来做。
首先,让我们对容器container的世界有一个更好的理解。
在SMRotaryWheel.m[/b]中continueTrackingWithTouch[/b]方法的顶部下列代码:
CGFloatradians=atan2f(container.transform.b,container.transform.a); NSLog(@"radis%f",radians); |
这是你在计算扇区边界时必须考虑的:它们的最大值、中间值和最小值。被选中的扇区必会在最左边的位置,0扇区被初始化的位置。你要找到这个问题的答案:当弧度值是x的时候,哪个扇区是被定位器标识的?
要回答这个问题,你需要逆向思考。下面的图片显示了一个有八个扇区的轮子。
圆圈周围的数值表示每隔扇区的最大和最小弧度值。例如,不论何时只要容器container的弧度值在-0.39和0.39之间,轮子就应停在扇区0的中间点位置。
再者,你必须考虑象限(正或负)来正确的加减角度差。有一个特殊,你必须处理跨两个象限的扇区0和扇区4。对于扇区0,中间点是0弧度,它还算较为简单。然而对于扇区4,中间点是PI或-PI,因为中间点跨越正负象限的分界线。所以,事情变得有点复杂。
你可以从下面这张图片看到,如果有奇数个扇区,那么扇区中间点的弧度值会稍简单点。
为了保证灵活和全面,这篇教程会考虑偶数和奇数个扇区的情况,并提供各自的程序代码。但是首先,我们要定义一个新类来表示扇区,并存储每个扇区弧度的最大值、中间值和最小值。
用IOS\CocoaTouch\Objective-Cclass模版创建一个新文件。起名类SMSector,并且继承自NSObject。现在来到SMSector.h[/b]文件并用下面的代码替换其中的内容:
@interfaceSMSector: @propertyfloatminValue; @propertyfloatmaxValue; @propertyfloatmidValue; @propertyintsector; @end |
#import"SMSector.h" @implementationSMSector @synthesizeminValue,maxValue,midValue,sector; -( return[ } @end |
#import"SMSector.h" |
@property(nonatomic,strong) |
@interfaceSMRotaryWheel() ... -(void)buildSectorsEven; -(void)buildSectorsOdd; @end |
@synthesizesectors; |
//8-Initializesectors sectors=[ if(numberOfSections%2==0){ [selfbuildSectorsEven]; }else{ [selfbuildSectorsOdd]; } |
-(void)buildSectorsOdd{ //1-Definesectorlength CGFloatfanWidth=M_PI*2/numberOfSections; //2-Setinitialmidpoint CGFloatmid=0; //3-Iteratethroughallsectors for(inti=0;i<numberOfSections;i++){ SMSector*sector=[[SMSectoralloc]init]; //4-Setsectorvalues sector.midValue=mid; sector.minValue=mid-(fanWidth/2); sector.maxValue=mid+(fanWidth/2); sector.sector=i; mid-=fanWidth; if(sector.minValue<-M_PI){ mid=-mid; mid-=fanWidth; } //5-Addsectortoarray [sectorsaddObject:sector]; NSLog(@"clis%@",sector); } } |
首先,我们定义了每隔扇区弧度值的长度(或者叫宽度如果你愿意)。
然后,我们用初始中间点声明了一个变量。既然我们的起始点是0弧度,那它就是我们第一个中间点。
然后我们重复设置每个扇区的最大、中间和最小弧度值。
当计算最小和最大弧度值时,你要加上或减去扇区宽度的一半来得到正确的结果。记得角度变化范围是从-PI到PI,这样才正常,如果一个值超出了PI或-PI,那意味着你改变了象限。你既然是顺时针定位轮子,你就得考虑弧度最小值小于PI的情况,并且改变中间点的标记。
最后,一旦创建一个扇区,我们把这个扇区添加到预先定义的扇区数组中。
现在在SMViewController.m[/b]中修改viewDidLoad[/b]方法的section#2处设置sections值为3,正如下面代码:
SMRotaryWheel*wheel=[[SMRotaryWheelalloc]initWithFrame:CGRectMake(0,0,200,200)andDelegate:self withSections:3]; |
这些数值跟上面被分为三部分的轮子的数值是相同的。所以你的计算工作非常精确!
AnimatingtheSelectionCentering[/b](旋转到扇区中心)[/b]
最后一步是实现校准当前扇区的中心点,让我们温习下这是什么意思。
当用户的手指离开屏幕你必须计算x值,当前的弧度值,并且根据这个值确定选中的扇区。然后你得计算x和扇区中心点的差值,并用它来构建一个仿射变换。
首先在SMRotaryWheel.h[/b]中添加一个新属性property来记录当天扇区:
@propertyintcurrentSector; |
@synthesizecurrentSector; |
在SMRotaryWheel.m[/b],在continueTrackingWithTouch:withEvent:[/b]方法的下面添加下列代码来处理奇数个扇区:
-(void)endTrackingWithTouch:(UITouch*)touchwithEvent:(UIEvent*)event { //1-Getcurrentcontainerrotationinradians CGFloatradians=atan2f(container.transform.b,container.transform.a); //2-Initializenewvalue CGFloatnewVal=0.0; //3-Iteratethroughallthesectors for(SMSector*sinsectors){ //4-Seeifthecurrentsectorcontainstheradianvalue if(radians>s.minValue&&radians<s.maxValue){ //5-Setnewvalue newVal=radians-s.midValue; //6-Getsectornumber currentSector=s.sector; break; } } //7-Setupanimationforfinalrotation [UIViewbeginAnimations:nilcontext:NULL]; [UIViewsetAnimationDuration:0.2]; CGAffineTransformt=CGAffineTransformRotate(container.transform,-newVal); container.transform=t; [UIViewcommitAnimations]; } |
通过修改SMViewController.m[/b]中iewDidLoad的section#2出的代码重新创建了三个扇区,编译、运行……哈哈!它工作了!抓住轮子并按你的意愿拖拽,你会看到当你停止拖拽并把手指抬起时,它选中了右边的扇区。
现在这些代码适合于所有带有奇数个扇区的轮子。要考虑偶数个扇区,你必须重做section#3出的循环类检测异常的情况,在这种情况下,弧度最小值是正的,最大值是负的。用下面的代码替换掉endTrackingWithTouch:withEvent:[/b]中的sections#4,#5和#6部分:
//4-Checkforanomaly(occurswithevennumberofsectors) if(s.minValue>0&&s.maxValue<0){ if(s.maxValue>radians||s.minValue<radians){ //5-Findthequadrant(positiveornegative) if(radians>0){ newVal=radians-M_PI; }else{ newVal=M_PI+radians; } currentSector=s.sector; } } //6-Allnon-anomalouscases elseif(radians>s.minValue&&radians<s.maxValue){ newVal=radians-s.midValue; currentSector=s.sector; } |
相关文章推荐
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 直面40个菜鸟迹象——40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟(转载)
- 40个迹象表明你还是php菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 直面40个菜鸟迹象——40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟
- 直面40个菜鸟迹象——40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟(转)
- 40个迹象表明你还是PHP菜鸟
- 40个迹象表明你还是PHP菜鸟(转)