Ios 不带接口生成器的自定义UITabBar子类
使用IB(无论是故事板还是XIB),通过在Identity Inspector->Custom class中编辑类名,可以很容易地让UITabBarController使用UITabBar的子类 如何模仿IB的这个“自定义类”特性,而不使用它 我尝试了以下方法(在我的UITabBarController子类中): 无效–将显示选项卡栏,但为空。问题不在其他地方,因为被覆盖的Ios 不带接口生成器的自定义UITabBar子类,ios,swift,uikit,uitabbarcontroller,uitabbar,Ios,Swift,Uikit,Uitabbarcontroller,Uitabbar,使用IB(无论是故事板还是XIB),通过在Identity Inspector->Custom class中编辑类名,可以很容易地让UITabBarController使用UITabBar的子类 如何模仿IB的这个“自定义类”特性,而不使用它 我尝试了以下方法(在我的UITabBarController子类中): 无效–将显示选项卡栏,但为空。问题不在其他地方,因为被覆盖的var中的returningsuper.tabBar修复了它 我想,问题是我没有设置我的customTabBar(框架、位置
var
中的return
ingsuper.tabBar
修复了它
我想,问题是我没有设置我的customTabBar
(框架、位置,将其添加到视图层次结构),但我希望让UITabBarControllerloadView
(我想这是一个,不确定)为我做这件事,就像它设置任何其他UITabBar
一样
想法 我想你不能。对于这个问题,我花了一些时间浏览了
uitabar
和UITabBarController
的文档
UITabBarController
的tabBar
属性仅为get属性
@available(iOS 3.0, *)
open var tabBar: UITabBar { get } // Provided for -[UIActionSheet showFromTabBar:]. Attempting to modify the contents of the tab bar directly will throw an exception.
此外,UITabBarController
中规定,您不应操纵此类属性
决不应试图操纵UITabBar对象本身
存储在此属性中。如果尝试执行此操作,则选项卡栏视图
抛出异常。为选项卡栏配置项目的步骤
接口,则应指定一个或多个自定义视图
将控制器添加到viewControllers属性。选项卡栏收集
指定的视图控制器中所需的选项卡栏项
此属性提供的选项卡栏视图仅适用于各种情况
要使用show(from:)方法显示操作表的位置
UIActionSheet类的
只想添加:但与此uitabarcontroller
不同,对UINavigationController
进行子类化可以使用UINavigationBar
子类初始化此类子类:
UINavigationController(navigationBarClass: <#T##AnyClass?#>, toolbarClass: <#T##AnyClass?#>)
UINavigationController(导航栏类:,工具栏类:)
不幸的是,
UITabBarController
没有这种init方法。如果你选择无视苹果关于支持什么的说法(使用自定义uitabar子类和Interface Builder,并且只使用它),这里有一个肮脏的解决方案(有效):
它需要对ObjC运行时有一点了解,因为我们将在运行时对内容进行快速转换。。。本质上,问题是我不能强制UITabBarController实例化我希望它实例化的类(这里是MyCustomTabBarSubclass)。相反,它总是实例化uitabar
但我知道它是如何实例化的:通过调用-[[uitabar alloc]initWithFrame:][/code>。我还知道,属于init
系列的所有函数都可以返回其类的实例或子类的实例(这是类集群的基础)
所以,我要用这个。我将用我的自定义版本swizzle(=替换实现)uitabar的-initWithFrame:
方法,它不会调用(self=[super initWithFrame:
)而会调用“down”(self=[MyCustomTabBarSubclass.alloc initWithFrame:
)。因此,返回的对象将是MyCustomTabBarSubclass类,这正是我试图实现的
注意我是如何调用MyCustomTabBarSubclass.alloc
——这是因为我的子类可能有UITabBar没有的IVAR,从而使它在内存布局中更大。在重新分配self之前,我可能必须先释放self,否则我可能会泄漏分配的内存,但我一点也不确定(而且ARC“禁止”我调用-release
,所以我必须使用另一个欺骗步骤来调用它)
编辑
(首先,此方法也适用于使用IB自定义类的任何情况)
还要注意,实现这一点需要编写ObjC代码,因为Swift不允许我们调用alloc
,例如,没有双关语。代码如下:
IMP originalImp=NULL;
id uuu Swizzle_InitWithFrame(id self,SEL _cmd,CGRect frame)
{
c类=NSClassFromString(@“MyBundleName.MyCustomTabBarSubclass”);
self=[c alloc];//因此我们将返回MyCustomTabBarSubclass的一个实例
如果(自我){
id(*castedImp)(id,SEL,CGRect)=(id(*)(id,SEL,CGRect))原始IP;
self=castedImp(self,_cmd,frame);/-[super initWithFrame:]
}
回归自我;
}
您还必须确保实际的滑动操作只执行一次(例如,dispatch\u once
)。下面是实际运行的代码:
Method=class\u getInstanceMethod(NSClassFromString(@“uitabar”),@selector(initWithFrame:);
IMP swizzleImp=(IMP)uu Swizzle_InitWithFrame;
originalImp=方法_setImplementation(方法,swizzleImp);
ObjC方面就是这样。
斯威夫特方面:
@objc类MyCustomTabbar子类:UITabBar{
lazy-var-anIvar:Int=0//显然只是一个例子
//别忘了让你所有的IVAR都是懒惰的或可选的
//因为初始化器不会像我们一样被调用
//绕过Swift运行时正常初始化机制
}
在初始化UITabBarController之前,不要忘记调用执行swizzling的ObjC代码
就这样!您欺骗了UITabBarController来实例化自己的UITabBar子类,而不是普通的。如果您使用的是纯ObjC,事情就更简单了(不必处理桥接头,我在这里没有介绍这个主题)
强制性免责声明:搞乱Objective运行时显然不是一件容易的事。确保没有更好的解决方案–IMHO,仅为了避免此类修补而使用XIB是更好的解决方案
UINavigationController(navigationBarClass: <#T##AnyClass?#>, toolbarClass: <#T##AnyClass?#>)
MyCustomTabBar *customTabBar = [[MyCustomTabBar alloc] initWithFrame:CGRectZero];
customTabBar.delegate = self;
[self setValue:customTabBar forKey:@"tabBar"];