您好,登錄后才能下訂單哦!
iOS中如何在內存中繪圖,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
前面介紹的都是通過擴展UIView、重寫drawRect:方法進行繪圖,這種繪圖方式是直接在UIView控件上繪制所有的圖形——由于每次該控件顯示出來時,drawRect:方法都會被調用,這意味著每次該控件顯示出來時,程序都需要重繪所有的圖形,很明顯,這種方式的性能并不好。除此之外,總有些時候需要在內存中繪制圖片,這樣既可導出到手機本地,也可上傳到網絡上。
與直接在UIView控件上繪圖不同,在內存中繪圖時,需要開發者自己準備繪圖環境,Quartz 2D提供了一個非常便捷的函數:UIGraphicsBeginImageContext(CGSize size),該函數用于準備繪圖環境。當圖形繪制完成后,可調用UIGraphicsEndImageContext()函數結束繪圖和關閉繪圖環境。
總結來說,在內存中繪圖的步驟如下。
調用UIGraphicsBeginImageContext(CGSize size)函數準備繪圖環境。
調用UIGraphicsGetCurrentContext()函數獲取繪圖CGContextRef。
用前面介紹的繪制集合圖形、使用路徑等方式進行繪圖。
調用UIGraphicsGetImageFromCurrentImageContext()函數獲取當前繪制的圖形,該方法返回一個UIImage對象。
調用UIGraphicsEndImageContext()函數結束繪圖,并關閉繪圖環境。
除了使用前面介紹需要CGContextRef參數的方法繪圖之外,還可調用如下函數進行繪圖。
UIRectFill(CGRect rect):向當前繪圖環境所創建的內存中的圖片上填充一個矩形。
UIRectFillUsingBlendMode(CGRect rect , CGBlendMode blendMode):向當前繪圖環境所創建的內存中的圖片上填充一個矩形,繪制使用指定的混合模式。
UIRectFrame(CGRect rect):向當前繪圖環境所創建的內存中的圖片上繪制一個矩形邊框。
UIRectFrameUsingBlendMode(CGRect rect , CGBlendMode blendMode):向當前繪圖環境所創建的內存中的圖片上繪制一個矩形邊框,繪制使用指定的混合模式。
上面4個方法都是直接繪制在當前繪圖環境所創建的內存中的圖片上,因此,這些方法都不需要傳入CGContextRef作為參數。
下面的程序示范了在內存中繪圖,并將圖片輸出到手機本地。首先創建一個Single View Application,該Application包含一個應用程序委托代理類、一個視圖控制
器和配套的Storyboard界面設計文件。本程序無須修改界面設計文件,也無須自定義UIView控件,該程序只是向該UIView上添加一個UIImageView,并控制該UIImageView顯示內存中繪制的圖片即可。因此,該程序只要修改視圖控制器類,該視圖控制器類的實現代碼如下。
程序清單:codes/12/12.2/DrawImage/DrawImage/FKViewController.m
程序中的第一行粗體字代碼用于創建內存中圖片的繪制環境,接著調用UIGraphics- GetCurrentContext()方法獲取繪圖的CGContextRef,剩下的繪圖操作與前面介紹的各種繪圖代碼完全相同。
圖形繪制完成后,第二行粗體字代碼調用UIGraphicsEndImageContext()方法結束繪圖,繪圖結束后,即可調用UIGraphicsGetImageFromCurrentImageContext()函數獲取當前繪制的圖片,程序既可使用UIImageView顯示該圖片(如程序的viewDidLoad方法所示),也可將圖片輸出到手機本地。
最后一行粗體字代碼調用了UIImagePNGRepresentation()函數獲取UIImage圖像的數據。該方法返回NSData對象,接下來就可利用NSData的方法執行輸出了。
提示:
UIImagePNGRepresentation()函數的作用是獲取UIImage圖片轉換為PNG格式的圖片數據,還有一個與之類似的UIImageJPEGRepresentation()函數,其作用是獲取UIImage圖片轉換為JPEG格式的圖片數據,UIImageJPEGRepresentation()函數多一個參數,用于指定圖片的壓縮質量。
編譯、運行該程序,即可看到如圖12.13所示的效果。
該程序還將繪制的圖片輸出到該應用程序沙盒的Documents文件夾下。對模擬器而言,該Documents文件夾位于OS X系統的一個隱藏文件夾下。為了查看iOS應用程序沙盒的文件夾,請按如下步驟進行。
提示:
為了保證系統安全,iOS應用程序只能在系統為該應用所分配的文件區域下讀、寫文件,該文件區域被稱為該應用程序的沙盒。iOS應用的所有非代碼文件都要保存在此,例如,圖像、圖標、聲音、映像、屬性列表、文本文件等。iOS的每個應用程序都有自己獨立的沙盒,該應用程序不能訪問其他應用的沙盒。
(1)打開Mac OS X系統的Finder。
(2)單擊Finder應用中主菜單的“前往”→“前往文件夾”菜單項,或單擊command+Shift+G快捷鍵,系統彈出如圖12.14所示的對話框。
(3)在圖12.14所示的對話框中輸入/users/登錄用戶名/library/application suport/iPhone Simulator,然后單擊“前往”按鈕進入該文件夾,即可看到5.0、5.1、6.0、6.1、7.0等文件夾,這就是該電腦上已經安裝過的iOS模擬器文件夾——不同的文件夾對應不同版本的iOS模擬器。
(4)進入當前iOS模擬器版本對應的文件夾,比如當前使用iOS 7.0模擬器,則經過7.0文件夾進入該模擬器,接下來即可看到該模擬器目錄下包括Applications、Media、Root、tmp、資源庫等文件夾,其中,Applications文件夾下保存了該模擬器上安裝的所有iOS應用。
(5)進入Applications文件夾,即可在該文件夾下看到大量的子文件夾,每個子文件夾對應一個應用程序,找到本應用對應的子文件夾,并進入該子文件夾,即可看到包含Documents、DrawImage.app、Library、tmp內容,在Documents文件夾下即可看到剛剛創建的newPng.png圖片,如圖12.15所示。
圖12.15 查看模擬器沙盒下的文件
提示:
讀者可能會想,如果可以直接查看OS X系統的隱藏文件,是不是就可以直接通過Finder進入該模擬器沙盒目錄?實際上,OS X并沒有提供圖形化界面來設置顯示隱藏文件,不過可以通過命令行進行修改,在OS X系統命令行窗口輸入defaults write com.apple.finder AppleShowAllFiles -bool true,然后退出所有的Finder,重啟Finder程序,即可看到隱藏文件;如果希望恢復隱藏,在命令行窗口輸入defaults write com.apple.finder AppleShowAllFiles -bool false,然后退出所有的Finder,并重啟Finder程序即可
實例:繪圖板
該實例將會實現一個繪圖板,用戶可以根據喜好隨心所欲地在手機上“涂鴉”,涂鴉完成后,即可得到自己想要的圖片——這張圖片既可保存到手機本地,也可通過網絡分享。
為了實現這個應用,僅僅通過重寫UIView的drawRect:方法并不適合——如果僅通過重寫UIView的drawRect:方法來實現繪圖,用戶每次繪圖的時候就會丟失上一次繪圖的內容。這顯然不是本實例要實現的效果。
為了保證用戶每次繪圖的內容不會丟失,將會在內存中創建一張圖片,當用戶開始繪圖時,程序會通過重寫drawRect:方法進行實時繪制,當用戶想要繪制的圖形確定下來后,將該圖形繪制到內存中的圖片上。
舉例來說,當用戶想要在屏幕上繪制直線時,程序會把用戶開始觸碰屏幕的第一個點作為繪圖的起始點,當用戶手指不離開屏幕而是在屏幕上拖動時,程序會不斷地獲取拖動點的坐標,并調用該UIView的drawRect:方法,該方法會從起始點繪制到當前拖動點——由于drawRect:每次重繪都只繪制起始點到當前拖動點的直線,因此,用戶可以實時看到拖動繪制的直線。當用戶松開手指時(表明用戶確定了最終繪制點),在內存中的圖片上繪制從起始點到手指松開點的直線即可。
需要指出的是,為了保證用戶能看到之前繪制的圖形,重寫UIView的drawRect:方法時一定要先把內存中的圖片繪制到UIView上。
首先創建一個Single View Application,該Application包含一個應用程序委托代理類、一個視圖控制器和配套的Storyboard界面設計文件。在Interface Builder中打開界面設計文件,將該界面設計文件中最大的UIView改為使用自定義的FKDrawView類。在界面上方放置一個UISegmentedControl控件,該控件用于控制繪圖顏色;在界面下方放置一個工具條,并向工具條中添加一個UISegmentedControl控件,該控件用于控制繪圖形狀。本應用的界面設計如圖12.16所示。
為了讓界面上的兩個UISegmentedControl控件能控制用戶繪制的顏色和形狀,需要在Interface Builder中為這兩個UISegmentedControl控件分別綁定changeColor:和changeShape:兩個IBAction方法。
為了能記錄該應用當前需要繪制的圖形,本程序先創建一個頭文件,該文件中僅定義一個枚舉類型,代碼如下。
程序清單:codes/12/12.2/HandDraw/HandDraw/Constant.h
本應用的視圖控制器類比較簡單,主要就是實現changeColor:和changeShape:兩個IBAction方法。下面是該視圖控制器類的實現代碼。
程序清單:codes/12/12.2/HandDraw/HandDraw/FKViewController.m
從上面程序中的兩行粗體字代碼可以看出,該視圖控制器類的view并不是UIView,而是自定義的FKDrawView,這個FKDrawView就是實現本應用的關鍵,FKDrawView不僅要重寫drawRect:方法,該方法還完成兩件事情:將內存中的圖片繪制出來;用戶手指拖動進行“實時”繪制。
FKDrawView類的接口代碼比較簡單,只是定義currentColor、shape兩個屬性即可,這兩個屬性用于接收控制器傳入的繪制顏色和繪制形狀。FKDrawView類的實現代碼如下。
程序清單:codes/12/12.2/HandDraw/HandDraw/FKDrawView.
該程序的關鍵是上面的粗體字draw:方法,該方法會根據想要繪制的圖形類型,繪制不同的形狀。需要讀者留意的是,該方法在兩個地方被調用過——當用戶拖動手指時,激發touchesMoved: withEvent:方法,該方法中會通知該控件重繪自己,該控件會調用drawRect:方法進行重繪,drawRect:方法中調用了這個粗體字draw:方法執行實時繪制。除此之外,當用戶手指結束觸碰時,激發touchesEnded: withEvent:方法,該方法中調用了[self draw:buffCtx];代碼,這行代碼將會把起始點到結束觸碰點的形狀繪制在內存中的圖片上。
程序中還有一個稍微有點復雜的地方,就是所謂的“自由繪制”。即當用戶手指在屏幕上拖動時,程序需要繪制手指拖動的軌跡,這條軌跡表面上看是一條不規則的曲線,但實際上它由很多很短的線段組成——當用戶手指在屏幕上拖動時,程序會不斷地從上一個觸碰點繪制到當前觸碰點,由于這些線段都非常短,因此,用戶會以為我們繪制了一條光滑的曲線。程序為了完成這個繪制過程,使用prevPoint保存上一個觸碰點的坐標,并不斷地繪制從prevPoint到lastPoint的線段,每次繪制完成后,使用prevPoint保存當前觸碰點的坐標,這對下一次繪制而言,當前觸碰點就變成了上一個觸碰點。
看完上述內容,你們掌握iOS中如何在內存中繪圖的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。