Quartz2D 第二集

01-帶有邊框的圖片裁剪

帶有邊框的圖片裁剪jpg
封裝.jpg
具體實現思路:
1.假設邊框寬度為BorderW
2.開啟的圖片上下文的尺寸就應該是原始圖片的寬高分別加上兩倍的BorderW,這樣開啟的目的是為了不讓原始圖片變形.
3.在上下文上面添加一個圓形填充路徑.位置從0,0點開始,寬高和上下文尺寸一樣大.設置顏色為要設置的邊框顏色.
4.繼續在上下文上面添加一個圓形路徑,這個路徑為裁剪路徑.
  它的x,y分別從BorderW這個點開始.寬度和高度分別和原始圖片的寬高一樣大.
  將繪制的這個路徑設為裁剪區域.
5.把原始路徑繪制到上下文當中.繪制的位置和是裁剪區域的位置相同,x,y分別從border開始繪制.
6.從上下文狀態當中取出圖片.
7.關閉上下文狀態.

02-截屏

截屏.jpg
D3028CBC7C978008188B6493557E52CB.jpg
B5ED675CB272A76DC2B25B352086B7AF.jpg
圖片截屏.jpg
圖片截屏2.jpg
截屏效果實現具體思路為:把UIView的東西繪制圖片上下文當中,生成一張新的圖片.
注意:UIView上的東西是不能直接畫到上下文當中的.
    UIView之所以能夠顯示是因為內部的一個層(layer),所以我要把層上的東西渲染到UIView上面的.
    怎樣把圖層當中的內容渲染到上下文當中?
    
    直接調用layer的renderInContext:方法
    renderInContext:帶有一個參數, 就是要把圖層上的內容渲染到哪個上下文.
    
    截屏具體實現代碼為:
        1.開啟一個圖片上下文
        UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
        獲取當前的上下文.
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        2.把控制器View的內容繪制上下文當中.
        [self.view.layer renderInContext:ctx];
        3.從上下文當中取出圖片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        4.關閉上下文.
        UIGraphicsEndImageContext();

03-圖片擦除

圖片擦除思路.
弄兩個不同的圖片.上面一張, 下面一張.
添加手勢,手指在上面移動,擦除圖片.
擦除前要先確定好擦除區域.
假設擦除區域的寬高分別為30.
那點當前的擦除范圍應該是通過當前的手指所在的點來確定擦除的范圍,位置.
那么當前擦除區域的x應該是等于當前手指的x減去擦除范圍的一半,同樣,y也是當前手指的y減去高度的一半.

有了擦除區域,要讓圖片辦到擦除的效果,首先要把圖片繪制到圖片上下文當中, 在圖片上下文當中進行擦除.
之后再生成一張新的圖片,把新生成的這一張圖片設置為上部的圖片.那么就可以通過透明的效果,看到下部的圖片了.

第一個參數, 要擦除哪一個上下文
第二人參數,要擦除的區域.
CGContextClearRect(ctx, rect);

具體實現代碼為:

確定擦除的范圍
CGFloat rectWH = 30;
獲取手指的當前點.curP
CGPoint curP = [pan locationInView:pan.view];
CGFloat x = curP.x - rectWH * 0.5;
CGFloat y = curP.y - rectWH * 0.5;
CGRect rect = CGRectMake(x, y,rectWH, rectWH);

先把圖片繪制到上下文.
UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0);
獲取當前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
把上面一張圖片繪制到上下文.
[self.imageView.layer renderInContext:ctx];
再繪上下文當中圖片進行擦除.
CGContextClearRect(ctx, rect);
生成一張新圖片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
再把新的圖片給重新負值
self.imageView.image = newImage;
關閉上下文.
UIGraphicsEndImageContext();

04-圖片截屏

圖片截屏實現思路.
手指在屏幕上移動的時
添加一個半透明的UIView,
然后開啟一個上下文把UIView的frame設置成裁剪區域.把圖片顯示的圖片繪制到上下文當中,生成一張新的圖片
再把生成的圖片再賦值給原來的UImageView.

具體實現步驟:
1.給圖片添加一個手勢,監聽手指在圖片上的拖動,添加手勢時要注意,UIImageView默認是不接事件的.
  要把它設置成能夠接收事件
