程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> Core Text實現編輯的時候會用到的

Core Text實現編輯的時候會用到的

編輯:關於C
首先說一下實現的原理,  首先當手指開始觸摸屏幕  以及滑動的時候,  效果與畫矩形框是一樣的 因此  此時的代碼也機會沒有區別, 當手指松開後   在當前的矩形框處創建一個臨時的textView ,並且背景變為灰色,textView    編輯結束, 在textView的  完成委托方法中    去掉灰色的背景  去掉臨時的textView    在相同的位置上 利用coreText   顯示出剛才編輯的內容   首先 手指觸摸 會調用到 TextTool.m ? 1 2 3 4 5 6 7 8 9 10 11 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {   UIView *touchedView = [delegate viewForUseWithTool:self];  //注意下面這句代碼   [touchedView endEditing:YES];   // we only track one touch at a time for this tool.   UITouch *touch = [[event allTouches] anyObject];   // remember the touch, and its original start point, for future   [trackingTouches addObject:touch];   CGPoint location = [touch locationInView:touchedView];   [startPoints addObject:[NSValue valueWithCGPoint:location]]; }  代碼  除了注釋的那一句 基本上與前面的矩形  是相同的  紀錄下來  UITouch 的實例  以及 開始的點  而注釋那一句 得到的touchedView  就是dudelView 如果此處設置為yes   在textView 成為第一響應 彈出鍵盤後,我們可以直接觸摸view  來取消TextView的第一響應狀態     隨著手指移動  不斷調用到  touchMoved   但是 與前面矩形的實現一樣 這裡的touchMoved方法為空  畫出臨時矩形的實現代碼在 drawTemporary 方法中 TextTool.m ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - (void)drawTemporary {   if (self.completedPath) {     [delegate.strokeColor setStroke];     [self.completedPath stroke];   } else {     UIView *touchedView = [delegate viewForUseWithTool:self];     for (int i = 0; i<[trackingTouches count]; i++) {       UITouch *touch = [trackingTouches objectAtIndex:i];       CGPoint startPoint = [[startPoints objectAtIndex:i] CGPointValue];       CGPoint endPoint = [touch locationInView:touchedView];       CGRect rect = CGRectMake(startPoint.x, startPoint.y, endPoint.x - startPoint.x, endPoint.y - startPoint.y);       UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];       [delegate.strokeColor setStroke];       [path stroke];     }   } }  completedPath是一個UIBezierPath  的實例, 在touchEnded方法中 將最終矩形的路徑 設置到其中, 所以在手指抬起來以前  都只會進入到else分支, 根據 起點與當前手指觸摸的點 描出一個矩形來     當手指抬起來後  進入touchEnded方法,而主要的實現代碼就在這裡面 TextTool.m ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {   UIView *touchedView = [delegate viewForUseWithTool:self];   for (UITouch *touch in [event allTouches]) {     // make a rect from the start point to the current point     NSUInteger touchIndex = [trackingTouches indexOfObject:touch];     // only if we actually remember the start of this touch...     if (touchIndex != NSNotFound) {       CGPoint startPoint = [[startPoints objectAtIndex:touchIndex] CGPointValue];       CGPoint endPoint = [touch locationInView:touchedView];       [trackingTouches removeObjectAtIndex:touchIndex];       [startPoints removeObjectAtIndex:touchIndex];               // detect short taps that are too small to contain any text;       // these are probably accidents       if (distanceBetween(startPoint, endPoint) < 50.0) return;               CGRect rect = CGRectMake(startPoint.x, startPoint.y, endPoint.x - startPoint.x, endPoint.y - startPoint.y);       self.completedPath = [UIBezierPath bezierPathWithRect:rect];               // draw a shaded area over the entire view, so that the user can       // easily see where to focus their attention.       UIView *backgroundShade = [[[UIView alloc] initWithFrame:touchedView.bounds] autorelease];       backgroundShade.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];       backgroundShade.tag = SHADE_TAG;       backgroundShade.userInteractionEnabled = NO;       [touchedView addSubview:backgroundShade];               // now comes the fun part.  we make a temporary UITextView for the       // actual text input.       UITextView *textView = [[[UITextView alloc] initWithFrame:rect] autorelease];       textView.font = delegate.font;       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];               // in case the chosen view is going to be below the keyboard, we need to       // make an effort to determine how far the display area should slide when       // the keyboard is going to be shown.       //       // keyboard heights:       //       // 352 landscape       // 264 portrait       CGFloat keyboardHeight = 0;       UIInterfaceOrientation orientation = ((UIViewController*)delegate).interfaceOrientation;       if (UIInterfaceOrientationIsPortrait(orientation)) {         keyboardHeight = 264;       } else {         keyboardHeight = 352;       }       CGRect viewBounds = touchedView.bounds;       CGFloat rectMaxY = rect.origin.y + rect.size.height;       CGFloat availableHeight = viewBounds.size.height - keyboardHeight;       if (rectMaxY > availableHeight) {         // calculate a slide distance so that the dragged box is centered vertically         viewSlideDistance = rectMaxY - availableHeight;       } else {         viewSlideDistance = 0;       }               textView.delegate = self;       [touchedView addSubview:textView];       textView.editable = NO;       textView.editable = YES;       [textView becomeFirstResponder];     }   } }  首先 得到起點,終點,然後清空數組 if (distanceBetween(startPoint, endPoint) < 50.0) return;  進行了一個判斷,  防止用戶畫的矩形太小,影響輸入文字, 如果大小沒問題,接下來  便將最終的矩形路徑  賦值到 self.completedPath    在退出此方法後 進入drawTemporary後就會進入if分支 接著畫出 灰色的背景, 此處的設置透明度為0.5,  並且為背景view設置tag為SHADE_TAG  這個標記用來在以後 編輯完成的時候通過 viewWithTag方法 找到這個背景的實例  並且 移除它 接下來便開始創建textView   其frame就是 剛在最終得到的矩形路徑的位置信息 接著注冊了一些通知, 即在鍵盤彈出,或者落下的時候 調用的幾個方法 下面的一部分代碼實現的功能是   如果鍵盤彈出 可能會擋住 textView 判斷 是否擋住了 如果擋住了 需要向上移動多少距離,並且將這個距離 賦值給全局的 變量viewSlideDistance  如果沒有擋住 設置為0 最後將textView顯示出來,並且通過[textView becomeFirstResponder];  在其剛顯示的時候 馬上成為第一響應者,彈出鍵盤       下面兩個方法在鍵盤彈出之前以及落下之前,調用  移動視圖,防止textView 被擋 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 - (void)keyboardWillShow:(NSNotification *)aNotification {    UIInterfaceOrientation orientation = ((UIViewController*)delegate).interfaceOrientation;     [UIView beginAnimations:@"viewSlideUp" context:NULL];   UIView *view = [delegate viewForUseWithTool:self];   CGRect frame = [view frame];   switch (orientation) {     case UIInterfaceOrientationLandscapeLeft:       frame.origin.x -= viewSlideDistance;       break;     case UIInterfaceOrientationLandscapeRight:       frame.origin.x += viewSlideDistance;       break;     case UIInterfaceOrientationPortrait:       frame.origin.y -= viewSlideDistance;       break;     case UIInterfaceOrientationPortraitUpsideDown:       frame.origin.y += viewSlideDistance;       break;     default:       break;   }   [view setFrame:frame];     [UIView commitAnimations]; } - (void)keyboardWillHide:(NSNotification *)aNotification {   UIInterfaceOrientation orientation = ((UIViewController*)delegate).interfaceOrientation;     [UIView beginAnimations:@"viewSlideDown" context:NULL];   UIView *view = [delegate viewForUseWithTool:self];   CGRect frame = [view frame];   switch (orientation) {     case UIInterfaceOrientationLandscapeLeft:       frame.origin.x += viewSlideDistance;       break;     case UIInterfaceOrientationLandscapeRight:       frame.origin.x -= viewSlideDistance;       break;     case UIInterfaceOrientationPortrait:       frame.origin.y += viewSlideDistance;       break;     case UIInterfaceOrientationPortraitUpsideDown:       frame.origin.y -= viewSlideDistance;       break;     default:       break;   }   [view setFrame:frame];     [UIView commitAnimations]; }       當我們編輯完了內容後  我們可以點擊屏幕的其他地方(我們設置了[dudelView endEditing:YES])     或者點擊鍵盤上的落下鍵盤按鈕   這時 進入textView的  delegate     ? 1 2 3 4 5 6 7 8 9 10 11 - (void)textViewDidEndEditing:(UITextView *)textView {   //NSLog(@"textViewDidEndEditing");   TextDrawingInfo *info = [TextDrawingInfo textDrawingInfoWithPath:completedPath text:textView.text strokeColor:delegate.strokeColor font:delegate.font];   [delegate addDrawable:info];   self.completedPath = nil;   UIView *superView = [textView superview];   [[superView viewWithTag:SHADE_TAG] removeFromSuperview];   [textView resignFirstResponder];   [textView removeFromSuperview];   [[NSNotificationCenter defaultCenter] removeObserver:self]; }    這裡  用到了一個新類TextDrawingInfo  同上一章  的PathDrawingInfo  類似,都是 存放一個完整操作的  全部信息,由於上一章我們做的是繪圖操作,因此PathDrawingInfo 存放的是每次繪圖操作的信息,  而這次我們主要向利用coreText在屏幕上顯示文字  那麼之前繪制的矩形的信息 此時已經沒有用 我門要  取得  CoreText 需要的信息,即我們這次文字操作的信息  存到TextDrawingInfo 中去  並且添加到 dudelView  的 drawables中  最後  將沒用的東西全部從屏幕上移除       最後看以下  TextDrawingInfo  中的draw方法是怎麼把文字繪制上去的   ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 - (void)draw {   CGContextRef context = UIGraphicsGetCurrentContext();     NSMutableAttributedString *attrString = [[[NSMutableAttributedString alloc] initWithString:self.text] autorelease];   [attrString addAttribute:(NSString *)(kCTForegroundColorAttributeName) value:(id)self.strokeColor.CGColor range:NSMakeRange(0, [self.text length])];       CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);       CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attrString length]), self.path.CGPath, NULL);   CFRelease(framesetter);   //CFRelease(attrString);   if (frame) {     CGContextSaveGState(context);           // Core Text wants to draw our text upside-down!  This flips it the     // right way.     CGContextTranslateCTM(context, 0, path.bounds.origin.y);     CGContextScaleCTM(context, 1, -1);     CGContextTranslateCTM(context, 0, -(path.bounds.origin.y + path.bounds.size.height));       CTFrameDraw(frame, context);       CGContextRestoreGState(context);       CFRelease(frame);   } }  首先獲得當前的上下文  創建一個屬性自字符串NSMutableAttributedString  並設置他的顏色以及其他屬性 利用該屬性字符串 創建一個CTFramesetterRef 再創建一個CTFrameRef 釋放之前創建的CTFramesetterRef  對象framesetter 由於CoreText 是來自於Mac OS X的  它在繪圖的時候 認為坐標軸是倒置的,所以在沒ios中會產生倒置的效果,這裡要轉化以下才能正常顯示      
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved