欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何實(shí)現(xiàn)一個(gè)手帳APP開(kāi)發(fā)

前段時(shí)間對(duì)手帳類 app 的實(shí)現(xiàn)細(xì)節(jié)非常感興趣,遂萌生了想自己實(shí)現(xiàn)一個(gè)最小化的可行性產(chǎn)品。當(dāng)然啦~既然是 MVP 模式下的產(chǎn)品,所以只實(shí)現(xiàn)了「功能」,但是在一些自己特別想要去「抄襲」的地方也下了一點(diǎn)功夫去追求 UI 的表現(xiàn)。

創(chuàng)新互聯(lián)專注于木壘哈薩克網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供木壘哈薩克營(yíng)銷型網(wǎng)站建設(shè),木壘哈薩克網(wǎng)站制作、木壘哈薩克網(wǎng)頁(yè)設(shè)計(jì)、木壘哈薩克網(wǎng)站官網(wǎng)定制、成都小程序開(kāi)發(fā)服務(wù),打造木壘哈薩克網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供木壘哈薩克網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。

前言

小時(shí)候,我是一個(gè)手抄報(bào)愛(ài)好者,四年級(jí)的時(shí)候班里組織了一個(gè)手抄報(bào)比賽,老師要求每位同學(xué)利用周末的時(shí)間做一份手抄報(bào)進(jìn)行評(píng)比,主題自選。到現(xiàn)在我印象還非常深刻的是,我想了一個(gè)中午都不知道要選什么主題,在白紙上畫(huà)了一些東西后又全都擦掉了,弄臟了好幾張紙,最后畫(huà)出了一個(gè)地球,思路就慢慢打開(kāi)了。

到了周一交給老師的時(shí)候,我不敢第一個(gè)交,我排在了隊(duì)伍的最后。老師接到我的手抄報(bào)后,居然說(shuō):“來(lái)來(lái)來(lái),你們來(lái)看看什么叫手抄報(bào)”,我當(dāng)時(shí)的心率達(dá)到了極高點(diǎn),臉又紅又燙,站在老師身邊站也不是走也不是,尷尬的笑著,但內(nèi)心卻極度自豪。

到了初中,班主任也讓大家利用周末的時(shí)間去做了一個(gè)手抄報(bào),因?yàn)樵谛W(xué)的時(shí)候有了一點(diǎn)經(jīng)驗(yàn),再加上到了初中那會(huì)兒基本上使用計(jì)算機(jī)來(lái)輔助完成各種任務(wù)也都鋪開(kāi)了,我就尋思著能不能再做些創(chuàng)新。當(dāng)時(shí)柯達(dá)傳出了倒閉的消息,這相當(dāng)于是一代人的記憶吧~有時(shí)候我會(huì)跑到老房子里翻到各種膠卷,在陽(yáng)光的照射下看著映射出的反射圖像。

結(jié)合這個(gè)事件,我就想到了利用「膠卷」風(fēng)格的來(lái)闡述對(duì)保護(hù)鳥(niǎo)類的主題,從網(wǎng)上下載了一些各種鳥(niǎo)類的圖片,自己加工一下,終于把手抄報(bào)做好了交給老師。當(dāng)交給老師的那一刻,老師愉悅的笑了,并拿著我的手抄報(bào)在講臺(tái)上給同學(xué)們展示,“大家看下,做的還不錯(cuò)吧~嗯,挺好看!”。

高考完的那個(gè)暑假,《南國(guó)都市報(bào)》組織了一次中小學(xué)生手抄報(bào)大賽,當(dāng)時(shí)我用堂弟的身份參加這個(gè)大賽,拿了三等獎(jiǎng),獎(jiǎng)品是一張創(chuàng)新書(shū)店 500 元的購(gòu)書(shū)卡。

以上就是我對(duì)手抄報(bào)或者說(shuō)類似于手帳的這種手工畫(huà)的經(jīng)歷了,我特別喜歡這種講述一個(gè)故事的方式,可以很好的把我想要表達(dá)的東西通過(guò)一些文字、圖片和畫(huà)的方式展現(xiàn)出來(lái)。

所以,當(dāng)出現(xiàn)了手帳類 app 時(shí),我迅速的下載進(jìn)行使用,使用過(guò)程中確實(shí)達(dá)到了自己當(dāng)初通過(guò)組織一些元素和文字來(lái)講述一件事的初衷。前段時(shí)間突發(fā)奇想,如果我能自己做一個(gè)手帳,順便去探究實(shí)現(xiàn)一個(gè)手帳 app 中需要注意的問(wèn)題,那該多好??!

設(shè)計(jì)

首先,我把 App Store 中「手帳」關(guān)鍵詞下的搜索排名前 10 的 app 都進(jìn)行了一番使用,總結(jié)出了一些手帳 app 通用點(diǎn):

  • 添加文字。可旋轉(zhuǎn)、放大縮小、旋轉(zhuǎn)字體;

  • 添加照片??尚D(zhuǎn)翻轉(zhuǎn)、放大縮小、并具備簡(jiǎn)單或者輔助的圖像修飾工具;

  • 添加貼紙。使用一些繪制好的貼紙,操作與「添加照片」差不多;

  • 模版。提供一套模版,用戶可以在這個(gè)模版規(guī)定好的區(qū)域進(jìn)行內(nèi)容添加;

  • 提供無(wú)限長(zhǎng)或?qū)挼漠?huà)布。

基本上這些手帳 app 的功能就是這么多了,因?yàn)楸局?MVP 的思路去做這個(gè)項(xiàng)目,所以也就沒(méi)有做到高保真的設(shè)計(jì),直接抄了一個(gè)比較簡(jiǎn)潔的手帳 app 設(shè)計(jì)。

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

技術(shù)棧

確定好了自己要實(shí)現(xiàn)的大概需要做的功能點(diǎn)后,就需要開(kāi)始去選擇技術(shù)棧,因?yàn)橐龅漠吘故?MVP 產(chǎn)品而不是 demo,我對(duì) demo 的理解是「實(shí)現(xiàn)某個(gè)功能點(diǎn)」,對(duì) MVP 產(chǎn)品的理解是「某個(gè)階段下的完整可用的產(chǎn)品」,MVP 模式下出來(lái)的東西細(xì)節(jié)出現(xiàn)一些問(wèn)題不用太過(guò)于苛責(zé),但整體的邏輯上一定是要完整的,不完整的邏輯可以沒(méi)有,但是一旦有了就要是完整的,覆蓋的邏輯路徑也可以不是 100%,但主邏輯一定要全覆蓋。

客戶端

iOS APP開(kāi)發(fā)技術(shù)點(diǎn)如下:

  • 純?cè)?Swift 開(kāi)發(fā);

  • 網(wǎng)絡(luò)請(qǐng)求 =>?Alamofire,一些簡(jiǎn)單的數(shù)據(jù)直接走?NSFileManager?進(jìn)行文件持久化管理;

  • UI 組件全都基于?UIKit?去做;社會(huì)化分享走系統(tǒng)分享,不集成其它 SDK;

  • 模塊上提供「貼紙」、「畫(huà)筆」、「照片」和「文字」。做的過(guò)程中發(fā)現(xiàn)其實(shí)「照片」和「文字」本質(zhì)上來(lái)說(shuō)也是貼紙,省了不少事。

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

服務(wù)端

其實(shí)我對(duì)自己每新開(kāi)一個(gè) side project 都有一個(gè)硬性要求,做完后要對(duì)自己的技術(shù)水平有增長(zhǎng),其實(shí)「增長(zhǎng)」這個(gè)東西很玄學(xué),怎么定義「增長(zhǎng)」對(duì)吧?我給自己找到了一個(gè)最簡(jiǎn)單的思路:用新的東西去完成它!

因此在服務(wù)端上我就直接無(wú)腦的選擇了?Vapor?進(jìn)行,通過(guò) Swift 去寫(xiě)服務(wù)端這是我之前一直想做但找不到時(shí)機(jī)去做的事情,借此機(jī)會(huì)就上車了。至于為什么不是選?Perfect,其實(shí)我個(gè)人沒(méi)有去動(dòng)手實(shí)踐過(guò),只是聽(tīng)大佬們說(shuō)?Vapor?的 API 風(fēng)格比較?Swifty?一些。

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

在第一期的 MVP 中對(duì)服務(wù)端的依賴不大,所以目前的架構(gòu)比較簡(jiǎn)單,達(dá)到能用即可就完事了~關(guān)于?Vapor?的一些使用細(xì)節(jié),可以在我的這篇文章中進(jìn)行查看,本文將不再細(xì)述?Vapor?使用細(xì)節(jié)。

實(shí)現(xiàn)

手勢(shì)

對(duì)于手帳來(lái)說(shuō),最核心的一個(gè)就是「貼紙」。如何把貼紙從存儲(chǔ)中拉出來(lái)放到畫(huà)布上,這一步解決了,后續(xù)大部分內(nèi)容也都解決了。

首先,我們需要明確一點(diǎn),在這個(gè)項(xiàng)目中,「畫(huà)布」本身也是個(gè)?UIView,把「貼紙」添加到畫(huà)布上,實(shí)質(zhì)上就是把?UIImageView?給?addSubview?到?UIView?上。其次,手帳中追求的是對(duì)素材的控制,可旋轉(zhuǎn)放大是基本操作,而且前文也說(shuō)過(guò)了,我們幾乎可以把「照片」和「文字」都認(rèn)為是對(duì)「貼紙」的繼承,所以這就抽離出了「貼紙」本身是所以可提供交互組件的基類。

手帳類 app 對(duì)貼紙進(jìn)行多手勢(shì)操作的流暢性是決定用戶留存率很大的一個(gè)因素。因此,我們?cè)俪殡x一下手帳「貼紙」,把基礎(chǔ)手勢(shì)操作都移到更高一層的父類中去,貼紙中留下業(yè)務(wù)邏輯。手勢(shì)操作核心代碼邏輯如下:

//?pinchGesture?縮放手勢(shì)//?縮放的方法(文件私有)。??gesture手勢(shì)?:UI縮放手勢(shì)識(shí)別器@objcfileprivate?func?pinchImage(gesture:?UIPinchGestureRecognizer)?{
????//??當(dāng)前手勢(shì)?狀態(tài)???改變中
????if?gesture.state?==?.changed?{
????????//?當(dāng)前矩陣2D變換??縮放通過(guò)(手勢(shì)縮放的參數(shù))
????????transform?=?transform.scaledBy(x:?gesture.scale,?y:?gesture.scale)
????????//?要復(fù)原到1(原尺寸),不要疊加放大
????????gesture.scale?=?1
????}}//?rotateGesture?旋轉(zhuǎn)手勢(shì)//?旋轉(zhuǎn)的方法(文件私有)。??gesture手勢(shì)?:UI旋轉(zhuǎn)手勢(shì)識(shí)別器@objcfileprivate?func?rotateImage(gesture:?UIRotationGestureRecognizer)?{
????if?gesture.state?==?.changed?{
????????transform?=?transform.rotated(by:?gesture.rotation)
????????//?0為弧度制(要跟角度轉(zhuǎn)換)
????????gesture.rotation?=?0
????}}//?panGesture?拖拽/平移手勢(shì)//?平移的方法(文件私有)。??gesture手勢(shì)?:UI平移手勢(shì)識(shí)別器@objcfileprivate?func?panImage(gesture:?UIPanGestureRecognizer)?{
????if?gesture.state?==?.changed?{
????????//?坐標(biāo)轉(zhuǎn)換至父視圖坐標(biāo)
????????let?gesturePosition?=?gesture.translation(in:?superview)
????????//?用移動(dòng)距離與原位置坐標(biāo)計(jì)算。?gesturePosition.x?已經(jīng)帶正負(fù)了
????????center?=?CGPoint(x:?center.x?+?gesturePosition.x,?y:?center.y?+?gesturePosition.y)
????????//?.zero?為?CGPoint(x:?0,?y:?0)的簡(jiǎn)寫(xiě),?位置坐標(biāo)回0
????????gesture.setTranslation(.zero,?in:?superview)
????}}//?雙擊動(dòng)作(UI點(diǎn)擊手勢(shì)識(shí)別器)@objcfileprivate?func?doubleTapGesture(tap:?UITapGestureRecognizer)?{
????//?狀態(tài)?雙擊結(jié)束后
????if?tap.state?==?.ended?{
????????//?翻轉(zhuǎn)?90度
????????let?ratation?=?CGFloat(Double.pi?/?2.0)
????????//?變換???旋轉(zhuǎn)角度?=?之前的旋轉(zhuǎn)角度?+?旋轉(zhuǎn)
????????transform?=?CGAffineTransform(rotationAngle:?previousRotation?+?ratation)
????????previousRotation?+=?ratation????}}

實(shí)現(xiàn)的效果下圖所示:

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

使用?UICollectionView?作為貼紙容器,通過(guò)閉包把點(diǎn)擊事件對(duì)應(yīng)索引映射的 icon 圖片實(shí)例化為貼紙對(duì)象傳遞給父視圖:

collectionView.cellSelected?=?{?cellIndex?in
????let?stickerImage?=?UIImage(named:?collectionView.iconTitle?+?"\(cellIndex)")
????let?sticker?=?UNStickerView()
????sticker.width?=?100
????sticker.height?=?100
????sticker.imgViewModel?=?UNStickerView.ImageStickerViewModel(image:?stickerImage!)
????self.sticker?(sticker)}

在父視圖中通過(guò)實(shí)現(xiàn)閉包接收貼紙對(duì)象,這樣就完成了「貼紙」到「畫(huà)布」的全流程。

stickerComponentView.sticker?=?{
????$0.viewDelegate?=?self
????//?父視圖居中
????$0.center?=?self.view.center
????$0.tag?=?self.stickerTag????self.stickerTag?+=?1
????self.view.addSubview($0)
????//?添加到貼紙集合中
????self.stickerViews.append($0)}

「照片」和「文字」

手帳編輯頁(yè)面的底部工具欄之前沒(méi)做好設(shè)計(jì),按道理來(lái)說(shuō),應(yīng)該直接上一個(gè)?UITabBar?即可完事,但最終也使用了?UICollectionView?完成。讀取設(shè)備照片操作比較簡(jiǎn)單,不需要自定義相冊(cè),所以通過(guò)系統(tǒng)的?UIImagePicker?完成,對(duì)自定義相冊(cè)感興趣的同學(xué)可以看我的這篇文章。頂部工具欄的代碼細(xì)節(jié)如下所示:

//?底部的點(diǎn)擊事件collectionView.cellSelected?=?{?cellIndex?inswitch?cellIndex?{
????//?背景
????case?0:
????????self.stickerComponentView.isHidden?=?true

????????brushView.isHidden?=?true
????????self.bgImageView.image?=?brushView.drawImage()

????????self.present(self.colorBottomView,?animated:?true,?completion:?nil)
????//?貼紙
????case?1:
????????brushView.isHidden?=?true
????????self.bgImageView.image?=?brushView.drawImage()

????????self.stickerComponentView.isHidden?=?false
????????UIView.animate(withDuration:?0.25,?animations:?{
????????????self.stickerComponentView.bottom?=?self.bottomCollectionView!.y????????})
????//?文字
????case?2:
????????self.stickerComponentView.isHidden?=?true

????????brushView.isHidden?=?true
????????self.bgImageView.image?=?brushView.drawImage()

????????let?vc?=?UNTextViewController()
????????self.present(vc,?animated:?true,?completion:?nil)
????????vc.complateHandler?=?{?viewModel?in
????????????let?stickerLabel?=?UNStickerView(frame:?CGRect(x:?150,?y:?150,?width:?100,?height:?100))
????????????self.view.addSubview(stickerLabel)
????????????stickerLabel.textViewModel?=?viewModel????????????self.stickerViews.append(stickerLabel)
????????}
????//?照片
????case?3:
????????self.stickerComponentView.isHidden?=?true

????????brushView.isHidden?=?true
????????self.bgImageView.image?=?brushView.drawImage()

????????self.imagePicker.delegate?=?self
????????self.imagePicker.sourceType?=?.photoLibrary????????self.imagePicker.allowsEditing?=?true
????????self.present(self.imagePicker,?animated:?true,?completion:?nil)
????//?畫(huà)筆
????case?4:
????????self.stickerComponentView.isHidden?=?true

????????brushView.isHidden?=?false
????????self.bgImageView.image?=?nil
????????self.view.bringSubviewToFront(brushView)
????default:?break}

底部工具欄的每一個(gè)模塊都是一個(gè)?UIView,這部分做的也不太好,最佳的做法應(yīng)該是基于?UIWindow?或者?UIViewController?做一個(gè)「工具容器」作為各個(gè)模塊 UI 內(nèi)容元素的容器,通過(guò)這種做法就可以免去在底部工具欄的點(diǎn)擊事件回調(diào)中寫(xiě)這么多的視圖顯示 / 隱藏的狀態(tài)代碼。

關(guān)注「照片」部分的代碼塊,實(shí)現(xiàn)?UIImagePickerControllerDelegate?協(xié)議后的方法為:

extension?UNContentViewController:?UIImagePickerControllerDelegate?{
????///?從圖片選擇器中獲取選擇到的圖片
????func?imagePickerController(_?picker:?UIImagePickerController,
???????????????????????????????didFinishPickingMediaWithInfo?info:?[UIImagePickerController.InfoKey?:?Any])?{
????????//?獲取到編輯后的圖片
????????let?image?=?info[UIImagePickerController.InfoKey.editedImage]?as??UIImage
????????if?image?!=?nil?{
????????????let?wh?=?image!.size.width?/?image!.size.height????????????//?初始化貼紙
????????????let?sticker?=?UNStickerView(frame:?CGRect(x:?150,?y:?150,?width:?100,?height:?100?*?wh))
????????????//?添加視圖
????????????self.view.addSubview(sticker)
????????????sticker.imgViewModel?=?UNStickerView.ImageStickerViewModel(image:?image!)
????????????//?添加到貼紙集合中
????????????self.stickerViews.append(sticker)

????????????picker.dismiss(animated:?true,?completion:?nil)
????????}
????}}

文字

文字模塊暴露給父視圖也是一個(gè)實(shí)例化后的貼紙對(duì)象,不過(guò)在文字 VC 里需要對(duì)文字進(jìn)行顏色、字體和字號(hào)的選擇。做完了才發(fā)現(xiàn)其實(shí)因?yàn)橘N紙是可以通過(guò)手勢(shì)進(jìn)行放大和縮小的,沒(méi)必要做字號(hào)的選擇......

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

其中比較費(fèi)勁的是對(duì)文字顏色的選擇,剛開(kāi)始我想的直接上 RGB 調(diào)色就算了,后來(lái)想到如果直接通過(guò) RGB 有三個(gè)通道,調(diào)起色來(lái)非常的難受。想到之前在做《瘋狂彈球》這個(gè)游戲時(shí)使用的 HSB 顏色模式,做一個(gè)圓盤(pán)顏色選擇器,后來(lái)在思考實(shí)現(xiàn)細(xì)節(jié)的過(guò)程中了這么 EF 寫(xiě)的這個(gè)庫(kù)?EFColorPicker,非常好用,改了改 UI 后直接拿來(lái)用了,感謝 EF !

「氣泡視圖」的本身是個(gè)?UIViewController,但是需要對(duì)其幾個(gè)屬性進(jìn)行設(shè)置。其實(shí)現(xiàn)流程比較流程化,比較好的做法是封裝一下,把這些模版化的代碼變成一個(gè)「氣泡視圖」類供業(yè)務(wù)方使用,但因?yàn)闀r(shí)間關(guān)系就一直在 copy,核心代碼如下:

///?文字大小氣泡private?var?sizeBottomView:?UNBottomSizeViewController?{
????get?{
????????let?sizePopover?=?UNBottomSizeViewController()
????????sizePopover.size?=?self.textView.font?.pointSize
????????sizePopover.preferredContentSize?=?CGSize(width:?200,?height:?100)
????????sizePopover.modalPresentationStyle?=?.popover????????let?sizePopoverPVC?=?sizePopover.popoverPresentationController
????????sizePopoverPVC?.sourceView?=?self.bottomCollectionView
????????sizePopoverPVC?.sourceRect?=?CGRect(x:?bottomCollectionView!.cellCenterXs[1],?y:?0,?width:?0,?height:?0)
????????sizePopoverPVC?.permittedArrowDirections?=?.down
????????sizePopoverPVC?.delegate?=?self
????????sizePopoverPVC?.backgroundColor?=?.white

????????sizePopover.sizeChange?=?{?size?in
????????????self.textView.font?=?UIFont(name:?self.textView.font!.familyName,?size:?size)
????????}

????????return?sizePopover????}}

在需要彈出該氣泡視圖的地方通過(guò)?present?即可調(diào)用:

collectionView.cellSelected?=?{?cellIndex?in
????switch?cellIndex?{
????case?0:?self.present(self.fontBottomView,
????????????????????????????animated:?true,
????????????????????????????completion:?nil)
????case?1:?self.present(self.sizeBottomView,
????????????????????????????animated:?true,
????????????????????????????completion:?nil)
????case?2:?self.present(self.colorBottomView,
????????????????????????????animated:?true,
????????????????????????????completion:?nil)
????default:?break
????}}

畫(huà)筆

之前在滴滴實(shí)習(xí)時(shí),寫(xiě)過(guò)一個(gè)關(guān)于畫(huà)筆的組件(居然已經(jīng)兩年前了...),但是這個(gè)畫(huà)筆是基于?drawRect:?方法去做的,對(duì)于內(nèi)存十分不友好,一直畫(huà)下去,內(nèi)存就會(huì)一直漲,這回采用了?CAShapeLayer?重寫(xiě)了一個(gè),效果還不錯(cuò)。

如何實(shí)現(xiàn)一個(gè)手帳 APP開(kāi)發(fā)

關(guān)于畫(huà)筆的撤回之前基于?drawRect:?的方式去做就會(huì)非常簡(jiǎn)單,每一次的撤回相當(dāng)于重繪一次,把被撤回的線從繪制點(diǎn)數(shù)組中?remove?掉就好了,但基于?CAShapeLayer?實(shí)現(xiàn)不太一樣,因?yàn)槠涿恳还P都是直接生成在?layer?中了,如果需要撤回就得把當(dāng)前重新生成?layer。

所以最后我的做法是每畫(huà)一筆都去生成一張圖片保存到數(shù)組中,當(dāng)執(zhí)行撤回操作時(shí),就把撤回?cái)?shù)組中的最后一個(gè)元素替換當(dāng)前正在的繪制畫(huà)布內(nèi)容,并從撤回?cái)?shù)組中移除這個(gè)元素。

有了撤回,那也要把重做給上了。重做的就是防止撤回,做法跟撤回類似。再創(chuàng)建一個(gè)重做數(shù)組,把每次從撤回?cái)?shù)組中移除掉的圖片都?append?到重做數(shù)組中即可。以下為撤回重做的核心代碼:

//?undo?撤回@objcprivate?func?undo()?{
????//?undoDatas?可撤回集合?數(shù)量
????guard?undoDatas.count?!=?0?else?{?return?}

????//?如果是撤回集合中只有?1?個(gè)數(shù)據(jù),則說(shuō)明撤回后為空
????if?undoDatas.count?==?1?{
????????//?重做?redo??append?添加
????????redoDatas.append(undoDatas.last!)
????????//?撤回?undo?清空
????????undoDatas.removeLast()
????????//?清空?qǐng)D片視圖
????????bgView.image?=?nil
????}?else?{
????????//?把?3?給?redo
????????redoDatas.append(undoDatas.last!)
????????//?從?undo?移除?3.?還剩?2?1
????????undoDatas.removeLast()
????????//?清空?qǐng)D片視圖
????????bgView.image?=?nil
????????//?把?2?給圖片視圖
????????bgView.image?=?UIImage(data:?undoDatas.last!)
????}}//?redo?重做@objcprivate?func?redo()?{
????if?redoDatas.count?>?0?{
????????//?先賦值,再移除(redo的last給圖片視圖)
????????bgView.image?=?UIImage(data:?redoDatas.last!)
????????//?redo的last?給?undo撤回?cái)?shù)組
????????undoDatas.append(redoDatas.last!)
????????//?從redo重做?移除last
????????redoDatas.removeLast()
????}}

