天天看點

解決在自定義tabbar的時候出現雙tabbar的問題

最近有個項目需要自定義tabbar,

我自定義tabbar的一個思路就是完全取代系統自帶的tabbar,生成一個繼承自UIview的customTabbar,将生成的customTabbar完全覆寫到tabbar上,為了讓我們自己生成的tabbar也能使用系統的一些方法,我們需要将customTabbar添加到系統的tabbar上,這就是我的一個大概思路(後期再添加自定義的相關邏輯和代碼)

在自定義tabbar的時候出現的問題,在iOS7以後tabbar做了一些修改,如果我們将customTabbar直接添加到系統的tabbar後,我們會發現,在顯示的時候出現我們自己的tabbar和系統的tabbar這種效果當然使我們不需要的,怎麼解決呢?我提供一個我的思路:我的做法是将系統tabbar生成的UItabbarButton從他的父視圖上面移除,

for (UIView *button in self.tabBar.subviews) {
        if ([button isKindOfClass:[LXQTabBar class]]) {
            NSLog(@"button == %@",button);
        } else {
            [button removeFromSuperview];
        }
    }
           

這樣就完美解決了,但是在後期使用中又發現一個問題,當我們dismiss或則popToViewController的時候,還是會出現系統的tabbarbutton,什麼原因呢?我也不清楚,我大概想到可能和view裡面的layoutSubviews這個方法有關,(希望有大神能講解一下這一塊的東西,謝謝),但是tabbarController沒有這個方法,隻有viewwilllayoutsubviews和ViewWilldidlayoutsubsiews這兩個方法,最後将删除系統tabbarbutton的方法添加到了ViewWillLayoutSubviews這個方法裡面就解決了這個問題

後記:

在更新iOS 10以後又重新出現以前的情況,一時不知道該怎麼去解決,後面想了想,一直在外部去修改還不如去内部修改,是以想到了runtime來解決這個問題,通過runtime去修改系統的方法下面列出代碼:

一、列印UITabbar系統方法:

- (void)systemMethod{
    unsigned int count;
    NSMutableArray *array = [NSMutableArray array];
    Method *meths = class_copyMethodList([UITabBar class], &count);
    for (int i = 0; i < count; i ++) {
        Method meth = meths[i];
        SEL sel = method_getName(meth);
        const char *name = sel_getName(sel);
        NSString *str = [NSString stringWithFormat:@"-------------- > %s",name];
        [array addObject:str];
    }
    LOG(@"%@",array);
}
           

列印的結果:

(
    "-------------- > remove_layoutSubviews",
    "-------------- > setDelegate:",
    "-------------- > layoutSubviews",
    "-------------- > _populateArchivedSubviews:",
    "-------------- > hitTest:withEvent:",
    "-------------- > _intrinsicSizeWithinSize:",
    "-------------- > _contentHuggingDefault_isUsuallyFixedHeight",
    "-------------- > sizeThatFits:",
    "-------------- > traitCollectionDidChange:",
    "-------------- > _backgroundView",
    "-------------- > setSemanticContentAttribute:",
    "-------------- > setTranslatesAutoresizingMaskIntoConstraints:",
    "-------------- > touchesBegan:withEvent:",
    "-------------- > touchesMoved:withEvent:",
    "-------------- > touchesEnded:withEvent:",
    "-------------- > touchesCancelled:withEvent:",
    "-------------- > _setVisualAltitude:",
    "-------------- > _setVisualAltitudeBias:",
    "-------------- > isTranslucent",
    "-------------- > isLocked",
    "-------------- > didUpdateFocusInContext:withAnimationCoordinator:",
    "-------------- > preferredFocusedItem",
    "-------------- > setTintColor:",
    "-------------- > _isEligibleForFocus",
    "-------------- > canBecomeFocused",
    "-------------- > removeConstraint:",
    "-------------- > addConstraint:",
    "-------------- > _didMoveFromWindow:toWindow:",
    "-------------- > hitTest:forEvent:",
    "-------------- > _didChangeFromIdiom:onScreen:traverseHierarchy:",
    "-------------- > _subclassImplementsDrawRect",
    "-------------- > backgroundImage",
    "-------------- > shadowImage",
    "-------------- > setShadowImage:",
    "-------------- > _appearanceStorage",
    "-------------- > _accessibilityButtonShapesParametersDidChange",
    "-------------- > _effectiveBarTintColor",
    "-------------- > setItems:animated:",
    "-------------- > setLocked:",
    "-------------- > setBarStyle:",
    "-------------- > _hidesShadow",
    "-------------- > _backdropViewLayerGroupName",
    "-------------- > _setBackdropViewLayerGroupName:",
    "-------------- > _shadowView",
    "-------------- > _setBackgroundView:",
    "-------------- > _shadowAlpha",
    "-------------- > _setShadowAlpha:",
    "-------------- > _disableBlurTinting",
    "-------------- > _setDisableBlurTinting:",
    "-------------- > setBarTintColor:",
    "-------------- > _setHidesShadow:",
    "-------------- > barStyle",
    "-------------- > setTranslucent:",
    "-------------- > barTintColor",
    "-------------- > _accessoryView",
    "-------------- > _isTranslucent",
    "-------------- > _setBarOrientation:",
    "-------------- > _setAccessoryView:",
    "-------------- > setSelectedItem:",
    "-------------- > _setPreferredFocusHeading:",
    "-------------- > _setFocusedItemHightlightShouldBeVisible:",
    "-------------- > _setHiddenAwaitingFocus:",
    "-------------- > beginCustomizingItems:",
    "-------------- > isCustomizing",
    "-------------- > setBackgroundImage:",
    "-------------- > _sendAction:withEvent:",
    "-------------- > _barMetrics",
    "-------------- > _imageStyle",
    "-------------- > _setBarMetrics:",
    "-------------- > _setImageStyle:",
    "-------------- > selectionIndicatorImage",
    "-------------- > selectedImageTintColor",
    "-------------- > _effectiveUnselectedTabTintColorConsideringView:",
    "-------------- > _buttonDown:",
    "-------------- > _buttonUp:",
    "-------------- > _buttonCancel:",
    "-------------- > _showsHighlightedState",
    "-------------- > _setShowsHighlightedState:",
    "-------------- > _scrollsItems",
    "-------------- > itemPositioning",
    "-------------- > itemWidth",
    "-------------- > itemSpacing",
    "-------------- > _configureItems:",
    "-------------- > _setBackgroundNeedsUpdate:",
    "-------------- > _blurEnabled",
    "-------------- > _preferredFocusHeading",
    "-------------- > selectedItem",
    "-------------- > _focusedItemHighlightShouldBeVisible",
    "-------------- > _setBlurEnabled:",
    "-------------- > setSelectionIndicatorImage:",
    "-------------- > setSelectedImageTintColor:",
    "-------------- > _configureTabBarReplacingItem:withNewItem:swapping:",
    "-------------- > _positionAllItems",
    "-------------- > setItemWidth:",
    "-------------- > setItemSpacing:",
    "-------------- > _setScrollsItems:",
    "-------------- > setItemPositioning:",
    "-------------- > _accessibilityButtonShapesEnabledDidChangeNotification:",
    "-------------- > setUnselectedItemTintColor:",
    "-------------- > _doCommonTabBarInit",
    "-------------- > _effectiveBarOrientation",
    "-------------- > _updateBackgroundColorForTraitCollection:",
    "-------------- > _customizeWithAvailableItems:",
    "-------------- > _dismissCustomizeSheet:",
    "-------------- > _updateTintedImages:selected:",
    "-------------- > _effectiveBarTintColorDidChange",
    "-------------- > unselectedItemTintColor",
    "-------------- > _effectiveUnselectedTintColor",
    "-------------- > _isHiddenAwaitingFocus",
    "-------------- > _buttonDownDelayed:",
    "-------------- > _adjustButtonSelection:",
    "-------------- > _customizeDoneButtonAction:",
    "-------------- > _totalDimensionForItems:spacing:dimension:scaleFactor:",
    "-------------- > _setBackgroundImage:",
    "-------------- > _setSelectionIndicatorImage:",
    "-------------- > _setLabelFont:",
    "-------------- > _setLabelTextColor:selectedTextColor:",
    "-------------- > _setLabelShadowColor:",
    "-------------- > _setLabelShadowOffset:",
    "-------------- > _setVibrantLabels:",
    "-------------- > _vibrantLabels",
    "-------------- > _nextSelectionSlideDuration",
    "-------------- > _setNextSelectionSlideDuration:",
    "-------------- > _backgroundNeedsUpdate",
    "-------------- > _setTabBarSizing:",
    "-------------- > _setTabButtonWidth:",
    "-------------- > _tabButtonWidth",
    "-------------- > _setInterTabButtonSpacing:",
    "-------------- > _interTabButtonSpacing",
    "-------------- > _barOrientation",
    "-------------- > endCustomizingAnimated:",
    "-------------- > _makeCurrentButtonFirstResponder",
    "-------------- > _setDividerImage:forLeftButtonState:rightButtonState:",
    "-------------- > _dividerImageForLeftButtonState:rightButtonState:",
    "-------------- > _pendingFocusAction",
    "-------------- > _setPendingFocusAction:",
    "-------------- > _focusedTabBarItem",
    "-------------- > _tabBarFinishedAnimating",
    "-------------- > dismissCustomizeSheet:",
    "-------------- > _scaleFactorForItems:spacing:dimension:maxWidth:",
    "-------------- > _updateTabBarItemView:",
    "-------------- > _tabBarSizing",
    "-------------- > isElementAccessibilityExposedToInterfaceBuilder",
    "-------------- > _autolayoutSpacingAtEdge:inContainer:",
    "-------------- > _autolayoutSpacingAtEdge:nextToNeighbor:",
    "-------------- > _hasCustomAutolayoutNeighborSpacing",
    "-------------- > encodeWithCoder:",
    "-------------- > initWithCoder:",
    "-------------- > delegate",
    "-------------- > setBounds:",
    "-------------- > .cxx_destruct",
    "-------------- > dealloc",
    "-------------- > initWithFrame:",
    "-------------- > setFrame:",
    "-------------- > items",
    "-------------- > setItems:",
    "-------------- > drawRect:"
)
           

