我有一个通过NIB文件创建的按钮。我已经从UIButton
派生了一个类,替换了NIB文件中的类名。
现在我的按钮显示没有背景。文本在那里,文本字体和颜色都是正确的,它对点击的反应如预期的那样,但就好像背景是透明的一样。在NIB中,它不是透明的——除了类名之外,我没有改变任何属性。
子类是微不足道的-它没有覆盖任何内容(目前)。拜托,我做错了什么?
我需要UIButton子类的原因是因为我想要能够,在某些情况下,将文本从按钮拖到其他地方。如果在UIKit提供的视图中有另一种处理拖放的方法,我很乐意听到。
检查NIB文件中按钮的状态。有可能您正在查看"活动"状态或其他东西,而不是更常见的uicontrolstatnormal。
老实说不确定子类出了什么问题,但'Net(包括SO)充满了关于子类化UIButton的警示故事,以及你如何不应该。
所以我会在四种触摸处理方法上使用方法搅拌。下面的函数用我的实现(取自MyButton类)替换了提供的按钮方法,同时将旧的按钮保存在系统按钮类中的不同选择器下:
//Does NOT look at superclasses
static bool MethodInClass(Class c, SEL sel)
{
unsigned n,i ;
Method *m = class_copyMethodList(c, &n);
for(i=0;i<n;i++)
{
if(sel_isEqual(method_getName(m[i]), sel))
return true;
}
return false;
}
static void MountMethod(Class &buc, SEL SrcSel, SEL SaveSlotSel)
{
IMP OldImp = [buc instanceMethodForSelector:SrcSel];
IMP NewImp = [[MyButton class] instanceMethodForSelector:SrcSel];
if(OldImp && NewImp)
{
//Save the old implementation. Might conflict if the technique is used
//independently on many classes in the same hierarchy
Method SaveMe = class_getInstanceMethod(buc, SaveSlotSel);
if(SaveMe == NULL)
class_addMethod(buc, SaveSlotSel, OldImp, "v@:@@");
else
method_setImplementation(SaveMe, OldImp);
//Note: the method's original implemenation might've been in the base class
if(MethodInClass(buc, SrcSel))
{
Method SrcMe = class_getInstanceMethod(buc, SrcSel);
if(SrcMe)
method_setImplementation(SrcMe, NewImp);
}
else //Add an override in the current class
class_addMethod(buc, SrcSel, NewImp, "v@:@@");
}
}
并这样称呼它:
Class buc = [bu class];
MountMethod(buc, @selector(touchesBegan:withEvent:), @selector(MyButton_SavedTouchesBegan:withEvent:));
MountMethod(buc, @selector(touchesCancelled:withEvent:), @selector(MyButton_SavedTouchesCancelled:withEvent:));
MountMethod(buc, @selector(touchesEnded:withEvent:), @selector(MyButton_SavedTouchesEnded:withEvent:));
MountMethod(buc, @selector(touchesMoved:withEvent:), @selector(MyButton_SavedTouchesMoved:withEvent:));
这样做的缺点是为所有按钮安装上述方法,而不仅仅是为所需的按钮安装方法。在MyButton的实现中,有一个额外的检查是否要为这个特定的按钮启用拖放功能。为此,我使用了关联对象。
一个很好的点是touchesXXX方法是在UIControl类中实现的,而不是在UIButton中。我对swizzling的第一个天真实现会替换UIControl中的方法,而不是按钮类。当前的实现没有假设这两种情况。此外,它没有对按钮的运行时类做任何假设。可以是UIButton,可以是任何东西(在真正的iOS中,它是UIRoundedRectButton)