2.監聽手指的移動.手指移動的時候添加一個UIView,
  x,y就是起始點,也就是當前手指開始的點.
  width即是x軸的偏移量,
  高度即是Y軸的偏移量.
  UIView的尺寸位置為CGrect(x,y,witdth,height);
  
  計算代碼為:
  CGFloat offSetX = curP.x - self.beginP.x;
  CGFloat offsetY = curP.y - self.beginP.y;
  CGRect rect = CGRectMake(self.beginP.x, self.beginP.y, offSetX, offsetY);
  
  UIView之需要添加一次,所以給UIView設置成懶加載的形式,
  保證之有一個.每次移動的時候,只是修改UIView的frame.
  
3.開啟一個圖片上下文,圖片上下文的大小為原始圖片的尺寸大小.使得整個屏幕都能夠截屏.
  利用UIBezierPath設置一個矩形的裁剪區域.
  然后把這個路徑設置為裁剪區域.
  把路徑設為裁剪區域的方法為:
  [path addClip];
  
4.把圖片繪制到圖片上下文當中
  由于是一個UIImageView上面的圖片,所以也得需要渲染到上下文當中.
  要先獲取當前的上下文,
  把UIImageView的layer渲染到當前的上下文當中.
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  [self.imageV.layer renderInContext:ctx];
  
5.取出新的圖片,重新賦值圖片.
  UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  self.imageV.image = newImage;
  
6.關閉上下文,移除上面半透明的UIView
  UIGraphicsEndImageContext();
  [self.coverView removeFromSuperview];

05-手勢解鎖

分析界面,當手指在上面移動時,當移動到一個按鈕范圍內當中, 它會把按鈕給成為選中的狀態.
并且把第一個選中的按鈕當做一個線的起點,當手指移動到某個按鈕上時,就會添加一根線到選中的那妞上.
當手指松開時,所有按鈕取消選中.所有的線都清空.

實現思路:
    先判斷點前手指在不在當前的按鈕上.如果在按鈕上,就把當前按鈕成為選中狀態.
    并且把當前選中的按鈕添加到一個數組當中.如果當前按鈕已經是選中狀態,就不需要再添加到數組中了.
    每次移動時,都讓它進行重繪.
    在繪圖當中,遍歷出所有的選中的按鈕,
    判斷數組當中的第一個無素,如果是第一個,那么就把它設為路徑的起點.其它都在添加一根線到按鈕的圓心.
    如果當前點不在按鈕上.那么就記錄住當前手指所在的點.直接從起點添加一根線到當前手指所在的點.
    

實現步驟:
1.搭建界面
    界面是一個九宮格的布局.九宮格實現思路.
    先確定有多少列  cloum = 3;
    計算出每列之間的距離
    計算為: CGFloat margin = (當前View的寬度 - 列數 * 按鈕的寬度) / 總列數 + 1
    每一列的X的值與它當前所在的行有關
    當前所在的列為:curColum = i % cloum
    每一行的Y的值與它當前所在的行有關.
    當前所在的行為:curRow = i / cloum
    
    每一個按鈕的X值為, margin + 當前所在的列 * (按鈕的寬度+ 每個按鈕之間的間距)
    每一個按鈕的Y值為 當前所在的行 * (按鈕的寬度 + 每個按鈕之間的距離)
    
    具體代碼為:
    總列婁
    int colum = 3;
    每個按鈕的寬高
    CGFloat btnWH = 74;
    每個按鈕之間的距離
    CGFloat margin = (self.bounds.size.width - colum * btnWH) / (colum + 1);
    for(int i = 0; i < self.subviews.count; i++ ){
        當前所在的列
        int curColum = i % colum;
        當前所在的行
        int curRow = i / colum;
        CGFloat x = margin + (btnWH + margin) * curColum;
        CGFloat y = (btnWH + margin) * curRow;
        取出所有的子控件
        UIButton *btn = self.subviews[i];
        btn.frame = CGRectMake(x, y, btnWH, btnWH);
    }
    
 2.監聽手指在上面的點擊,移動,松開都需要做操作.
    
    2.1在手指開始點擊屏幕時,如果當前手指所在的點在按鈕上, 那就讓按鈕成為選中狀態.
        所以要遍歷出所有的按鈕,判斷當前手指所在的點在不在按鈕上,
        如何判斷當前點在不在按鈕上?
        當前方法就是判斷一個點在不在某一個區域,如果在的話會返回Yes,不在的話,返回NO.
        CGRectContainsPoint(btn.frame, point)
    
        在手指點擊屏幕的時候,要做的事分別有
        1.獲取當前手指所在的點.
            UITouch *touch = [touches anyObject];
            CGPoint curP =  [touch locationInView:self];
        2.判斷當前點在不在按鈕上.
             for (UIButton *btn in self.subviews) {
                if (CGRectContainsPoint(btn.frame, point)) {
                      return btn;
                }
             }
        3.如果當前點在按鈕上,并且當前按鈕不是選中的狀態.
          那么把當前的按鈕成為選中狀態.
          并且把當前的按鈕添加到數組當中.

    
    2.2 當手指在移動的時也需要判斷.
          判斷當前點在按鈕上,并且當前按鈕不是選中的狀態.
          那么把當前的按鈕成為選中狀態.
          并且把當前的按鈕添加到數組當中.
         在移動的時候做重繪的工作.
         
    2.3 當手指離開屏幕時.
        取出所有的選中按鈕,把所有選中按鈕取消選中狀態.
        清空選中按鈕的數組.
        繪重繪的工作.
        
        
 3. 在繪圖方法當中.
    創建路徑 
    遍歷出有的選中按鈕.如果是第一個按鈕,把第一個按鈕的中心點當做是路徑的起點.
    其它按鈕都直接添加一條線,到該按鈕的中心.
    
    遍歷完所有的選中按鈕后.
    最后添加一條線到當前手指所在的點.