我接觸iOS的時間也不長,不能從這對堆結果中去找到具體設定tabbarbutton的方法,但是我知道layoutSubviews是布局子視圖的方法,然後就用runtime替換掉UItabbar中的layoutSubviews方法,在布局子視圖的時候将系統自帶的UItabbarbutton給移除掉,貼代碼:

這段代碼是寫在UItabbar的分類中的:

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL systemSel = @selector(layoutSubviews);
        SEL lxqSel = @selector(remove_layoutSubviews);
        
        Method systemMethod = class_getInstanceMethod([self class], systemSel);
        Method lxqMethod = class_getInstanceMethod([self class], lxqSel);
        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(lxqMethod), method_getTypeEncoding(lxqMethod));
        if (isAdd) {
            class_replaceMethod(self, lxqSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
        } else {
            method_exchangeImplementations(systemMethod, lxqMethod);
        }
    });
}

- (void)remove_layoutSubviews{
    NSArray *subviews = self.subviews;
    for (UIView *subview in subviews) {
        if ([subview isKindOfClass:[LXQTabBar class]]) {
            
        } else {
            [subview removeFromSuperview];
        }
    }
    
}
           

這樣就完美解決了iOS10 以及以前系統的問題了,不過就是不知道這樣做了之後會不會出現稽核不通過的問題!

繼續閱讀