自定義--iOS控制器(上下拉抽式)

今天我們來自定義iOS的一種控制器,平時(shí)在項(xiàng)目中大部分用的都是tabBar控制器(微信),也有側(cè)滑式控制器(QQ),但是如果類似抽屜式的控制器呢? 原理一樣,只是加了一點(diǎn)數(shù)學(xué)運(yùn)算在里面。

有很多優(yōu)秀的第三方,但我們只需要分隔控制器這塊功能就好,在項(xiàng)目中減少代碼量,不妨自己自定義一個(gè)。 顯示如下:

功能要求

? ? ? ? ? ? ? ? 豎直方向堆疊,每個(gè)控制器如卷起的畫卷一樣,點(diǎn)擊,畫卷展開,再次點(diǎn)擊,畫卷合上(點(diǎn)擊第一封畫卷時(shí),畫卷展開,點(diǎn)擊第二封時(shí),第一封關(guān)閉,第二封展開,以此類推。再次點(diǎn)擊畫卷,畫卷合上)。


注意:之后提到“畫卷”就是“控制器”的意思。

實(shí)現(xiàn)邏輯:

? ? ? ? ? ? ? 1,繼承控制器UIViewController,實(shí)現(xiàn)方法定制;在里面添加extension進(jìn)行“畫卷“自定義。

? ? ? ? ? ? ? 2,實(shí)現(xiàn)相關(guān)數(shù)學(xué)邏輯運(yùn)算(請(qǐng)大家在這里想想畫卷坐標(biāo)變換的實(shí)現(xiàn),不要想得太復(fù)雜哦)。

? ? ? ? ? ? ? 3,以此為基類,創(chuàng)建controller,進(jìn)行UI界面實(shí)現(xiàn)。


? ? ? ? ? ? ? ? ? ?本文只描述了一些核心代碼與邏輯思維,詳細(xì)代碼可參考下面Demo。


一,自定義實(shí)現(xiàn):我們要自定義控制器,顯然得有controller容器,類似tag的標(biāo)記,相關(guān)可見和不可見controller相互轉(zhuǎn)換,以及相關(guān)“畫卷的屬性”,因此在繼承的控制里面定義:

@interface ExpandableViewController : UIViewController

@property (nonatomic, readonly, retain) UIView* contentView;

@property (nonatomic, readonly, retain) UIViewController* expandedViewController; //the top view controller on the stack

@property (nonatomic, readonly, retain) UIViewController* visibleViewController; //Return modal view controller if it exists. Otherwise the top view controller.

@property (nonatomic, copy) NSArray *viewControllers; //the current view controller stack.

@property (nonatomic) NSInteger expandedIndex; //default is 0 is the stack is not empty, NSNotFound otherwise

@property (nonatomic) CGFloat headerViewHeight; // height of each headerView

@end

從而,我們要?jiǎng)討B(tài)加入方法,此時(shí)大家已經(jīng)想到:objc_getAssociatedObject、objc_setAssociatedObject即可實(shí)現(xiàn)。

在調(diào)用此方法是,不要忘記倒入頭文件:

#import <objc/runtime.h>

此時(shí)也注意到,數(shù)個(gè)控制器要在同一界面實(shí)現(xiàn),所以我們不能采用push壓棧方式,或者present的model方式,是的,你也想到了,我們采用以下方式:

- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(5_0);

使用上面方法有時(shí)一不小心就把操作步驟弄反了,或漏掉了,會(huì)帶來不必要的麻煩。大致步驟為:加入控制器,開啟響應(yīng)鏈,移除控制器,結(jié)束響應(yīng)鏈

[UIApplication sharedApplication] beginIgnoringInteractionEvents];

[fromViewController willMoveToParentViewController:nil];

[self addChildViewController:toViewController];

[toViewController didMoveToParentViewController:self];

[fromViewController removeFromParentViewController];

[[UIApplication sharedApplication]endIgnoringInteractionEvents ];

二,邏輯關(guān)系

手勢觸摸,當(dāng)然保證觸摸在響應(yīng)的View上,點(diǎn)擊展開畫卷,再次點(diǎn)擊關(guān)閉畫卷,這里用屬性expandedIndex做標(biāo)記來區(qū)分,判斷響應(yīng)在UIGestureRecognizerDelegate中進(jìn)行:

數(shù)學(xué)邏輯中, controller轉(zhuǎn)換,我們假設(shè)點(diǎn)擊的畫卷標(biāo)記為fromIndex,再次點(diǎn)擊的畫卷為toIndex,則fromIndex > toIndex或者 fromIndex < toIndex。條件為前者時(shí),

CGRect fromViewFrameAfter = fromViewController.view.frame;

fromViewFrameAfter.origin.y += fromViewFrameAfter.size.height;

fromViewController.view.frame = fromViewFrameAfter;

相反為后者時(shí),

CGRect toViewFrameBefore = [self frameForViewControllerAtIndex:toIndex];

toViewFrameBefore.origin.y += toViewFrameBefore.size.height;

toViewController.view.frame = toViewFrameBefore;

讀者可能會(huì)有疑問:frameForViewControllerAtIndex:toIndex這又是什么?這就是來斷定畫卷坐標(biāo)的,看一下代碼您將豁然開朗:

關(guān)鍵布局,則y就是contentView的height加上畫卷的height * 數(shù)量.詳細(xì)看代碼(可能有更簡單的做法):

三,創(chuàng)建controller;因?yàn)槲覀冏远x為了達(dá)到共用效果,面向?qū)ο蠖?,每個(gè)controller都可以調(diào)用并使用;我們暫時(shí)以三個(gè)控制器為例,本Demo中舉例代碼:V1,V2,V3為三個(gè)控制器

[self setViewControllers:@[ [VC1 alloc] init], [[VC2 alloc] init], [[VC3 alloc] init],]];

for (NSUInteger i =0 ; i < [self.viewControllers count]; ++i) {

UIViewController* viewController = self.viewControllers[i];

ExpandableHeaderView* expandableHeaderView = (ExpandableHeaderView *)[viewController expandableHeaderView];

expandableHeaderView.backgroundColor = COLOR_INT32(kColors[i]);

expandableHeaderView.titleLabel.textColor = [UIColor whiteColor];

expandableHeaderView.titleLabel.text = titles[i];

}

詳細(xì)代碼,參考Demo:

百度云升級(jí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容