06-畫板


相冊來源選擇.png
保存到系統相冊.png
畫板界面分析.
頂部是一個工具欄.有清屏,撤銷,橡皮擦,照片功能.最右部是一個保存按鈕
中間部分為畫板區域
最下部拖動滑竿能夠改變畫筆的粗線.可以選顏色.

1.界面搭建
    最上部為一個ToolBar,往ToolBar拖些item,使用ToolBar的好處.里面按鈕的位置不需要我們再去管理.
    給最上部的工具欄做自動布局.離父控件左,上,右都為0,保存工具條的高度不度
    
    拖一個UIView當前下部的View.在下部的View當中拖累三個按鈕,設置每一個按鈕的背景顏色.
    點擊每一按鈕時辦到設置畫筆的顏色.
    其中三個按鈕只間的間距始終保存等,每一個按鈕的寬度和高度都相等.通過自動布局的方式辦到.
    
    先把這個UIView的自動布局設好, 讓其左,右,下都是0,高度固定.
    
    自動布局設置為:第一個按鈕高度固定,與左,右,下都保存20個間距.
    第二個按鈕與第一個按鈕,高度,寬度,centerY都相等.與右邊有20個間距.
    第三個按鈕也是第一個按鈕的高度,寬度,centerY都相等.與右邊有20個間距,最右邊也保存20個間距.
    
    最后是中間的畫板區域,畫板區域只需要上距離上下左右都為0即可.
    
2.實現畫板功能.
  
  當手指移動的時候,在中間的畫板區域當中進行繪制.由于每一個路徑都有不同的狀態.所以我們就不能用一條路徑來做.
  所以要弄一個數組記錄住每一條路徑.
  實現畫板功能.
  1.監聽手指在屏幕上的狀態.在開始點擊屏幕的時候,創建一個路徑.并把手指當前的點設為路徑的起點.
    
    弄一個成員屬性記錄當前繪制的路徑.并把當前的路徑添加到路徑數組當中.
    
  2.當手指在移動的時候,用當前的路徑添加一根線到當前手指所在的點.然后進行重繪.
  3.在繪圖方法當中.取出所有的路徑.把所有的路徑給繪制出來.
  
3.設置路徑屬性.
    提供屬性方法.
    
    清屏功能:刪除所有路徑進行重繪
    
    撤銷功能:刪除最后一條路徑,進行重繪
    
    設置線寬:
            由于每一條線寬度都不樣.所以要在開始創建路徑的時,就要添加一個成員屬性,設置一個默認值.
            在把當前路徑添加到路徑數組之前,設置好線的寬度.然后重寫線寬屬性方法.
            下一次再創建路徑時,線的寬度就是當前設置的寬度.
    設置線的顏色:
            同樣,由于每一條線的顏色也不一樣.也需要記錄住每一條路徑的顏色.
            由于UIBezierPath沒有給我們直接提供設置顏色的屬性.我們可以自定義一個UIBezierPath.
            創建一個MyBezierPath類,繼承UIBezierPath,在該類中添加一個顏色的屬性.
            在創建路徑的時候,直接使用自己定義的路徑.設置路徑默認的一個顏色.方法給設置線寬一樣.
            在繪圖過程中, 取出來的都是MyBezierPath,把MyBezierPath的顏色設置路徑的顏色.
            
    橡皮擦功能:橡皮擦功能其實就是把路徑的顏色設為白色.
    
    
