demo地址:https://github.com/al-liu/HCSpringBoard.git
效果圖:
說明
項目是個手機銀行app,要求做一個仿照招商手機銀行的最愛菜單功能,沒有找到合適的輪子,就只能自己寫個了。功能是在原有項目上做的(原來只能添加和刪除),后來抽出來一個demo,因為邏輯較復雜,也沒有花太多時間休整代碼,復用程度不夠高,但是按照下面我寫的分析流程來集成該功能并沒有什么困難。
希望朋友們幫我指正代碼問題和bug。
準備工作
組織菜單數據結構在 HCAssistant
類中,配置一個菜單要顯示的圖片,菜單名稱,是否默認顯示,是否可刪除,跳轉頁面等。
顯示菜單
1,獲取存到 NSUserDefaults
中的最愛菜單數據,如果沒有,從配置中的全部菜單中篩選出默認要顯示的數據,并存起來,有了數據之后就使用 HCSpringBoardView
類來生成菜單。
2,在 HCSpringBoardView
的初始化方法里,根據一頁有幾行幾列,確定需要的頁數,和需要的菜單 frame 并創建 UIScrollView 和 UIPageControl。在根據傳進來的模型數組,判斷是文件夾 HCFavoriteFolderModel
還是圖標 HCFavoriteIconModel
分別創建對應的視圖,HCFavoriteFolderView
或 HCFavoriteIconView
并設置代理。
這里的適配很簡陋,不要做參考
模型類 HCFavoriteIconModel
和 HCFavoriteFolderModel
使用 YYModel 做的數據模型轉換,很好用。
HCFavoriteIconModel
image ,name , targetController等屬性。
需要實現NSCoding
協議用于序列化。HCFavoriteFolderModel
'folderName' 文件夾名稱,'iconModelsFolderArray' 存該文件夾下的菜單模型,'iconViewsFolderArray' 存該文件夾下的菜單視圖。
需要實現NSCoding
協議用于序列化。
視圖類 HCFavoriteIconView
和 HCFavoriteFolderView
- HCFavoriteIconView
主要的是下面兩個代理
favoriteIconDelegate
favoriteIconLongGestureDelegate
例如:
@class HCFavoriteIconView;
@protocol HCFavoriteIconDelegate <NSObject>
- (void)deleteIconOfLoveIconView:(HCFavoriteIconView *)iconView;
- (void)pushPageOfLoveIconView:(HCFavoriteIconView *)iconView;
- (void)intoEditingModeOfLoveIconView:(HCFavoriteIconView *)iconView;
@optional
- (void)addIconOfLoveIconView:(HCFavoriteIconView *)iconView;
@end
@protocol HCFavoriteIconLongGestureDelegate <NSObject>
- (void)longGestureStateBegin:(UILongPressGestureRecognizer *)gesture forLoveView:(HCFavoriteIconView *)loveView;
- (void)longGestureStateMove:(UILongPressGestureRecognizer *)gesture forLoveView:(HCFavoriteIconView *)loveView;
- (void)longGestureStateEnd:(UILongPressGestureRecognizer *)gesture forLoveView:(HCFavoriteIconView *)loveView;
- (void)longGestureStateCancel:(UILongPressGestureRecognizer *)gesture forLoveView:(HCFavoriteIconView *)loveView;
@end
定義了刪除,進入下一頁,開始編輯,增加和長按手勢的協議。
- HCFavoriteFolderView
同上有兩個協議方法都是把事件代理到 'HCSpringBoardView' 中。
刪除菜單
HCSpringBoardView
里有兩個屬性_favoriteModelArray 和 _favoriteViewArray 分別管理最愛菜單的模型和視圖,刪除就是刪掉對應的元素,并更新視圖,還要更新全部菜單列表,以至于在添加的時候不是打勾的狀態,可以重新加進來。
進入編輯模式
長按菜單會進入編輯模式,此時用該菜單的模型創建一個拖動的視圖,在window上。
仔細觀察了招商手機銀行的最愛菜單實現,發現拖動圖標速度較快的時候并不會做任何處理,所以它是在一定滑動速度之下,開始檢測的當前拖動圖標的移動點是在其它圖標的中間區域還是四周區域,這樣就可以判斷出該圖標是要換位置還是合并文件夾。
換位置操作在 longGestureStateMove
方法里。
判斷是兩圖標合并還是合并到已有文件夾邏輯在 longGestureStateEnd
里。
至于拖動文件夾就只有換位置的邏輯,相對簡單多了。
現在能合并,看看怎么從文件夾里拖出去?
拖出文件夾
HCFavoriteFolderFloatView
和HCFavoriteFolderMenuView
用于展示文件夾的圖標,在文件夾里的排序和刪除邏輯也是和外面的一樣且不能再合并簡單了很多。
至于拖出去的邏輯是這樣的,首先在文件夾的編輯模式下,拖動時也會在一定速度下檢測點的位置,判斷是不是要換位置,如果拖出了菜單面板,隱藏當前HCFavoriteFolderFloatView
但是并不刪除它(如果刪掉,拖出去的view會卡在那里,招商就有個拖出去卡在左邊的問題,很可能和這個有關系),此時長按手勢的回調方法在HCFavoriteFolderMenuView
里,將移動事件longGestureStateMove
代理給HCSpringBoardView
(HCFavoriteFolderMenuView
有個代理要設置給HCSpringBoardView
)。在HCSpringBoardView
里重新獲取該點,排序合并的邏輯和在外面是一樣的。
待用戶松開手指,調用longGestureStateEnd
時,一樣處理合并邏輯,并將重新拖出的菜單設置代理到HCSpringBoardView
,不要忘了從父視圖刪除掉HCFavoriteFolderFloatView
,就此操作完成。