zoukankan      html  css  js  c++  java
  • ios基础知识

       1 1获取系统语言设置
       2 
       3      NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
       4 
       5      NSArray *languages = [userDefault objectForKey:@"AppleLanguages"];
       6 
       7      NSString *preferredLang = [languages objectAtIndex:0];
       8 
       9 2
      10 
      11 缓存路径下文件大小
      12 
      13 
      14 - (unsigned long long int) cacheFolderSize 
      15 
      16 {
      17 
      18     NSFileManager  *_manager = [NSFileManager defaultManager];
      19 
      20     NSArray *_cachePaths =  NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
      21                                                 NSUserDomainMask, YES);
      22 
      23     NSString  *_cacheDirectory = [_cachePaths objectAtIndex:]; 
      24 
      25     NSArray  *_cacheFileList;
      26 
      27     NSEnumerator *_cacheEnumerator;
      28 
      29     NSString *_cacheFilePath;
      30 
      31     unsigned long long int _cacheFolderSize = ;
      32 
      33     _cacheFileList = [ _manager subpathsAtPath:_cacheDirectory];
      34 
      35    _cacheEnumerator = [_cacheFileList objectEnumerator];
      36 
      37     while (_cacheFilePath = [_cacheEnumerator nextObject]) 
      38 
      39    {
      40 
      41          NSDictionary *_cacheFileAttributes = [_managerfileAttributesAtPath:  
      42 
      43          [_cacheDirectory   stringByAppendingPathComponent:_cacheFilePath]
      44 
      45          traverseLink:YES];
      46 
      47       _cacheFolderSize += [_cacheFileAttributes fileSize];
      48 
      49     }
      50 
      51 // 单位是字节
      52 
      53     return _cacheFolderSize;
      54 
      55 }
      56 
      57 3Popover push 时 Frame无法改变解决办法
      58 
      59 在popover中的ViewController中实现:
      60 
      61 - (void)viewWillAppear:(BOOL)animated 
      62 {
      63 
      64    CGSize size = CGSizeMake(320, 480); // size of view in popover  
      65 
      66    self.contentSizeForViewInPopover = size; 
      67 
      68    [super viewWillAppear:animated]; 
      69 
      70 }
      71 
      72 4tableview滑动导致NSTimer和委托回调停止解决办法
      73 
      74 / /请求回调
      75 
      76 NSURLRequest  * 请求  =  ...
      77 
      78 scheduleInRunLoop :[ NSRunLoop  currentRunLoop ] 
      79                                             forMode :NSRunLoopCommonModes ] 
      80 [ 连接开始] / /定时器回调
      81 
      82 NSTimer * updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.01f目标:自我选择:选择(updatePencent)的UserInfo:无重复:是];
      83 
      84 * NSRunLoop主要= [NSRunLoop currentRunLoop] 
      85 [主要addTimer:updateTimer forMode:NSRunLoopCommonModes];
      86 
      87 5手势识别类
      88 
      89 UIGestureRecognizer
      90 
      91 
      92 6SFHFKeychainUtils 存储信息
      93 
      94 苹果SDK自带的就有密码保护,使用方法很简单,如下:
      95 
      96 1、引入Security.frameWork框架。
      97 
      98 2、引入头文件:SFHKeychainUtils.h.
      99 
     100 3、存密码:
     101 
     102 [SFHFKeychainUtils storeUsername:@"dd" andPassword:@"aa"forServiceName:SERVICE_NAMEupdateExisting:1 error:nil];
     103 
     104 [SFHFKeychainUtils deleteItemForUsername:@"dd" andServiceName:SERVICE_NAME error:nil];
     105 
     106 4、取密码:
     107 
     108 NSString *passWord =  [SFHFKeychainUtils getPasswordForUsername:@"dd"andServiceName:SERVICE_NAMEerror:nil];
     109 
     110 7missing required architecture i386 in file 解决办法
     111 
     112 在TargetInfo里面修改 Framework Search Pasths 删除里面内容就可以了。
     113 
     114 
     115 8view 放大缩小动画效果
     116 
     117 //创建缩小了的视图
     118 myWeiBoImageVC = [[UIViewController alloc] init];
     119 myWeiBoImageVC.view.clipsToBounds = YES;
     120 myWeiBoImageVC.view.alpha = 0.0;
     121 myWeiBoImageVC.view.frame = CGRectMake(64, 0, 1024-64, 768-20);
     122 [self.view addSubview:myWeiBoImageVC.view];
     123     
     124 CGAffineTransform newTransform = 
     125 CGAffineTransformScale(myWeiBoImageVC.view.transform, 0.1, 0.1);
     126 [myWeiBoImageVC.view setTransform:newTransform];
     127 myWeiBoImageVC.view.center = CGPointMake(670, 100);
     128  
     129 [self performSelector:@selector(imageViewControllerBigAnimation)];
     130 
     131 //放大刚刚创建缩小后的视图
     132 - (void)imageViewControllerBigAnimation{
     133    
     134     [UIView beginAnimations:@"imageViewBig" context:nil];
     135     [UIView setAnimationDuration:0.5];   
     136     CGAffineTransform newTransform =            CGAffineTransformConcat(myWeiBoImageVC.view.transform,  CGAffineTransformInvert(myWeiBoImageVC.view.transform));
     137     [myWeiBoImageVC.view setTransform:newTransform];
     138     myWeiBoImageVC.view.alpha = 1.0;
     139     myWeiBoImageVC.view.center = CGPointMake(416, 510);
     140     [UIView commitAnimations];
     141    
     142 }
     143 
     144 //缩小视图 隐藏
     145 
     146 - (void)imageViewControllerSmallAnimation{
     147 
     148     [UIView beginAnimations:@"imageViewSmall" context:nil];
     149     [UIView setAnimationDuration:0.5];
     150     CGAffineTransform newTransform =  CGAffineTransformScale(myWeiBoImageVC.view.transform, 0.1, 0.1);
     151     [myWeiBoImageVC.view setTransform:newTransform];
     152     myWeiBoImageVC.view.center = CGPointMake(670, 100);
     153     [UIView commitAnimations];
     154    
     155 }
     156 
     157 9UIScrollView 控制View缩放
     158 
     159 allImageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 768, 1024)];
     160 allImageScrollView.minimumZoomScale = 0.3;
     161 allImageScrollView.maximumZoomScale = 1.0;
     162 allImageScrollView.backgroundColor = [UIColor clearColor];
     163 allImageScrollView.delegate = self;
     164 [self.view addSubview:allImageScrollView];
     165 
     166 mPicStatusesViewController = [[PicStatusesViewController alloc] init];
     167 [allImageScrollView addSubview:mPicStatusesViewController.view];
     168 
     169 //UIScrollView Delegete 实现
     170 
     171 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
     172 
     173 {
     174     return mPicStatusesViewController.view; //返回ScrollView上添加的需要缩放的视图
     175 }
     176 
     177 - (void)scrollViewDidZoom:(UIScrollView *)scrollView
     178 
     179 {
     180     //缩放操作中被调用
     181 }
     182 
     183 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
     184 
     185 {
     186     //缩放结束后被调用
     187   }
     188 
     189 10、iOS3.2 播放视频
     190 
     191 NSString *urlString = [NSString stringWithString:@"视频url"];
     192 
     193 NSURL *movieUrl = [[NSURL alloc] initWithString:urlString];
     194     
     195 MPMoviePlayerController *myMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieUrl];
     196 myMoviePlayer.view.frame = CGRectMake(250, 250, 350, 350);
     197 [self.view addSubview:myMoviePlayer.view];    
     198 myMoviePlayer.shouldAutoplay = YES;
     199 myMoviePlayer.scalingMode= MPMovieScalingModeAspectFit;  
     200 [myMoviePlayer play];
     201 
     202 
     203 11、谷歌地图翻起动画效果
     204 
     205     CATransition *animation = [CATransition animation];
     206     [animation setDelegate:self];
     207     [animation setDuration:0.35];
     208     [animation setTimingFunction:UIViewAnimationCurveEaseInOut];
     209     if (!curled){
     210 
     211         animation.type = @"pageCurl";
     212         animation.fillMode = kCAFillModeForwards;
     213         animation.endProgress = 0.40;
     214     } else {
     215         animation.type = @"pageUnCurl";
     216         animation.fillMode = kCAFillModeBackwards;
     217         animation.startProgress = 0.30;
     218     }
     219     [animation setRemovedOnCompletion:NO];
     220     [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
     221     
     222     [self.view.layer addAnimation:animation forKey:@"pageCurlAnimation"];
     223 
     224 12、给View添加阴影 和边框
     225 
     226 UIImageView *imgvPhoto  = [UIImageView alloc] init];
     227 
     228 //添加边框
     229    CALayer *layer = [_imgvPhoto layer];
     230     layer.borderColor = [[UIColor whiteColor] CGColor];
     231     layer.borderWidth = 5.0f;
     232 //添加四个边阴影
     233     _imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
     234     _imgvPhoto.layer.shadowOffset = CGSizeMake(0, 0);
     235     _imgvPhoto.layer.shadowOpacity = 0.5;
     236     _imgvPhoto.layer.shadowRadius = 10.0;
     237 //添加两个边阴影
     238     _imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
     239     _imgvPhoto.layer.shadowOffset = CGSizeMake(4, 4);
     240     _imgvPhoto.layer.shadowOpacity = 0.5;
     241     _imgvPhoto.layer.shadowRadius = 2.0;
     242 
     243 13、使用NSTimer与UIView动画实现飘雪效果
     244 
     245 viewDidLoad事件中,增加一个图片及定时器并启动,这里的pic请在头文件中定义。
     246 
     247 -(void)viewDidLoad{
     248  [super viewDidLoad];
     249  self.pic = [UIImage imageNamed:@"snow.png"];//初始化图片
     250  //启动定时器,实现飘雪效果
     251  [NSTimer scheduledTimerWithTimeInterval:(0.2) target:self selector:@selector(ontime) userInfo:nil repeats:YES];
     252 }
     253 
     254 然后再实现定时器定时调用的ontime方法:
     255 -(void)ontime{
     256  UIImageView *view = [[UIImageView alloc] initWithImage:pic];//声明一个UIImageView对象,用来添加图片
     257  view.alpha = 0.5;//设置该view的alpha为0.5,半透明的
     258  int x = round(random()20);//随机得到该图片的x坐标
     259  int y = round(random()20);//这个是该图片移动的最后坐标x轴的
     260  int s = round(random())+10;//这个是定义雪花图片的大小
     261  int sp = 1/round(random()0)+1;//这个是速度
     262  view.frame = CGRectMake(x, -50, s, s);//雪花开始的大小和位置
     263  [self.view addSubview:view];//添加该view
     264  [UIView beginAnimations:nil context:view];//开始动画
     265  [UIView setAnimationDuration:10*sp];//设定速度
     266  view.frame = CGRectMake(y, 500, s, s);//设定该雪花最后的消失坐标
     267  [UIView setAnimationDelegate:self];
     268  [UIView commitAnimations];
     269 }
     270 
     271 14、配置Xcode 看程序崩溃信息
     272 
     273 1、在xcode中的左侧目录中找到Executables 打开
     274 
     275 2、双击和工程名一样的文件。
     276 
     277 3、在打开的文件中的Arguments选项,在下面的框中加入Name: NSZombieEnabled 设置value为YES。
     278 
     279 15、程序中发送邮件和检测设备邮箱是否被配置
     280 
     281 -(void)addEmail{
     282 
     283 Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
     284 
     285 if (mailClass != nil){
     286 
     287     if ([mailClass canSendMail]){
     288 
     289         [self displayComposerSheet];
     290 
     291     }else{
     292 
     293         [self launchMailAppOnDevice];
     294 
     295     }
     296 
     297 }else{
     298 
     299     [self launchMailAppOnDevice];
     300 
     301     }
     302 
     303 }
     304 
     305 -(void)displayComposerSheet
     306 
     307 {
     308 
     309 MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
     310 
     311 controller.navigationBar.tag = 1002;
     312 
     313 [self.navigationController.navigationBar setNeedsDisplay];
     314 
     315 controller.mailComposeDelegate = self;
     316 
     317 [controller setSubject:@"意见反馈"];
     318 
     319 [controller setToRecipients:[[NSArray alloc] initWithObjects:@"555@cifco.net.cn",nil]];
     320 
     321 NSString *emailBody = nil;
     322 
     323 [controller setMessageBody:emailBody isHTML:YES];
     324 
     325 [self presentModalViewController:controller animated:YES];
     326 
     327 [controller release];
     328 
     329 }
     330 
     331 #pragma mark mailComposeDelegate ----
     332 
     333 - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error 
     334 
     335 {
     336 
     337 if (result == MFMailComposeResultSent) 
     338 
     339 {
     340 
     341 [self dismissModalViewControllerAnimated:YES];
     342 
     343 }
     344 
     345 if (result == MFMailComposeResultSaved) 
     346 
     347 {
     348 
     349 [self dismissModalViewControllerAnimated:YES];
     350 
     351 }
     352 
     353 if (result == MFMailComposeResultFailed) 
     354 
     355 {
     356 
     357 Emailalert = [[UIAlertView alloc] initWithTitle:@"" message:@"发送失败" delegate:selfcancelButtonTitle:@"知道了" otherButtonTitles:nil];
     358 
     359 [Emailalert show];
     360 
     361 }
     362 
     363 if (result == MFMailComposeResultCancelled) 
     364 
     365 {
     366 
     367 [self dismissModalViewControllerAnimated:YES];
     368 
     369 }
     370 
     371 }
     372 
     373 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
     374 
     375 {
     376 
     377 if(alertView == Emailalert)
     378 
     379 {
     380 
     381 if (buttonIndex == ) 
     382 
     383 {
     384 
     385 [self dismissModalViewControllerAnimated:YES];
     386 
     387 }
     388 
     389 }else 
     390 
     391 {
     392 
     393 if (buttonIndex == ) 
     394 
     395 {
     396 
     397 //[self dismissModalViewControllerAnimated:YES];
     398 
     399 }else 
     400 
     401 {
     402 
     403 NSString *recipients = @"mailto:theonelgq@gmail.com?cc=theone_liuguoqing@163.com&subject=text";
     404 
     405 NSString *body = @"&body=text!";
     406 
     407 NSString *email = [NSString stringWithFormat:@"%@%@", recipients, body];
     408 
     409 email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
     410 
     411 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
     412 
     413 }
     414 
     415 }
     416 
     417 }
     418 
     419 #pragma mark -
     420 
     421 #pragma mark Workaround
     422 
     423 -(void)launchMailAppOnDevice
     424 
     425 {
     426 
     427 isEmailalert = [[UIAlertView alloc] initWithTitle:@"警告" message:@"请配置您的邮箱" delegate:selfcancelButtonTitle:@"取消" otherButtonTitles:@"好的",nil];
     428 
     429 [isEmailalert show];
     430 
     431 }
     432 
     433 16、程序启动画面大小
     434 
     435  iOS设备现在有三种不同的分辨率:iPhone 320x480、iPhone 4 640x960、iPad 768x1024。以前程序的启动画面(图片)只要准备一个 Default.png 就可以了,但是现在变得复杂多了。下面就是 CocoaChina 会员做得总结
     436 
     437   如果一个程序,既支持iPhone又支持iPad,那么它需要包含下面几个图片:
     438 
     439 Default-Portrait.png iPad专用竖向启动画面 768x1024或者768x1004
     440 
     441 Default-Landscape.png iPad专用横向启动画面 1024x768或者1024x748
     442 
     443 Default-PortraitUpsideDown.png iPad专用竖向启动画面(Home按钮在屏幕上面),可省略 768x1024或者768x1004
     444 
     445 Default-LandscapeLeft.png iPad专用横向启动画面,可省略 1024x768或者1024x748
     446 
     447 Default-LandscapeRight.png iPad专用横向启动画面,可省略 1024x768或者1024x748
     448 
     449 Default.png iPhone默认启动图片,如果没有提供上面几个iPad专用启动图片,则在iPad上运行时也使用Default.png(不推荐) 320x480或者320x460
     450 
     451 Default@2x.png iPhone4启动图片640x960或者640x920
     452 
     453   为了在iPad上使用上述的启动画面,你还需要在info.plist中加入key: UISupportedInterfaceOrientations。同时,加入值UIInterfaceOrientationPortrait, UIInterfacOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight
     454 
     455 17、ASIHTTPRequest实现断点下载
     456 
     457 - (IBAction)URLFetchWithProgress:(id)sender
     458 
     459 {
     460 
     461 [startButton setTitle:@"Stop" forState:UIControlStateNormal];
     462 
     463 [startButton addTarget:self action:@selector(stopURLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
     464 
     465 NSString*tempFile = [[[[NSBundle mainBundle] bundlePath]stringByDeletingLastPathComponent]stringByAppendingPathComponent:@"MemexTrails_1.0b1.zip.download"];
     466 
     467 if ([[NSFileManager defaultManager] fileExistsAtPath:tempFile]) {
     468 
     469 [[NSFileManager defaultManager] removeItemAtPath:tempFile error:nil];
     470 
     471 }
     472 
     473 [self resumeURLFetchWithProgress:self];
     474 
     475 }
     476 
     477 - (IBAction)stopURLFetchWithProgress:(id)sender
     478 
     479 {
     480 
     481 networkQueue = [[ASINetworkQueue alloc] init];
     482 
     483 timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:selfselector:@selector(updateBandwidthUsageIndicator) userInfo:nil repeats:YES];
     484 
     485 timer = nil;
     486 
     487 [startButton setTitle:@"Stop" forState:UIControlStateNormal];
     488 
     489 [startButton addTarget:self action:@selector(URLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
     490 
     491 [networkQueue cancelAllOperations];
     492 
     493 [resumeButton setEnabled:YES];
     494 
     495 }
     496 
     497 - (IBAction)resumeURLFetchWithProgress:(id)sender 
     498 
     499 {
     500 
     501 [resumeButton setEnabled:NO];
     502 
     503 [startButton setTitle:@"Start" forState:UIControlStateNormal];
     504 
     505  [startButton addTarget:self action:@selector(stopURLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
     506 
     507 [networkQueue cancelAllOperations];
     508 
     509 [networkQueue setShowAccurateProgress:YES];
     510 
     511 [networkQueue setDownloadProgressDelegate:progressIndicator];
     512 
     513 [networkQueue setDelegate:self];
     514 
     515 [networkQueue setRequestDidFinishSelector:@selector(URLFetchWithProgressComplete:)];
     516 
     517 ASIHTTPRequest*request=[[[ASIHTTPRequest alloc] initWithURL:[NSURLURLWithString:@"http://9991.net/blog/mp3/2.mp3"]] autorelease];
     518 
     519 [request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath]
     520 
     521 stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"MemexTrails_1.0b1.mp3"]];
     522 
     523 [request setTemporaryFileDownloadPath:[[[[NSBundle mainBundle] bundlePath]stringByDeletingLastPathComponent]stringByAppendingPathComponent:@"MemexTrails_1.0b1.zip.down"]];
     524 
     525 [request setAllowResumeForFileDownloads:YES];
     526 
     527 [networkQueue addOperation:request];
     528 
     529 [networkQueue go];
     530 
     531 }
     532 
     533 - (void)URLFetchWithProgressComplete:(ASIHTTPRequest *)request
     534 
     535 {
     536 
     537 if ([request error]) {
     538 
     539 fileLocation.text=[NSString stringWithFormat:@"An error occurred:%@",[[[requesterror] userInfo] objectForKey:@"Title"]];
     540 
     541 } else {
     542 
     543 fileLocation.text=[NSString stringWithFormat:@"File downloaded to %@",[requestdownloadDestinationPath]];
     544 
     545 }
     546 
     547 [startButton setTitle:@"Start" forState:UIControlStateNormal];
     548 
     549 [startButton addTarget:self action:@selector(URLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
     550 
     551 }
     552 
     553 - (IBAction)throttleBand(id)sender
     554 
     555 {
     556 
     557 if ([(UIButton *)sender state] ==YES) {
     558 
     559 [ASIHTTPRequest setMaxBandwidthPerSecond:ASIWWANBandwidthThrottleAmount];
     560 
     561 } else {
     562 
     563 [ASIHTTPRequest setMaxBandwidthPerSecond:];
     564 
     565 }
     566 
     567 }
     568 
     569 18、Safari 启动本地app
     570 
     571 在plist文件中加入URL types 结构如下图,在Safari中地址栏输入 设置的字符串,比如设置的是
     572 
     573 QQ,地址栏输入 QQ:// 就可以起点本地应用。
     574 
     575  
     576 
     577 
     578 19、拖到视频进度与滑动手势冲突解决办法
     579 
     580 #pragma mark -
     581 #pragma mark UIGestureRecognizerDelegate
     582 
     583 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
     584 {
     585     UIView *touchView = touch.view;
     586     
     587     if ([touchView isKindOfClass:[UISlider class]]) 
     588     {
     589         return NO;
     590     }
     591     else 
     592     {
     593         return YES;
     594     }
     595 }
     596 
     597 20、创建并保存Cookie的方法
     598 
     599 
     600         NSString *cookieString = [NSString stringWithString:[headers objectForKey:@"Cookie"]];
     601         
     602         NSMutableDictionary *cookieProperties = [[NSMutableDictionary alloc] init];
     603         [cookieProperties setValue:cookieString forKey:NSHTTPCookieValue];
     604         [cookieProperties setValue:@"QQCookie" forKey:NSHTTPCookieName];
     605         [cookieProperties setValue:@".QQ.com" forKey:NSHTTPCookieDomain];
     606         [cookieProperties setValue:[NSDate dateWithTimeIntervalSinceNow:60*60] forKey:NSHTTPCookieExpires];
     607         [cookieProperties setValue:@"/" forKey:NSHTTPCookiePath];
     608         NSHTTPCookie *newcookie = [[NSHTTPCookie alloc] initWithProperties:cookieProperties];
     609         
     610         [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newcookie];
     611 
     612 
     613 21、popover横竖屏位置改变解决办法
     614 
     615 1、 delegate中 处理
     616 
     617 - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
     618 {
     619     userImageShow = NO;
     620     
     621     if ([popoverController isEqual:myPopover]) 
     622     {
     623         [myPopover release];
     624         myPopover = nil;
     625     }
     626 }
     627 
     628 2、屏幕旋转时重新弹出Popover
     629 
     630 if (myPopover)  
     631 
     632 {
     633 
     634      if ((self.interfaceOrientation == 
     635        UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation == 
     636        UIInterfaceOrientationLandscapeRight)) 
     637      {
     638             [myPopover presentPopoverFromRect:CGRectMake(10,180, 1, 1)
     639                                                 inView:self.view
     640                               permittedArrowDirections:UIPopoverArrowDirectionRight
     641                                               animated:YES];
     642      }
     643      else 
     644      {
     645            [myPopover presentPopoverFromRect:CGRectMake(20,180, 1, 1)
     646                                                 inView:self.view
     647                               permittedArrowDirections:UIPopoverArrowDirectionRight
     648                                               animated:YES];
     649       }
     650 
     651 }
     652 
     653 22、plist各种key值含义
     654 
     655 原文:http://www.minroad.com/?p=434
     656 
     657 
     658 
     659 UIRequiresPersistentWiFi 在程序中弹出wifi选择的key(系统设置中需要将wifi提示打开)
     660 UIAppFonts 内嵌字体(http://www.minroad.com/?p=412 有详细介绍)
     661 UIApplicationExitsOnSuspend 程序是否在后台运行,自己在进入后台的时候exit(0)是很傻的办法
     662 UIBackgroundModes 后台运行时的服务,具体看iOS4的后台介绍
     663 UIDeviceFamily array类型(1为iPhone和iPod touch设备,2为iPad)
     664 UIFileSharingEnabled 开启itunes共享document文件夹
     665 UILaunchImageFile 相当于Default.png(更名而已)
     666 UIPrerenderedIcon icon上是否有高光
     667 UIRequiredDeviceCapabilities 设备需要的功能(具体点击这里查看)
     668 UIStatusBarHidden 状态栏隐藏(和程序内的区别是在于显示Default.png已经生效)
     669 UIStatusBarStyle 状态栏类型
     670 UIViewEdgeAntialiasing 是否开启抗锯齿
     671 CFBundleDisplayName app显示名
     672 CFBundleIconFile、CFBundleIconFiles 图标
     673 CFBundleName 与CFBundleDisplayName的区别在于这个是短名,16字符之内
     674 CFBundleVersion 版本
     675 CFBundleURLTypes 自定义url,用于利用url弹回程序
     676 CFBundleLocalizations 本地资源的本地化语言,用于itunes页面左下角显示本地话语种
     677 CFBundleDevelopmentRegion 也是本地化相关,如果用户所在地没有相应的语言资源,则用这个key的value来作为默认
     678 最后附上官方文档,所有的key都有,看英文原版才是正路:)点我进入
     679 
     680 24、xcode工程内添加多个Target
     681 
     682 转自:http://blog.sina.com.cn/s/blog_682dc7810100pv8t.html
     683 
     684  
     685 
     686 啥叫多Targets, 有啥用!
     687 
     688  
     689 
     690    相信很多人都注意到XCode中,
     691 有个Target的概念.
     692     这在很多地方都有所体现,
     693 比如打开一个工程后, 左侧的列表中有Targets一项, 而在工程界面的顶部菜单中,
     694 project里面也有多个涉及到Target的项目,
     695 那么这个Target到底是什么呢?  
     696     Apple的人是这样说的:
     697     
     698 
     699 引用
     700 
     701 Targets that define the products to build. A
     702 target organizes the files and instructions needed to build a
     703 product into a sequence of build actions that can be taken.
     704 
     705 
     706 
     707     简单的理解的话, 
     708 
     709 可以认为一个target对应一个新的product(基于同一份代码的情况下). 但都一份代码了, 弄个新product做啥呢? 
     710 
     711 折腾这个有意思么? 
     712 
     713     其实这不是单纯的瞎折腾, 
     714 
     715 虽然代码是同一份, 但编译设置(比如编译条件), 以及包含的资源文件却可以有很大的差别. 于是即使同一份代码, 
     716 
     717 产出的product也可能大不相同. 
     718 
     719     我们来举几个典型的应用多Targets的情况吧, 
     720 
     721 比如完整版和lite版; 比如同一个游戏的20关, 30关, 50关版; 再或者比如同一个游戏换些资源和名字就当新游戏卖的(喂喂, 
     722 
     723 你在教些什么...) 
     724 
     725 
     726 Targets之间, 什么相同, 什么不同! 
     727 
     728 
     729     既然是利用同一份代码产出不同的product, 
     730 
     731 那么到底不同Target之间存在着什么样的差异呢? 
     732 
     733     要解释这个问题, 
     734 
     735 我们就要来看看一个Target指定了哪些内容. 
     736 
     737 
     738     从XCode左侧的列表中, 
     739 
     740 我们可以看到一个Target包含了Copy Bundle Resources, Compile Sources, Link 
     741 
     742 Binary With Libraries. 其中 
     743 
     744         Copy 
     745 
     746 Bundle Resources 是指生成的product的.app内将包含哪些资源文件 
     747 
     748         Compile 
     749 
     750 Sources 是指将有哪些源代码被编译 
     751 
     752         Link 
     753 
     754 Binary With Libraries 是指编译过程中会引用哪些库文件 
     755 
     756 
     757     通过Copy 
     758 
     759 Bundle Resources中内容的不同设置, 我们可以让不同的product包含不同的资源, 包括程序的主图标等, 
     760 
     761 而不是把XCode的工程中列出的资源一股脑的包含进去. 
     762 
     763     而这还不是一个target所指定的全部内容. 
     764 
     765 每个target可以使用一个独立, 
     766 
     767 不同的Info.plist文件.   
     768 
     769     我们都知道, 
     770 
     771 这个Info.plist文件内定义了一个iPhone项目的很多关键性内容, 比如程序名称, 
     772 
     773 最终生成product的全局唯一id等等. 
     774 
     775      
     776 
     777     而且不同的target还可以定义完整的差异化的编译设置, 
     778 
     779 从简单的调整优化选项, 到增加条件编译所使用的编译条件, 以至于所使用的base SDK都可以差异化指定. 
     780 
     781 
     782 创建第二个Target! 
     783 
     784     为什么是第二个? 
     785 
     786 因为第一个就是创建好工程后的默认Target呀! (废话这么多, 拖走...) 
     787 
     788 
     789     创建target有多种方法, 
     790 
     791 我们可以从现有的target上复制出一份, 然后略加改动, 也可以完全新建一个target出来. 但其实说穿了, 
     792 
     793 两个方法大同小异 
     794 
     795     首先我们来看看利用复制的方法创建target 
     796 
     797 
     798      利用复制创建target 
     799 
     800     我们在XCode左侧的列表中, 
     801 
     802 展开 Targets 项, 在现有的target上, 右键选择 "Duplicate", 或者选中现有target后, 
     803 
     804 在顶部菜单的Edit内选择"Duplicate"也可以. 
     805 
     806     此时我们就得到了一个新的target, 
     807 
     808 而在Resource里面也会得到一个 xxxx copy.plist. 这个新的target与原有的target是完全一致的, 
     809 
     810 余下的就是一些差异化的修改, 这个我们后面再说 
     811 
     812 
     813      创建全新的target 
     814 
     815     类似复制的方法, 
     816 
     817 我们可以在左侧的列表中很多地方按下右键菜单, 都可以看到Add中会有"New Target..."一项, 
     818 
     819 而在工程顶部菜单的Project内, 也可以看到这个"New Target..."的身影. 
     820 
     821     点击后, 
     822 
     823 首先会让你选择target的类型, 既然我一直所指的都是程序本身, 那么自然选择Application了(至于其他的嘛, 
     824 
     825 有兴趣的自己研究吧, 比如我们可以把程序中的部分提取成一个Static Library). 
     826 
     827     Next后, 
     828 
     829 会让你输入一个新的Target的名字, 而不像复制的方法中, 默认生成 xxxxx copy这样的target名. 
     830 
     831     但是这样生成出的Target几乎是空的. 
     832 
     833 Copy Bundle Resources, Compile Sources, Link Binary With 
     834 
     835 Libraries里面都没有任何内容. 编译设置也是完全原始的状态. 
     836 
     837     可以通过拖拽内容到这些target的设置中, 
     838 
     839 以及调整编译选项来完成Target的配置. 
     840 
     841 
     842 
     843 Target中部分内容的修改方法! 
     844 
     845     其实这段的部分内容, 
     846 
     847 在非多Targets的工程中也可能会用得到. 
     848 
     849     由于修改基本都是在工程/编译设置中完成, 
     850 
     851 因此没有特殊情况, 就不再声明了, 打开target对应的工程/编译设置的方法可以采用在该target上右键, 选择get 
     852 
     853 info来做到. 
     854 
     855 
     856     生成的product名称的修改: 
     857 
     858 Packing段内的Product Name一项 
     859 
     860 
     861     Info.plist文件名: 
     862 
     863 Packing段内的Info.plist File一项, 比如复制出来的target觉得那个xxxxx 
     864 
     865 copy.plist太傻就可以在这里改 
     866 
     867 
     868  869 
     870 件编译: 增加一个User-Defined Setting(Target "xxxx" 
     871 
     872 Info的build页的左下角那个齿轮中可以看到这个内容), 在Other C Flag里面填入, 
     873 
     874 比如要定义一个叫做LITE_VERSION的define值, 我们可以写上 "-DLITE_VERSION" 875 
     876 "-DLITE_VERSION=1". 那么在程序中就可以用 
     877 
     878     #if 
     879 
     880 defined(LITE_VERSION) 
     881 
     882     #else 
     883 
     884     #endif 
     885 
     886 这样的条件编译来部分差异化代码了 
     887 
     888 
     889     也许有些朋友记得我在代码区贴过的检测破解版的代码, 
     890 
     891 其中有一种检测方法就是看info.plist是文本还是二进制的, 那么我们能否建议一个模拟破解的target, 
     892 
     893 直接生成文本的info.plist以便测试呢? 
     894 
     895     当然可以, 
     896 
     897 在packing段内, 有一项叫"Info.plist Output Encoding", 默认值是Binary, 
     898 
     899 我们只要选成xml, 那么生成出的product.app内的info.plist就直接是文本样式的了. 
     900 
     901 
     902 
     903  904 
     905 外, 向Copy Bundle Resources, Compile Sources, Link Binary With 
     906 
     907 Libraries内添加/删除文件, 可以在要改动的文件上, 选择get info, 并且切换到Target页, 
     908 
     909 勾选要引用这个文件的target即可. 比如icon.png可以指定给默认target, 而icon_lite.png指定给lite 
     910 
     911 verion的target 
     912 
     913 
     914 
     915 大致就是如此吧, 懒得抓图了. 各位将就吧. 想到什么需要补充的, 我会加入 
     916 
     917 另外 
     918 
     919 一个英文教程:http://www.codza.com/free-iphone-app-version-from-the-same-xcode-project
     920 
     921 25、详解IOS SDK兼容性引导
     922 
     923 转自: http://mobile.51cto.com/iphone-284052.htm
     924 
     925  
     926 
     927 IOS SDK兼容性引导是本文要介绍的内容,主要是基于IOS SDK基础的开发介绍说明如何应用于XCode工程的基于IOS SDK开发的技术。来看详细内容讲解。
     928 
     929 1、用(weakly linked)弱连接类、方法和函数来支持在不同版本之间的程序运行
     930 
     931 2、弱连接整个框架(framework)
     932 
     933 3、为不同的IOS SDK选择不同的编译条件
     934 
     935 4、在代码中找出过时API的使用
     936 
     937 5、确定在运行时操作系统和框架(framework)的版本
     938 
     939 一 、在IOS中使用弱连接类
     940 
     941 在工程中使用类的弱连接的时候必须确保这些类在运行时的可用性,要不会引起动态连接的错误。
     942 
     943 在IOS4.2以后的版本都是使用NSObject class的方法来检测弱连接在运行时态的可用性,这种简单高效的机制使用了NS_CLASS_AVAILABLE的可用性宏。
     944 
     945 检测最近release的framework还不支持NS_CLASS_AVAILABLE的宏
     946 
     947 在支持NS_CLASS_AVAILABLE的宏framework的条件编译中,可以如下的使用
     948 
     949 if ([UIPrintInteractionController class]) {   
     950     // Create an instance of the class and use it.   
     951 } else {   
     952     // Alternate code path to follow when the   
     953     // class is not available.   
     954 } 
     955 如果你在不确保是否已经可以使用类方法的时候你可以使用NSClassFromString 方法来判断,使用方法如下:
     956 
     957 Class cls = NSClassFromString (@"NSRegularExpression");   
     958 if (cls) {   
     959     // Create an instance of the class and use it.   
     960 } else {   
     961     // Alternate code path to follow when the   
     962     // class is not available.   
     963 } 
     964 二、在方法,函数和符号中使用弱连接
     965 
     966 和使用类的弱连接一样,在使用它之前要确保方法函数和符号在运行时的可用性,要不在编译的时候会报错动态连接错误,假设你想使用新版本IOS 
     967 SDK的特性但是又想能够运行在低版本的SDK中,那么就要对早期的版本设置相应的开发target,在Object-c中 
     968 instancesRespondToSelector: 
     969 方法告诉我们所给的方法是否可用,例如:使用availableCaptureModesForCameraDevice:这个方法(在4.0以后才是可
     970 用的),我们可以这样使用它。
     971 
     972 1、检查一个Object-c方法的可用性
     973 
     974 if ([UIImagePickerController instancesRespondToSelector:   
     975               @selector (availableCaptureModesForCameraDevice:)]) {   
     976     // Method is available for use.   
     977     // Your code can check if video capture is available and,   
     978     // if it is, offer that option.   
     979 } else {   
     980     // Method is not available.   
     981     // Alternate code to use only still image capture.   
     982 } 
     983 判断一个弱连接的C函数是否可用,只要判断函数的地址是否返回为NULL,以CGColorCreateGenericCMYK 函数为例,我们可以像以下那样使用。
     984 
     985 2、检查C方法的可用性
     986 
     987 if (CGColorCreateGenericCMYK != NULL) {   
     988     CGColorCreateGenericCMYK (0.1,0.5.0.0,1.0,0.1);   
     989 } else {   
     990     // Function is not available.   
     991     // Alternate code to create a color object with earlier technology   
     992 }  
     993 要检测一个C方法是否可用,比较明确的为地址是否为NULL或零。你不能使用反运算符(!)来否定一个函数的可用性
     994 
     995 检测一个 external(extern)常量或一个通知的名字应当比较它的地址(address)--而不是符号的名称, 判断是否为NULL or nil
     996 
     997 三、弱连接整个Framework
     998 
     999 比如一个在高版本中才出现的Framework,想在低版本使用他的特性。那你就必须弱连接那个使用的Framework,详见官方的图解---(其实就是在添加进去的Framework的 required 改成 optional)
    1000 
    1001 http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/XcodeProjectManagement/
    1002 130-Files_in_Projects/project_files.html#//apple_ref/doc/uid/TP40002666-SW4 
    1003 四、条件编译for不同的SDK
    1004 
    1005 如果你不止基于一个IOS SDK编译,你就可能需要为base 
    1006 sdk使用条件化,可以使用在Availability.h中的定义。这个.h文件存在于系统的文件夹/usr/include的文件夹下,例如想在
    1007 Mac OS X v10.5(而不是IOS)中使用函数 CGColorCreateGenericCMYK
    1008 
    1009 使用预处理指令for条件编译
    1010 
    1011 #ifdef __MAC_OS_X_VERSION_MAX_ALLOWED   
    1012     // code only compiled when targeting Mac OS X and not iOS   
    1013     // note use of 1050 instead of __MAC_10_5   
    1014 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050   
    1015     if (CGColorCreateGenericCMYK != NULL) {   
    1016         CGColorCreateGenericCMYK(0.1,0.5.0.0,1.0,0.1);   
    1017     } else {   
    1018 #endif   
    1019     // code to create a color object with earlier technology   
    1020 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050   
    1021     }   
    1022 #endif   
    1023 #endif   
    1024 } 
    1025 五、寻找出在程序中使用的以过时的实例
    1026 
    1027 在IOS或Mac 
    1028 OS中有时候API会过时,但是过时不代表着那些就从Library或framework中删除,但是在使用的过程中会报出warning,并且在不远的
    1029 将来可能会被Apple从中移除。例如我们在code中使用了过时的函数 HPurge那么就会报出如下
    1030 
    1031 'HPurge' is deprecated (declared at /Users/steve/MyProject/main.c:51) 
    1032 所以我们应当在工程中查找出如下的警告并且修改。
    1033 
    1034 六、确定操作系统和Framework的版本
    1035 
    1036 在运行时检查IOS的版本
    1037 
    1038 NSString *osVersion = [[UIDevice currentDevice] systemVersion]; 
    1039 在运行时检查Mac OS X用Gestalt function 和 系统版本常量
    1040 
    1041 另外,对于许多的Framework你可以在运行时检查指定Framework的版本。
    1042 
    1043 例如:Application Kit(NSApplication.h)定义了NSAppKitVersionNumber常量---可以用来检查Application Kit Framework的版本
    1044 
    1045 1046 
    1047 APPKIT_EXTERN double NSAppKitVersionNumber;   
    1048 #define NSAppKitVersionNumber10_0 577   
    1049 #define NSAppKitVersionNumber10_1 620   
    1050 #define NSAppKitVersionNumber10_2 663   
    1051 #define NSAppKitVersionNumber10_2_3 663.6   
    1052 #define NSAppKitVersionNumber10_3 743   
    1053 #define NSAppKitVersionNumber10_3_2 743.14   
    1054 #define NSAppKitVersionNumber10_3_3 743.2   
    1055 #define NSAppKitVersionNumber10_3_5 743.24   
    1056 #define NSAppKitVersionNumber10_3_7 743.33   
    1057 #define NSAppKitVersionNumber10_3_9 743.36   
    1058 #define NSAppKitVersionNumber10_4 824   
    1059 #define NSAppKitVersionNumber10_4_1 824.1   
    1060 #define NSAppKitVersionNumber10_4_3 824.23   
    1061 #define NSAppKitVersionNumber10_4_4 824.33   
    1062 #define NSAppKitVersionNumber10_4_7 824.41   
    1063 #define NSAppKitVersionNumber10_5 949   
    1064 #define NSAppKitVersionNumber10_5_2 949.27   
    1065 #define NSAppKitVersionNumber10_5_3 949.33 
    1066 所以我们可以像如下使用:
    1067 
    1068 if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_0) {   
    1069   /* On a 10.0.x or earlier system */   
    1070 } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) {   
    1071   /* On a 10.1 - 10.1.x system */   
    1072 } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_2) {   
    1073   /* On a 10.2 - 10.2.x system */   
    1074 } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_3) {   
    1075   /* On 10.3 - 10.3.x system */   
    1076 } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) {   
    1077   /* On a 10.4 - 10.4.x system */   
    1078 } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {   
    1079   /* On a 10.5 - 10.5.x system */   
    1080 } else {   
    1081   /* 10.6 or later system */   
    1082 } 
    1083 跟以上一样在 NSObjCRuntime.h中用定义了NSFoundationVersionNumber全局常量
    1084 
    1085 小结:详解IOS SDK兼容性引导的内容介绍玩玩了,希望通过本文的学习能对你有所帮助!
    1086 
    1087 原文地址:http://blog.csdn.net/diyagoanyhacker/article/details/6673344
    1088 
    1089 26、NSDate 与 NSString 转换
    1090 
    1091 将字符串 “Fri Nov 11 09:06:27 +0800 2011” 转换成Date:
    1092 
    1093     NSDateFormatter *format = [[NSDateFormatter alloc] init];
    1094     NSLocale *enLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
    1095     [format setLocale:enLocale];
    1096     [enLocale release];
    1097     [format setDateFormat:@"EEE MMM dd HH:mm:ss ZZZ yyyy"];
    1098     NSDate *dateTime = [format dateFromString:message];
    1099 
    1100  
    1101 
    1102 将Date转换成字符串:
    1103 
    1104     NSDate *date = [NSDate date];
    1105     NSString * dateString = [format stringFromDate:date];
    1106 
    1107 //字符串转换成NSDate 需要设置NSLocale 否则真机上会失败。
    1108 
    1109 27、数组中存储数据查询
    1110 
    1111 NSMutableDictionary *userDic1 = [NSMutableDictionary dictionaryWithCapacity:10];
    1112     NSMutableDictionary *userDic2 = [NSMutableDictionary dictionaryWithCapacity:10];
    1113     [userDic1 setValue:@"Li" forKey:@"name"];
    1114     [userDic2 setValue:@"Wang" forKey:@"name"];
    1115     
    1116     NSArray *userArray = [NSArray arrayWithObjects:userDic1,userDic2,nil];
    1117     NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@"SELF.name contains[cd] %@ ",@"L"];
    1118     
    1119     NSMutableArray *searchArray = [NSMutableArray arrayWithArray:[userArray filteredArrayUsingPredicate:namePredicate]];
    1120     
    1121     NSLog(@"searchArray  == %@",searchArray);
    1122 
    1123 28、CoreText 总结
    1124 
    11251) NSAttributedString
    1126 
    1127       NSAttributedString 可以将一段文字中的部分文字设置单独的字体和颜色。
    1128 
    1129       与UITouch结合可以实现点击不同文字触发不同事件的交互功能。
    1130 
    1131        主要方法:
    1132 
    1133            - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
    1134 
    1135            可以设置某段文字的字体名称,颜色,下滑线等信息。
    1136 
    1137            - (void)removeAttribute:(NSString *)name range:(NSRange)range;
    1138 
    1139            移除之前设置的字体属性值。
    1140 
    1141            - (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;
    1142 
    1143            存储某段文字包含的信息(包括字体属性或其它,也可以存储一些自定义的信息) 
    1144 
    1145            - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range;
    1146 
    1147            通过location来获取某段文字中之前存储的信息NSDictionary
    1148 
    1149  
    1150 
    1151    //设置字体
    1152    CTFontRef aFont = CTFontCreateWithName((CFStringRef)textFont.fontName, textFont.pointSize, NULL);
    1153    if (!aFont) return;
    1154    CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(aFont, 0.0, NULL, kCTFontItalicTrait, kCTFontBoldTrait);    //将默认黑体字设置为其它字体 
    1155    [self removeAttribute:(NSString*)kCTFontAttributeName range:textRange];
    1156    [self addAttribute:(NSString*)kCTFontAttributeName value:(id)newFont range:textRange];
    1157    CFRelease(aFont);
    1158    CFRelease(newFont);
    1159    
    1160    //设置字体颜色
    1161    [self removeAttribute:(NSString*)kCTForegroundColorAttributeName range:textRange];
    1162    [self addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)textColor.CGColor range:textRange];
    1163    
    1164    //设置对齐 换行
    1165    CTTextAlignment coreTextAlign = kCTLeftTextAlignment;
    1166    CTLineBreakMode coreTextLBMode = kCTLineBreakByCharWrapping;
    1167    CTParagraphStyleSetting paraStyles[2] =
    1168    {
    1169        {.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void*)&coreTextAlign},
    1170        {.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void*)&coreTextLBMode},
    1171    };
    1172    CTParagraphStyleRef aStyle = CTParagraphStyleCreate(paraStyles, 2);
    1173    [self removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:textRange];
    1174    [self addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)aStyle range:textRange];
    1175    CFRelease(aStyle);
    1176 
    1177  
    1178 
    11792)Draw NSAttributedString
    1180 
    1181 
    1182        
    1183    CGContextRef cgc = UIGraphicsGetCurrentContext();
    1184    CGContextSaveGState(cgc);
    1185    
    1186    //图像方向转换
    1187    CGContextConcatCTM(cgc, CGAffineTransformScale(CGAffineTransformMakeTranslation(0, self.bounds.size.height), 1.f, -1.f));
    1188    
    1189    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)weiBoText);
    1190    drawingRect = self.bounds;
    1191    CGMutablePathRef path = CGPathCreateMutable();
    1192    CGPathAddRect(path, NULL, drawingRect);
    1193    textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL);
    1194    CGPathRelease(path);
    1195    CFRelease(framesetter);
    1196    
    1197    CTFrameDraw(textFrame, cgc);
    1198    CGContextRestoreGState(cgc);
    1199 
    12003)图文混排
    1201 
    1202      CTFrameRef  textFrame     // coreText 的 frame
    1203 
    1204      CTLineRef      line             //  coreText 的 line
    1205 
    1206      CTRunRef      run             //  line  中的部分文字
    1207 
    1208      相关方法:
    1209 
    1210    
    1211    CFArrayRef CTFrameGetLines    (CTFrameRef frame )      //获取包含CTLineRef的数组
    1212 
    1213    void CTFrameGetLineOrigins(
    1214    CTFrameRef frame,
    1215    CFRange range,
    1216    CGPoint origins[] )  //获取所有CTLineRef的原点
    1217 
    1218  CFRange CTLineGetStringRange  (CTLineRef line )    //获取line中文字在整段文字中的Range
    1219 
    1220  CFArrayRef CTLineGetGlyphRuns  (CTLineRef line )    //获取line中包含所有run的数组
    1221 
    1222  CFRange CTRunGetStringRange  (CTRunRef run )     //获取run在整段文字中的Range
    1223 
    1224  CFIndex CTLineGetStringIndexForPosition(
    1225    CTLineRef line,
    1226    CGPoint position )   //获取点击处position文字在整段文字中的index
    1227 
    1228    CGFloat CTLineGetOffsetForStringIndex(
    1229    CTLineRef line,
    1230    CFIndex charIndex,
    1231    CGFloat* secondaryOffset ) //获取整段文字中charIndex位置的字符相对line的原点的x值
    1232 
    1233   主要步骤:
    1234 
    1235        1)计算并存储文字中保含的所有表情文字及其Range
    1236 
    1237        2)替换表情文字为指定宽度的NSAttributedString
    1238 
    1239            CTRunDelegateCallbacks callbacks;
    1240    callbacks.version = kCTRunDelegateVersion1;
    1241    callbacks.getAscent = ascentCallback;
    1242    callbacks.getDescent = descentCallback;
    1243    callbacks.getWidth = widthCallback;
    1244    callbacks.dealloc = deallocCallback;
    1245    
    1246    CTRunDelegateRef runDelegate = CTRunDelegateCreate(&callbacks, NULL);
    1247    NSDictionary *attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:
    1248                                            (id)runDelegate, (NSString*)kCTRunDelegateAttributeName,
    1249                                            [UIColor clearColor].CGColor,(NSString*)kCTForegroundColorAttributeName,
    1250                                            nil];
    1251    
    1252    NSAttributedString *faceAttributedString = [[NSAttributedString alloc] initWithString:@"*" attributes:attrDictionaryDelegate];
    1253    
    1254    [weiBoText replaceCharactersInRange:faceRange withAttributedString:faceAttributedString];
    1255    [faceAttributedString release];    
    1256 
    1257        3)  根据保存的表情文字的Range计算表情图片的Frame
    1258 
    1259                 textFrame 通过CTFrameGetLines 获取所有line的数组 lineArray
    1260 
    1261                遍历lineArray中的line通过CTLineGetGlyphRuns获取line中包含run的数组 runArray
    1262 
    1263                遍历runArray中的run 通过CTRunGetStringRange获取run的Range
    1264 
    1265                判断表情文字的location是否在run的Range
    1266 
    1267                如果在 通过CTLineGetOffsetForStringIndex获取x的值 y的值为line原点的值
    1268 
    1269        4)Draw表情图片到计算获取到的Frame
    1270 
    1271  
    1272 
    12733)点击文字触发事件
    1274 
    1275   
    1276 
    1277   主要步骤:
    1278 
    1279        1) 根据touch事件获取点point
    1280 
    1281        2)   textFrame 通过CTFrameGetLineOrigins获取所有line的原点
    1282 
    1283        3) 比较point和line原点的y值获取点击处于哪个line
    1284 
    1285        4)  line、point 通过CTLineGetStringIndexForPosition获取到点击字符在整段文字中的    index   
    1286 
    1287        5)  NSAttributedString 通过index 用方法-(NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range  可以获取到点击到的NSAttributedString中存储的NSDictionary
    1288 
    1289        6) 通过NSDictionary中存储的信息判断点击的哪种文字类型分别处理
    1290 
    1291 23、视频播放、编辑
    1292 
    1293 
    1294 
    1295 
    1296  
    1297 
    1298 转载: http://www1.huachu.com.cn/read/readbookinfo.asp?sectionid=1000006772
    1299 
    1300 
    1301 对于不同的设备,视频功能是各不相同的。所有的设备都能够回放视频,但是仅有iPhone 3GS设备有记录视频的能力。对于每个设备而言,都存在API能够让您检测哪些功能是可用的和哪些功能是不可用的,这样就能够针对使用视频功能的所有用户创建优秀的用户体验。这一节内容讨论如何才能将视频集成到应用程序中,以及如何才能使用特定的设备记录视频。
    1302 
    1303 10.2.1  播放视频
    1304 
    1305 iPhone SDK提供了一个简单的控制器来在应用程序中播放视频。MPMoviePlayerController类位于MonoTouch.MediaPlayer名称空间中,它提供了播放影片、准备播放影片和停止播放影片的功能。程序清单10-9说明了如何开始播放视频。第一行代码显示的是实例化一个新的影片播放器对象,并将视频内容文件路径传入其构造函数内。第二行代码简单地调用了Play方法,该方法显示影片播放器并开始播放视频。
    1306 
    1307 程序清单10-9  播放视频文件
    1308 
    1309 var player = new MPMoviePlayerController(NSUrl.FromFilename("video.mp4"));
    1310 
    1311 player.Play();
    1312 
    1313 如果希望使用外部视频,并以渐进方式下载视频,而不是直接播放设备上的视频,那么就要使用NSUrl的FromString方法,而不是使用FromFilename,并将视频的URL地址传入其中。当然,需要使用自己的外部视频替换这里的URL字符串。
    1314 
    1315 var videoUrl = NSUrl.FromString("http://example.com/video.mp4")
    1316 
    1317 var player = new MPMoviePlayerController(videoUrl);
    1318 
    1319 player.Play();
    1320 
    1321 您也许会注意到,在视频开始播放之前有一个短暂的缓冲周期。这就是所谓的预加载过程。可以设置视频播放器上的通知,在视频已经开始预加载时让其引发一条消息,这样就能够显示加载屏幕,然后在预加载完成后开始显示视频。当视频完成播放或者用户改变视频的缩放比例时,也可以使用通知引发消息。
    1322 
    1323 使用NSNotificationCenter类的DefaultCenter属性添加观察者,从而在通知产生时引发这些消息。可以将观察者看作将事件添加到特定动作上的一种方式,使用字符串作为创建这些事件的方式,而不是使用您也许已经熟悉的C#内的强类型事件。对于本示例而言,只需要使用通知MPMoviePlayerContentPreloadDidFinishNotification和MPMoviePlayerPlaybackDid- FinishNotification。另一个通知名为MPMoviePlayerScalingModeDidChangeNotification。还要添加两个NSObject类型的类变量,它们可以作为预加载和回放完成的观察者。使用AddObserver方法,为每个观察者传入一个动作方法,当通知被调用时这些动作方法就会运行。可以使用Lambda表达式以内联方式放置这段代码。当预加载通知被激活以后,只需要开始播放视频,因此可以调用MPMoviePlayerController上的Play方法;当回放通知激活以后,需要移除观察者,并清除影片播放器实例。可以使用活动指示器确保让用户知道当应用程序启动时正在预加载视频。程序清单10-10给出了完成这项工作的示例代码。同样,需要确保改变第8行代码中的URL,让其指向选择的外部视频。
    1324 
    1325 程序清单10-10  使用影片播放器观察者
    1326 
    1327 MPMoviePlayerController moviePlayer;
    1328 
    1329 NSObject didFinishPreload, didFinishPlayback;
    1330 
    1331 
    1332 public override void ViewDidLoad()
    1333 
    1334 {
    1335 
    1336   base.ViewDidLoad ();
    1337 
    1338  
    1339 
    1340   var videoUrl = NSUrl.FromString("http://example.com/video.mp4");
    1341 
    1342   moviePlayer = new MPMoviePlayerController(videoUrl);
    1343 
    1344  
    1345 
    1346   activityIndicator.StartAnimating();
    1347 
    1348 
    1349   var centre = NSNotificationCenter.DefaultCenter;
    1350 
    1351   var preloadFinish = "MPMoviePlayerContentPreloadDidFinishNotification";
    1352 
    1353   didFinishPreload = centre.AddObserver(preloadFinish,
    1354 
    1355      (notify) => {
    1356 
    1357         Console.WriteLine ("Start playing movie");
    1358 
    1359         activityIndicator.StopAnimating();
    1360 
    1361         moviePlayer.Play();
    1362 
    1363      });
    1364 
    1365 
    1366   var playbackFinished = "MPMoviePlayerPlaybackDidFinishNotification";
    1367 
    1368   didFinishPlayback = centre.AddObserver(playbackFinished,
    1369 
    1370      (notify) => {
    1371 
    1372         Console.WriteLine ("Movie finished, Clean up");
    1373 
    1374 
    1375         centre.RemoveObserver(didFinishPreload);
    1376 
    1377         centre.RemoveObserver(didFinishPlayback);
    1378 
    1379 
    1380         activityIndicator.Hidden = true;
    1381 
    1382 
    1383         moviePlayer.Dispose();
    1384 
    1385         moviePlayer = null;
    1386 
    1387      }); }
    1388 
    1389 }
    1390 
    1391 10.2.2  定制视频播放器
    1392 
    1393 影片播放器提供的功能是相当有限的,仅允许对两个属性根据需要进行调整,这两个属性是ScalingMode和MovieControlMode。
    1394 
    1395 缩放模式对播放影片的长宽比进行设置。可用的长宽比选项为Fill、AspectFill、AspectFit和None。
    1396 
    1397 Fill选项用于让视频填满整个屏幕,这样视频的边缘会与屏幕吻合,但是可能无法保持原有的长宽比。
    1398 
    1399 AspectFill选项在视频填满整个屏幕时不会扭曲视频,但是确实会对视频进行裁剪,这样视频才能够无缝地填满这个屏幕。
    1400 
    1401 AspectFit选项会保留视频原有的长宽比,并让视频的边缘尽可能地与屏幕吻合,但如果视频不是完全吻合,那么可能会露出背景视图。
    1402 
    1403 None选项不会调整视频,而是按照视频自身的大小进行播放。
    1404 
    1405 使用MPMovieScalingMode枚举,可以将ScalingMode设置为这个列表中的任何选项。参见图10-10~图10-13,其中给出了每一种缩放模式的示例。播放器的背景设置为蓝色(在这些图中,背景是以浅灰色打印版本进行显示的),因此可以看到视频大小和播放器大小之间的差异。注意,在这个示例中,Aspect Fit和Fill视频是一样的。这是因为视频的当前长宽比允许视频的边缘与屏幕吻合,而无须改变长宽比。
    1406 
    1407 
    140810-1010-11  
    1409 
    1410 
    141110-1210-13  
    1412 
    1413 另外一个可以针对视频播放器修改的属性是MovieControlMode。使用MPMovieControlMode枚举,可以将控件模式设置为Default、Hidden或VolumeOnly。图10-14和图10-15给出了Default和VolumeOnly控件模式。Hidden模式隐藏了屏幕上所有默认的动作;如果希望让自己提供的用户界面位于视频的上方,那么该模式就很有用。
    1414 
    1415 
    141610-1410-15  
    1417 
    1418 影片播放器本身是作为一个关键窗口出现在屏幕上的。为了将自定义界面添加到影片播放器关键窗口的上方,可以从应用程序中具有的窗口列表内获取该关键窗口的引用(关键窗口在本质上是窗口框架内可以获得的最顶层的可见视图)。然后可以简单地将子视图添加到影片播放器关键窗口中。因为影片播放器是以横屏模式出现的,所以必须对叠加视图进行变换,从而使其能够与横屏模式匹配。程序清单10-11说明了如何使用代码实现此处提到的所有内容。
    1419 
    1420 程序清单10-11  在视频播放器上叠加视图
    1421 
    1422 public MPMoviePlayerController mPlayer;
    1423 
    1424 
    1425 public override void ViewDidLoad ()
    1426 
    1427 {
    1428 
    1429   base.ViewDidLoad ();
    1430 
    1431 
    1432   var button = UIButton.FromType(UIButtonType.RoundedRect);
    1433 
    1434   button.Frame = new RectangleF(0f, 20f, 320f, 40f);
    1435 
    1436   button.SetTitle("Play Video", UIControlState.Normal);
    1437 
    1438   button.TouchUpInside += delegate(object sender, EventArgs e)
    1439 
    1440   {
    1441 
    1442      PlayMovie ();
    1443 
    1444 
    1445      var windows = UIApplication.SharedApplication.Windows;
    1446 
    1447      if(windows.Count() > 1)
    1448 
    1449      {
    1450 
    1451         var moviePlayerWindow = UIApplication.SharedApplication.KeyWindow;
    1452 
    1453         var customView = new MyOverlayView(this);
    1454 
    1455         moviePlayerWindow.AddSubview(customView);
    1456 
    1457      }
    1458 
    1459   };
    1460 
    1461   this.View.AddSubview(button);
    1462 
    1463 }
    1464 
    1465 
    1466 void PlayMovie ()
    1467 
    1468 {
    1469 
    1470   var url = NSUrl.FromFilename("video.mp4");
    1471 
    1472   mPlayer = new MPMoviePlayerController(url);
    1473 
    1474   mPlayer.Play();
    1475 
    1476 }
    1477 
    1478 
    1479 ...
    1480 
    1481 
    1482 public class MyOverlayView : UIView
    1483 
    1484 {
    1485 
    1486   public MyOverlayView (MainViewController mvc)
    1487 
    1488   {
    1489 
    1490      this.Frame = new RectangleF(0f, 0f, 320f, 480f);
    1491 
    1492      this.Transform = CGAffineTransform.MakeRotation((float)(Math.PI / 2));
    1493 
    1494 
    1495      UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
    1496 
    1497      button.SetTitle("Pause", UIControlState.Normal);
    1498 
    1499      button.Frame = new RectangleF(65f, 360f, 190f, 32f);
    1500 
    1501      button.TouchUpInside += delegate(object sender, EventArgs e) {
    1502 
    1503         Console.WriteLine ("Paused the video");
    1504 
    1505         mvc.mPlayer.Pause();
    1506 
    1507      };
    1508 
    1509 
    1510      this.AddSubview(button);
    1511 
    1512   }
    1513 
    1514 }
    1515 
    1516 图10-16显示的是在程序清单10-11中创建的叠加视图。
    1517 
    1518 
    151910-16  
    1520 
    1521 10.2.3  选取视频
    1522 
    1523 为了让用户可以从存储在设备上的视频列表中选取视频,可以使用UIImagePickerController,在本章前面已经使用过该类。因为面向iPhone的视频功能非常类似于摄像头功能,所以看到视频功能属于UIImagePickerController类的组成部分并不令人感到惊奇。在程序清单10-6中,我们使用IsSourceTypeAvailable方法来确定设备是否具有摄像头。因为视频功能仅限于iPhone3GS模型,所以只是弄清楚是否存在摄像头并不足够。这时就需要使用UIImagePickerController类上的AvailableMediaTypes静态方法。
    1524 
    1525 AvailableMediaTypes方法以源类型作为输入,返回设备上可用媒体类型的数组。图像的媒体类型为public.image,而视频的媒体类型为public.movie。如果该方法返回public.movie类型,那么可以将UIImagePickerController实例的MediaTypes属性设置为仅有public.movie媒体类型。程序清单10-12给出了以这种方式设置的选取器。
    1526 
    1527 程序清单10-12  使用图像选取器控制器选取视频
    1528 
    1529 if (HasVideoSupport())
    1530 
    1531 {
    1532 
    1533   UIImagePickerController picker = new UIImagePickerController();
    1534 
    1535   picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
    1536 
    1537   picker.MediaTypes = new []{"public.movie"};
    1538 
    1539   picker.Delegate = new MyImagePickerDelegate(this);
    1540 
    1541   this.PresentModalViewController(picker, true);
    1542 
    1543 }
    1544 
    1545 else
    1546 
    1547 {
    1548 
    1549   using (var alert = new UIAlertView("Whoops", "No video support found",
    1550 
    1551                                       null, "Ok!", null))
    1552 
    1553   {
    1554 
    1555      alert.Show();
    1556 
    1557   }
    1558 
    1559 }
    1560 
    1561 
    1562 ...
    1563 
    1564 
    1565 bool HasVideoSupport()
    1566 
    1567 {
    1568 
    1569   var cameraType = UIImagePickerControllerSourceType.Camera;
    1570 
    1571   var cameraSupport =
    1572 
    1573                  UIImagePickerController.IsSourceTypeAvailable(cameraType);
    1574 
    1575   return (!cameraSupport) ? false :
    1576 
    1577          UIImagePickerController.AvailableMediaTypes(cameraType)
    1578 
    1579                                        .Contains("public.movie");
    1580 
    1581 }
    1582 
    1583 在显示该选取器时,注意到您只看到了视频,因为视频是可以选取的唯一的媒体类型。图10-17说明了如何显示只选取视频的选取器。
    1584 
    1585 
    158610-17  
    1587 
    1588 在选取视频以后,该选取器使用与图像选取器相同的回调:FinishedPickingMedia。NSDictionary带有两个键:UIImagePickerControllerMediaURL和UIImagePickerControllerMediaType。媒体URL包含一个指向所选择视频的临时位置的NSUrl对象。这就是您可以处理视频的地方—— 要么将视频移动到Documents文件夹中,要么通过其他方式使用视频。临时视频存储在应用程序的tmp文件夹中,OS在认为合适的时候会将其清除。
    1589 
    1590 10.2.4  记录视频
    1591 
    1592 使用iPhone记录视频非常类似于使用iPhone进行拍照。在前一个示例中,可以仅将源类型设置为摄像头而不是图片库的默认源类型,所有这些设置都是为了记录视频而不是拍摄照片。当然,这就是假设您已经使用AvailableMediaTypes方法验证了该设备可以记录视频。注意,摄像头控件会发生变化,从而反映出是记录视频而不是拍摄照片。作为可选项,可以选择通过将ShowsCameraControls设置为false来隐藏摄像头控件;然而,在编写本书的时候,如果不使用默认的摄像头控件,那么还没有方式可以通过编程来记录视频。程序清单10-13是设置UIImagePickerController以记录视频的一个示例。图10-18显示的是视频记录屏幕。
    1593 
    1594 程序清单10-13  记录视频
    1595 
    1596 public override void ViewDidLoad ()
    1597 
    1598 {
    1599 
    1600   base.ViewDidLoad ();
    1601 
    1602 
    1603   UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
    1604 
    1605   button.Frame = new RectangleF(0f, 30f, 320, 40f);
    1606 
    1607   button.SetTitle("Record Video", UIControlState.Normal);
    1608 
    1609   button.TouchUpInside += delegate(object sender, EventArgs e) {
    1610 
    1611 
    1612      var cameraType = UIImagePickerControllerSourceType.Camera;
    1613 
    1614      if(HasVideoSupport())
    1615 
    1616      {
    1617 
    1618         UIImagePickerController picker = new UIImagePickerController();
    1619 
    1620         picker.SourceType = cameraType;
    1621 
    1622         picker.MediaTypes = new []{"public.movie"};
    1623 
    1624         picker.Delegate = new MyImagePickerDelegate(this);
    1625 
    1626         this.PresentModalViewController(picker, true);
    1627 
    1628      }
    1629 
    1630      else
    1631 
    1632      {
    1633 
    1634         using (var alert = new UIAlertView("Whoops",
    1635 
    1636                           "No video support found", null, "Ok!", null))
    1637 
    1638         {
    1639 
    1640            alert.Show();
    1641 
    1642         }
    1643 
    1644      }
    1645 
    1646   };
    1647 
    1648   this.View.AddSubview(button);
    1649 
    1650 }
    1651 
    1652 
    1653 ...
    1654 
    1655 
    1656 bool HasVideoSupport()
    1657 
    1658 {
    1659 
    1660   var cameraType = UIImagePickerControllerSourceType.Camera;
    1661 
    1662   var cameraSupport =
    1663 
    1664                  UIImagePickerController.IsSourceTypeAvailable(cameraType);
    1665 
    1666   return (!cameraSupport) ? false :
    1667 
    1668          UIImagePickerController.AvailableMediaTypes(cameraType)
    1669 
    1670                                        .Contains("public.movie");
    1671 
    1672 }
    1673 
    1674 
    167510-18  
    1676 
    1677 在记录视频时,还可以设置视频记录的质量。质量越低,那么得到的视频文件越小。可以像下面的代码这样使用UIImagePickerControllerQualityType枚举设置图像选取器的VideoQuality属性:
    1678 
    1679 picker.VideoQuality =  UIImagePickerControllerQualityType.Low;
    1680 
    1681 该枚举提供3个质量选项:High、Medium和Low。视频记录中使用的默认设置是Medium。在记录视频时可以使用的另外一个属性是VideoMaximumDuration,这个属性用于设置记录视频的最长持续时间(单位为秒)。视频最长可以是10分钟,记录视频的默认时间值也是10分钟。
    1682 
    1683 10.2.5  编辑视频
    1684 
    1685 采用与通过UIImagePickerController编辑图像相同的方式,在记录或选取视频时也可以将AllowEditing属性设置为true。这样,从图像选取器中选取了视频以后,就能够有一个接口对视频进行裁剪。与编辑图像时不同,在完成编辑时,只会使用NSDictionary中的UIImagePickerCon-trollerMediaURL键获得临时裁剪或编辑的视频(而不是原始视频),该键在选择或记录视频后可用。临时创建的视频最终会被设备自动地清除。UIImagePickerControllerMediaURL对象属于NSUrl类型,需要将该视频对象强制转换为NSUrl类型来提取定位该文件所需的Path属性。图10-19显示了图像选取器视频编辑器的外观。
    1686 
    1687 
    168810-19
    1689 
    1690 但是,视频选取器不是编辑视频最值得推荐的方式。对于编辑视频而言,最好使用专门的UIVideoEditorController类作为替代。该视频编辑器控制器为您提供了一个编辑窗口,它类似于图像选取器所使用的编辑窗口。然而,注意到用户有两个选项可以选择:Cancel和Save。UIVideoEditorController类对此提供了3个不同的事件:
    1691 
    1692 UserCancelled  当用户单击Cancel按钮时处理这个事件。
    1693 
    1694 Saved  当用户单击Save按钮时处理该事件。
    1695 
    1696 Failed  当产生无法预料的错误时会引发该事件,例如视频的格式无法编辑这样的错误。
    1697 
    1698 Saved事件返回编辑好的视频文件的路径,Failed事件返回一个NSError对象,UserCancelled事件不会返回任何额外的信息。如果希望获得原始文件的路径,那么可以将发送方强制转换为UIVideoEditorController对象,然后使用该对象的VideoPath属性。
    1699 
    1700 
    1701 视频编辑器只能用在直屏模式中
    1702 
    1703 
    1704 
    1705 
    1706 有了视频编辑器以后,通过分别设置VideoQuality和VideoMaximumDuration属性,就可以将编辑好的视频设置为较低的质量和强制编辑好的视频具有最大时间长度。
    1707 
    1708 创建视频编辑界面是相当直观的。实例化一个新的UIVideoEditorController,将VideoPath设置为希望编辑的视频的路径,然后将视频编辑器作为一个模态视图展示。因为无法知道运行该应用程序的iPhone是否支持对视频进行编辑,所以需要使用视频编辑器的静态方法CanEditVideoAtPath。传入视频路径,如果该视频可以编辑,那么该方法就返回true。程序清单10-14给出了一个创建专用视频编辑器界面的示例,图10-20给出了UIVideoEditorController界面的显示外观。
    1709 
    1710 程序清单10-14  使用专用视频编辑器界面
    1711 
    1712 if(UIVideoEditorController.CanEditVideoAtPath(ChosenVideoPath))
    1713 
    1714 {
    1715 
    1716   var videoEditor = new UIVideoEditorController();
    1717 
    1718   videoEditor.VideoPath = ChosenVideoPath;
    1719 
    1720   videoEditor.Saved += delegate(object sender, UIPathEventArgs e) {
    1721 
    1722      this.DismissModalViewControllerAnimated(true);
    1723 
    1724      // Handle edited video with e.Path
    1725 
    1726   };
    1727 
    1728   videoEditor.Failed += delegate(object sender, NSErrorEventArgs e) {
    1729 
    1730      this.DismissModalViewControllerAnimated(true);
    1731 
    1732      // Handle error here with e.Error
    1733 
    1734   };
    1735 
    1736   videoEditor.UserCancelled += delegate(object sender, EventArgs e) {
    1737 
    1738      this.DismissModalViewControllerAnimated(true);
    1739 
    1740      // Handle cancel
    1741 
    1742   };
    1743 
    1744   this.PresentModalViewController(videoEditor, true);
    1745 
    1746 }
    1747 
    1748 
    1749 图10-20
    1750 
    1751 10.2.6  将视频保存到相册
    1752 
    1753 在将图像保存到相册时,要使用UIImage类上的静态方法保存文件。因为对视频文件的所有引用都使用路径而不是内存中的对象,所以UIVideo静态类提供了将视频保存到相册中所需的方法。视频功能仅限于特定的设备,因此在将视频保存到相册之前,需要检查一下该设备是否能够真正将视频保存到其相册中。静态方法IsCompatibleWithSavedPhotosAlbum提供了这种功能,如果传入可以保存到相册的视频的路径,那么该方法就会返回true。
    1754 
    1755 为了将视频保存到相册中,一旦通过检查确定该设备确实可以保存视频,那么就可以使用UIVideo类上的静态方法SaveToPhotosAlbum。将希望保存的视频的路径传入该方法,当保存视频以后会触发一个回调函数。程序清单10-15给出了完成这些任务的代码。
    1756 
    1757 程序清单10-15  将视频保存到相册
    1758 
    1759 var videoPath = videoSavePath;
    1760 
    1761 if(UIVideo.IsCompatibleWithSavedPhotosAlbum(videoPath))
    1762 
    1763 {
    1764 
    1765   UIVideo.SaveToPhotosAlbum(videoPath, delegate (string path,
    1766 
    1767                                                  NSError errors)
    1768 
    1769   {
    1770 
    1771      using (var alert = new UIAlertView("Success", "Video saved!",
    1772 
    1773                                         null, "Ok!", null))
    1774 
    1775      {
    1776 
    1777         alert.Show();
    1778 
    1779      }
    1780 
    1781   });
    1782 
    1783 }
    1784 
    1785 
    1786 24、CoreText基础-字体必修课
    1787 
    1788 
    1789 转自:http://www.dreamingwish.com/dream-2011/coretext-ji-chu-font-basis.html
    1790 
    1791 介绍一些字体的术语,以及对应的英文名称
    1792 
    1793 字体(Font):是一系列字号、样式和磅值相同的字符(例如:10磅黑体Palatino)。现多被视为字样的同义词
    1794 
    1795 字面(Face):是所有字号的磅值和格式的综合
    1796 
    1797 字体集(Font family):是一组相关字体(例如:Franklin family包括Franklin Gothic、Fran-klinHeavy和Franklin Compressed)
    1798 
    1799 磅值(Weight):用于描述字体粗度。典型的磅值,从最粗到最细,有极细、细、book、中等、半粗、粗、较粗、极粗
    1800 
    1801 样式(Style):字形有三种形式:Roman type是直体;oblique type是斜体;utakuc type是斜体兼曲线(比Roman type更像书法体)。
    1802 
    1803 x高度(X height):指小写字母的平均高度(以x为基准)。磅值相同的两字母,x高度越大的字母看起来比x高度小的字母要大
    1804 
    1805 Cap高度(Cap height):与x高度相似。指大写字母的平均高度(以C为基准)
    1806 
    1807 下行字母(Descender):例如在字母q中,基线以下的字母部分叫下伸部分
    1808 
    1809 上行字母(Ascender):x高度以上的部分(比如字母b)叫做上伸部分
    1810 
    1811 基线(Baseline):通常在x、v、b、m下的那条线
    1812 
    1813 描边(Stroke):组成字符的线或曲线。可以加粗或改变字符形状
    1814 
    1815 衬线(Serif):用来使字符更可视的一条水平线。如字母左上角和下部的水平线。
    1816 
    1817 无衬线(Sans Serif):可以让排字员不使用衬线装饰。
    1818 
    1819 方形字(Block):这种字体的笔画使字符看起来比无衬线字更显眼,但还不到常见的衬线字的程度。例如Lubalin Graph就是方形字,这种字看起来好像是木头块刻的一样
    1820 
    1821 手写体脚本(Calligraphic script):是一种仿效手写体的字体。例如Murray Hill或者Fraktur字体
    1822 
    1823 艺术字(Decorative):像绘画般的字体
    1824 
    1825 Pi符号(Pisymbol):非标准的字母数字字符的特殊符号。例如Wingdings和Mathematical Pi
    1826 
    1827 连写(Ligature):是一系列连写字母如fi、fl、ffi或ffl。由于字些字母形状的原因经常被连写,故排字员已习惯将它们连写。
    1828 
    1829 
    1830 
    1831 25、准确计算CoreText高度的方法
    1832 
    1833 - (int)getAttributedStringHeightWithString:(NSAttributedString *)  string  WidthValue:(int) width
    1834 {
    1835    int total_height = 0;
    1836    
    1837    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);    //string 为要计算高度的NSAttributedString
    1838    CGRect drawingRect = CGRectMake(0, 0, width, 1000);  //这里的高要设置足够大
    1839    CGMutablePathRef path = CGPathCreateMutable();
    1840    CGPathAddRect(path, NULL, drawingRect);
    1841    CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL);
    1842    CGPathRelease(path);
    1843    CFRelease(framesetter);
    1844    
    1845    NSArray *linesArray = (NSArray *) CTFrameGetLines(textFrame);
    1846    
    1847    CGPoint origins[[linesArray count]];
    1848    CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), origins);
    1849    
    1850    int line_y = (int) origins[[linesArray count] -1].y;  //最后一行line的原点y坐标
    1851    
    1852    CGFloat ascent;
    1853    CGFloat descent;
    1854    CGFloat leading;
    1855    
    1856    CTLineRef line = (CTLineRef) [linesArray objectAtIndex:[linesArray count]-1];
    1857    CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
    1858    
    1859    total_height = 1000 - line_y + (int) descent +1;    //+1为了纠正descent转换成int小数点后舍去的值
    1860    
    1861    CFRelease(textFrame);
    1862    
    1863    return total_height;
    1864    
    1865 }
    1866 
    1867  
    1868 
    1869 //关于line坐标位置y为下图黑线所在位置 descent为黑线下部分字体的高度
    1870 
    1871 //关于字体各部分高度说明  http://ios-iphone.diandian.com/post/2012-03-29/18055023  
    1872 
    1873 
    1874 26、自定义拷贝、粘贴窗口
    1875 
    18761)、重写canBecomeFirstResponder方法
    1877 
    1878   - (BOOL)canBecomeFirstResponder{
    1879   
    1880   [super canBecomeFirstResponder];
    1881   return YES;
    1882 }
    1883 
    18842)、创建自定义UIMenuController
    1885 
    1886   UIMenuItem *share = [[UIMenuItem alloc] initWithTitle:@"分享" action:@selector(share:)];
    1887    UIMenuItem *email = [[UIMenuItem alloc] initWithTitle:@"邮件" action:@selector(email:)];
    1888    UIMenuItem *print = [[UIMenuItem alloc] initWithTitle:@"打印" action:@selector(print:)];
    1889 
    1890    UIMenuController *menu = [UIMenuController sharedMenuController];
    1891    [menu setMenuItems:[NSArray arrayWithObjects:share, email,print, nil]];
    1892    [menu setTargetRect:self.frame inView:self.superview];
    1893    [menu setMenuVisible:YES animated:YES];
    1894 
    18953)、判断显示哪个menu
    1896 
    1897 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
    1898 {
    1899   [super canPerformAction:action withSender:sender];
    1900  
    1901   if ( action == @selector(share:) || action == @selector(email:) || action == @selector(print:))
    1902   {
    1903       return YES;    
    1904   }
    1905   else
    1906   {
    1907       return NO;
    1908   }
    1909 }
    1910 
    1911  
    1912 
    1913 
    1914 27、iOS本地推送通知方法
    1915 
    1916   
    1917 可在应用后台执行时,本地弹出推送通知,也可以定时触发推送。
    1918 
    1919 - (void)applicationDidEnterBackground:(UIApplication *)application
    1920 {
    1921    
    1922    UIDevice* device = [UIDevice currentDevice];
    1923    
    1924    BOOL backgroundSupported = NO;
    1925    
    1926    if ([device respondsToSelector:@selector(isMultitaskingSupported)])
    1927    {    
    1928        backgroundSupported = device.multitaskingSupported;
    1929    }
    1930    if (backgroundSupported && _bgTask==UIBackgroundTaskInvalid)
    1931    {
    1932        UIApplication *app = [UIApplication sharedApplication];
    1933        
    1934        _bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    1935        }];  
    1936        
    1937        
    1938        dispatch_async(dispatch_get_main_queue(), ^{
    1939            
    1940            while (app.applicationState==UIApplicationStateBackground && _bgTask!=UIBackgroundTaskInvalid  && [app backgroundTimeRemaining] > 10)  
    1941            {
    1942                [NSThread sleepForTimeInterval:1];
    1943                NSLog(@"background task %d left left  time %d.", _bgTask, (int)[app backgroundTimeRemaining]);
    1944                                
    1945                if ([app backgroundTimeRemaining] < 580)
    1946                {
    1947                    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
    1948                    if (localNotif)
    1949                    {
    1950                        localNotif.alertBody = [NSString stringWithString:@"测试本地通知消息,后台提示功能。"];
    1951                        localNotif.alertAction = NSLocalizedString(@"查看", nil);
    1952                        localNotif.soundName = UILocalNotificationDefaultSoundName;
    1953                        localNotif.applicationIconBadgeNumber = 1;            
    1954                        [application presentLocalNotificationNow:localNotif];
    1955                        [localNotif release];
    1956                        break;
    1957                    }
    1958                }
    1959            }
    1960            
    1961            NSLog(@"background task %d finished.", _bgTask);     
    1962            [app endBackgroundTask:_bgTask];
    1963            _bgTask = UIBackgroundTaskInvalid;   
    1964               
    1965        });      
    1966    }
    1967 
    1968 }
    1969 
    1970 28、CoreText绘制文本出现行间距不等及解决办法
    1971 
    1972 
    1973 转自: http://willonboy.tk/?p=1163
    1974 
    1975 
    1976 
    1977 
    1978 
    1979 
    1980 
    1981 
    1982 
    1983 
    1984 
    1985 
    1986 
    1987 
    1988 
    1989 
    1990 
    1991  
    1992 
    1993 
    1994 最终在http://www.cocoanetics.com/2012/02/radar-coretext-line-spacing-bug/
    1995 
    1996 找到了DTCoreText库
    1997 
    1998 
    1999 Radar: “CoreText Line Spacing Bug” b 05, 2012
    2000 
    2001 I finally got around to report an annoying bug in CoreText that has been bugging us in DTCoreText until I wrote a method to correct line origins as a workaround. rdar://10810114
    2002 
    2003 The annoying thing about this bug is that it adds visual noise to otherwise pristinely rendered text. Especially on larger font sizes you see that additional space appears before each CTLine that ends with a paragraph break (
    ).
    2004 
    2005 UPDATE: This is a duplicate of rdar://9931615.
    2006 
    2007 
    2008 
    2009 CoreText Line Spacing BugSummary
    2010 
    2011 CoreText inserts too much space before any line that ends with a 
    . This extra space depends on the font and font size. On large print this causes visual noise by not being uniform.
    2012 
    2013 Steps to Reproduce
    2014 
    2015 Create a CTFrame from a CTFrameSetter with a string that is long enough to wrap and that contains paragraph breaks. Use a non-UI font, like for example AriaMT.
    2016 
    2017 Expected Results
    2018 
    2019 Line origins should be spaced by exactly the same distance for identical text and identical attributes.
    2020 
    2021 Actual Results
    2022 
    2023 Each line that ends with a paragraph break is shifted down. With the system UI font, size 54 baselines are spaced exactly 64 pixels apart. With ArialMT, size 54, baseline spacing differs between 62 and 65.
    2024 
    2025 Regression
    2026 
    2027 This has been a bug since before iOS 4.3.
    2028 
    2029 Notes
    2030 
    2031 This does not occur with all fonts, Using a system font the spacing is precisely correct. I have attached a project to demonstrate the issue. See TextView.m.
    2032 
    2033 It appears that the text metrics for an (invisible) paragraph glyph are miscalculated. Since the glyph is not visible you’d expect neither and ascender nor descender value. But instead the descender is too large. If you walk through the entire line and get the maximum ascenders and descenders the value is correct if you omit the 
     in this calculation.
    2034 
    2035 In short: A trailing 
     messes up the font metrics for the entire CTLine.
    2036 
    2037 Attachment: CoreTextLineOrigins Demo Project
  • 相关阅读:
    刘汝佳,竖式问题
    二叉树
    sort
    hash
    贪心算法
    FFT,NTT 专题
    hdu 5861 Road 两棵线段树
    hdu 5862 Counting Intersections
    hdu 5833 Zhu and 772002 ccpc网络赛 高斯消元法
    hdu 5800 To My Girlfriend + dp
  • 原文地址:https://www.cnblogs.com/niit-soft-518/p/4285995.html
Copyright © 2011-2022 走看看