iOS自定义控件的问题及解决方法

来源:互联网 发布:德哈维兰 知乎 编辑:程序博客网 时间:2024/06/02 03:50
       今天要写一个同时包含图片和文字的按钮控件,同时支持4种显示方式:图片在文字上面、下面、左边、右边,并且要能以纯代码和xib/storyboard方式创建,以autolayout对内部的图片和文字进行布局。为了支持纯代码方式创建,重写了initWithFrame方法,在其中用代码创建了UIImageView和UILabel,然后用masonry对其进行布局,没有问题。然后,为支持xib/storyboard方式创建,一开始,以为该自定义控件的实现也要以界面方式(实现方法参见:)。于是又创建了xib,重写了initWithCoder方法,在其中以

[[NSBundle mainBundle] loadNibNamed:@"ImageTitleButton" owner:self options:nil];方式从xib加载内容视图。但是,由于布局有4种方式可选,因此不能在xib中添加约束。所以还是采用masonry进行布局(复用纯代码中的布局代码)。结果问题来了,图片的显示是正常的,但是label的约束死活不起效果,总是显示为xib中拖放的位置和大小。几经周折,最后无奈接受了一点:在xib中创建视图,而在代码中为其添加约束,这种方法不可取,经常会出现各种莫名其妙的问题(笔者之前已经因为这种做法导致的各种视图不显示、显示不正常,已经浪费了很多时间。。。)。

       如果xcode输出以下错误信息,而代码添加的约束确实不存在冲突等问题,那有可能就是用代码为xib中的视图创建约束导致的。

       最后,纠结好久没法解决后,就尝试换了一种思路。一开始,想在initWithCoder方法中转调initWithFrame,即如下所示:

       

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

    [self initWithFrame:CGRectZero];

    returnself;

}

    结果发现不行,又换成如下方式:

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

    if (self = [superinitWithCoder:aDecoder]) {

        [selfaddSubviews];

    }

    returnself;

}

其中addSubviews是代码中创建UIImageView和UILabel的函数:

- (void)addSubviews {

    _imageView = [[UIImageViewalloc] init];

    [selfaddSubview:_imageView];

    _titleLabel = [[UILabelalloc] init];

    [selfaddSubview:_titleLabel];

}

autolayout还是之前的masonry代码,这次终于成功了。

总结一下,一定不要用用代码为xib中的视图创建约束。如果是界面里添加的视图,就在界面上使用autolayout;如果像本文这样不是布局不是静态的,而是比较灵活、运行时才能确定、且区别较大、必须用代码写约束的,那就在代码中创建视图。这并不影响最后整体的自定义控件从界面创建,因为可以参照上述initWithCoder方法,将界面创建转化为纯代码方式。


1 0