關(guān)于橡皮的思路我是這么考慮的。按照現(xiàn)實(shí)生活中情況,使用橡皮時(shí)是把已經(jīng)寫(xiě)在紙上的筆跡給擦除,換到項(xiàng)目中來(lái)看,其實(shí)橡皮也是一種畫(huà)筆只不過(guò)是沒(méi)有顏色的畫(huà)筆罷了,并且可以有兩種思路:

  • 筆跡直接加在?contentLayer?上,此時(shí)需要對(duì)橡皮做一個(gè)?mask,把橡皮筆跡的路徑和底圖做一個(gè)?mask,這樣橡皮筆跡留下的內(nèi)容就是底圖的內(nèi)容了;

  • 筆跡加在另外一個(gè)?layer?上。這種情況可以直接給橡皮設(shè)置成該?layer?的背景色,相當(dāng)于?clearColor

第二種做法我沒(méi)試過(guò),但是第一種做法是非常 OK 的。

總結(jié)

以上就是手帳 app 的最小可行性產(chǎn)品了,當(dāng)然還有很多細(xì)節(jié)都沒(méi)有展開(kāi),比如服務(wù)端部分的代碼思路。因?yàn)榉?wù)端還是圍繞產(chǎn)品出發(fā),設(shè)計(jì)上也不太好,是我第一次使用?Vapor?進(jìn)行開(kāi)發(fā),只發(fā)揮出了?Vapor?的 10% 功力。目前服務(wù)端完成的需求有:

  • 用戶的登錄注冊(cè)和鑒權(quán);

  • 手帳及手帳本的創(chuàng)建、刪除和修改;

  • 貼紙的創(chuàng)建、刪除和修改。

如果不想與服務(wù)端進(jìn)行交互,可以直接該對(duì)應(yīng)按鈕的點(diǎn)擊事件為你想要展示的類,并注釋掉對(duì)應(yīng)的服務(wù)端代碼即可。

分享文章:如何實(shí)現(xiàn)一個(gè)手帳APP開(kāi)發(fā)
新聞來(lái)源:http://aaarwkj.com/article32/pegosc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)站制作做網(wǎng)站、企業(yè)網(wǎng)站制作、App設(shè)計(jì)、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)
天天操天天日天天干夜夜情欢| 日本高清三级精品一区二区| 日本福利一区二区三区| 精品一二三区在线天堂| 欧美福利免费在线视频| 久久综合婷婷亚洲色图| 日韩av在线国产观看| 国产日韩亚洲欧美在线| 91九色国产在线视频| 日韩国产精品一区二区| 哪里可以看日韩免费毛片| 欧美中文字幕内射合集| 午夜性生活视频免费看| 亚洲欧美日韩国产桃色| 国产v精品欧美精品v日韩| 日韩精品亚洲专区在线观看 | 成人性生交视频免费看| 欧美亚洲另类色自拍偷拍| 日本一区二区三区免费不卡视频 | 欧美黄片网站免费观看| 久久久久精品国产亚洲av影院| 成年自拍视频在线观看| 在线观看一区二区三区国产视频| 黄色日韩欧美在线观看| 日韩高清伦理一区二区| 中文字幕人妻紧贴拍摄| 九九九视频精品免费九九| 精品一区二区三区女同| 中文字幕国产成人在线视频| 欧美福利区免费观看视频| 国产女主播高清在线视频| 一区二区三区在线观看精品| 国产精品一级在线播放| 精品欧美日韩国产一区| 中文字幕伦理一区二区| 日本中文字幕一区在线观看| 欧美日韩在线视频第三区| 成人免费av在线网址| 中文在线在线天堂中文| 国产精品国产亚洲精品| 亚洲精品视频一区二区|