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)throttleBandwidth:(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 2、在方法,函數和符號中使用弱鏈接 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 3、弱鏈接整個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 4、條件編譯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 5、尋找出在程序中使用的以過期的實例 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 6、肯定操做系統和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 1125 (1) 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 1179 (2)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 1200 (3)圖文混排 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 1273 (3)點擊文字觸發事件 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 1408 圖 10-10 圖 10-11 1409 1410 1411 圖 10-12 圖 10-13 1412 1413 另一個能夠針對視頻播放器修改的屬性是MovieControlMode。使用MPMovieControlMode枚舉,能夠將控件模式設置爲Default、Hidden或VolumeOnly。圖10-14和圖10-15給出了Default和VolumeOnly控件模式。Hidden模式隱藏了屏幕上全部默認的動做;若是但願讓本身提供的用戶界面位於視頻的上方,那麼該模式就頗有用。 1414 1415 1416 圖 10-14 圖 10-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 1519 圖 10-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 1586 圖 10-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 1675 圖 10-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 1688 圖 10-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 1876 (1)、重寫canBecomeFirstResponder方法 1877 1878 - (BOOL)canBecomeFirstResponder{ 1879 1880 [super canBecomeFirstResponder]; 1881 return YES; 1882 } 1883 1884 (2)、建立自定義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 1895 (3)、判斷顯示哪一個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 (\n). 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 \n. 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 \n in this calculation. 2034 2035 In short: A trailing \n messes up the font metrics for the entire CTLine. 2036 2037 Attachment: CoreTextLineOrigins Demo Project