4.保存繪制的圖片到相冊.
    保存相冊的思路:就是把繪制的在View上的內容生成一張圖片,保存到系統相冊當中.
    具體步驟:
    開啟一個跟View相同大小的圖片上下文.
    把View的layer上面內容渲染到上下文當中.
    生成一張圖片,把圖片保存到上下文.
    關閉上下文.
    如何把一張圖片保存到上下文?
    調用方法:
    參數說明:
    第一個參數:要寫入到相冊的圖片.
    第二個參數:哪個對象堅聽寫入完成時的狀態.
    第三個參數:圖片保存完成時調用的方法
    UIImageWriteToSavedPhotosAlbum(newImage,
                                         self,
     @selector(image:didFinishSavingWithError: contextInfo:),nil);
    注意:圖片保存完成時調用的方法必須得是image:didFinishSavingWithError: contextInfo:
            
    
 5.選擇圖片.
    點擊圖片時彈出系統的相冊.
    如果彈出系統的相冊?
    使用UIImagePickerController控件器Modal出它來.
    UIImagePickerController *pick = [[UIImagePickerController alloc] init];
    
    設置照片的來源
    pick.sourceType =  UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    
    設置代碼,監聽選擇圖片,UIImagePickerController比較特殊,它需要遵守兩個協議
    <UINavigationControllerDelegate,UIImagePickerControllerDelegate>
    pick.delegate = self;
    
    modal出控件器
    [self presentViewController:pick animated:YES completion:nil];
    
    注意沒有實現代碼方法時,選擇一張照片會自動的dismiss掉相冊控制器.但是設置代碼后,就得要自己去dismiss了
    
    
    實現代理方法.
    選擇的照片就在這個方法第二個參數當中, 它是一個字典
    -(void)imagePickerController:(nonnull UIImagePickerController *)picker
     didFinishPickingMediaWithInfo:(nonnull NSDictionary<NSString *,id> *)info{
        
        獲取當前選中的圖片.通過UIImagePickerControllerOriginalImage就能獲取.
        UIImage *image = info[UIImagePickerControllerOriginalImage];
    
    }
    
    獲取完圖片后.圖片是能夠縮放,平移的,因此獲取完圖片后,是在畫板板View上面添加了一個UIView.
    只有UIView才能做平移,縮放,旋轉等操作.
    因此做法為.在圖片選擇完畢后,添加一個和畫板View相同大小的UIView,這個UIView內部有一個UIImageView.
    對這個UIImageView進行一些手勢操作.操作完成時.長按圖片,把View的內容截屏,生成一張圖片.
    把新生成的圖片繪制到畫板上面.
    
6.繪制圖片.
    在畫板View當中提供一個UImage屬性,供外界傳遞.重寫屬性的set方法,每次傳遞圖片時進行重繪
    畫圖片也有有序的,所以要把圖片也添加到路徑數組當中.
    在繪圖片過過程當中,如果發現取出來的是一個圖片類型.那就直接圖片繪制到上下文當中.
    
    具體實現代碼為:
    -(void)drawRect:(CGRect)rect{

        for (DrawPath *path in self.pathArray) {
    
            if ([path isKindOfClass:[UIImage class]]) {
        
                    UIImage *image = (UIImage *)path;
                    [image drawInRect:rect];

                }else{
                    [path.lineColor set];
                    [path stroke];
                }
    
            }
        }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,229評論 4 61
  • 1.矩陣操作 1.1.平移 1.2.旋轉 1.3.縮放 1.4.注意 2.圖形上下文棧 2.1.通過繪圖原理來理解...
    帥哥_刷哥閱讀 427評論 0 1
  • 轉載自:https://github.com/Tim9Liu9/TimLiu-iOS 目錄 UI下拉刷新模糊效果A...
    袁俊亮技術博客閱讀 11,961評論 9 105
  • 生命中我們要相遇很多人,有的能在我們的生命中留下印記,我們稱之為有緣。但那些只是點綴了一下我們的生活匆匆劃過并很快...
    恒思閱讀 418評論 0 0
  • 《海底總動員》 Background 背景知識 Finding Nemo is a 2003 American c...
    Mona老師閱讀 682評論 0 1