UIButton子类显示错误



我有一个通过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)

相关内容

最新更新