【问题标题】:textRectForBounds: Not Called on Custom UITextFields Loaded from NibtextRectForBounds:未在从 Nib 加载的自定义 UITextFields 上调用
【发布时间】:2012-08-14 13:15:50
【问题描述】:

我创建了 UITextField 的一个子类,它覆盖了 [text|editing|placeholder]RectForBounds: (都具有完全相同的实现)。从代码实例化时一切正常,但从 nib 加载时却不行。在从笔尖加载的文本字段上,既不绘制文本也不绘制占位符。

我注意到在用户点击文本字段之前,不会调用任何 RectForBounds 方法;点击时,editing & placeholderRectForBounds 使用正确的边界大小 ({{0, 0}, {300, 39}}) 调用,而 textRectForBounds 使用 ({{0, 0}, {100, 100}}) 调用。

那么,为什么从不绘制文本(并且只在从笔尖加载的字段上)?是我做错了什么,还是 UITextField 的错误?

编辑:

代码如下:

#import "SearchTextField.h"
#import <QuartzCore/QuartzCore.h>

#define BUTTON_WIDTH 50
#define MAX_LABEL_WIDTH 200

@interface SearchTextField ()

@property(retain, nonatomic) UILabel *label;
@property(retain, nonatomic) UIButton *button;

- (void)i_baseInit;

@end

@implementation SearchTextField

@synthesize title = _title;
@synthesize label = label_;
@synthesize button = button_;
@synthesize showButton = _showButton;
@synthesize backgroundView = _my_backgroundView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        _showButton = YES;
        [self i_baseInit];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder])
    {
        [self i_baseInit];
    }
    return self;
}

- (void)i_baseInit
{
    self.opaque = NO;
    self.textAlignment = UITextAlignmentRight;
    self.leftViewMode = UITextFieldViewModeAlways;
    self.rightViewMode = UITextFieldViewModeAlways;
    self.backgroundColor = [UIColor clearColor];

    _my_backgroundView = [[MyView alloc] init];
    self.backgroundView.backgroundColor = [UIColor whiteColor];

    self.label = [[[UILabel alloc] init] autorelease];
    self.label.font = [UIFont fontWithName:@"HelveticaNeue-CondensedBold" size:15];
    self.label.textColor = [UIColor darkGrayColor];
    self.label.textAlignment = UITextAlignmentRight;
    self.label.backgroundColor = [UIColor clearColor];
    self.label.text = _title;
    self.leftView = self.label;

    self.button = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.button setBackgroundImage:[UIImage imageNamed:@"button_sm"]
                           forState:UIControlStateNormal];
    [self.button setBackgroundImage:[UIImage imageNamed:@"button_sm_pressed"]
                           forState:UIControlStateHighlighted];
    self.button.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;
    self.button.hidden = !_showButton;
    self.rightView = self.button;
}

- (void)drawRect:(CGRect)rect
{
    self.backgroundView.frame = CGRectMake(self.bounds.origin.x,
                                           self.bounds.origin.y,
                                           self.bounds.size.width-1, // Without this, the background sticks out 1 pt from the button
                                           self.bounds.size.height);
    [self.backgroundView drawRect:rect];
}

- (id)copy
{
    SearchTextField *copy = [[self.class alloc] initWithFrame:self.frame];
    copy.text = self.text;
    copy.textAlignment = self.textAlignment;
    copy.textColor = self.textColor;

    copy.placeholder = self.placeholder;

    copy.background = self.background;
    copy.backgroundColor = self.backgroundColor;

    copy.borderStyle = self.borderStyle;
    copy.font = self.font;
    copy.showButton = self.showButton;
    copy.title = self.title;

    copy.delegate = self.delegate;

    copy.secureTextEntry = self.secureTextEntry;

    copy.returnKeyType = self.returnKeyType;
    copy.keyboardType = self.keyboardType;

    return copy;
}

#pragma mark - UITextField Positioning -

- (CGRect)textRectForBounds:(CGRect)bounds
{
    CGSize labelSize = [self.label.text sizeWithFont:self.label.font constrainedToSize:CGSizeMake(MAX_LABEL_WIDTH, bounds.size.height)];
    CGSize textSize = [@"Test" sizeWithFont:self.font];
    CGRect rect = CGRectMake(10 + labelSize.width,
                      (bounds.size.height-textSize.height)/2,
                      bounds.size.width - (20 + labelSize.width + ((self.showButton) ? BUTTON_WIDTH : 0)),
                      textSize.height);
    return rect;
}

- (CGRect)placeholderRectForBounds:(CGRect)bounds
{
    return [self textRectForBounds:bounds];
}

- (CGRect)editingRectForBounds:(CGRect)bounds
{
    return [self textRectForBounds:bounds];
}

- (CGRect)leftViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(10,
                      0,
                      [self.label.text sizeWithFont:self.label.font constrainedToSize:CGSizeMake(MAX_LABEL_WIDTH, bounds.size.height)].width,
                      bounds.size.height);
}

- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    if (!self.showButton) { return CGRectZero; }

    return CGRectMake(bounds.size.width-BUTTON_WIDTH,
                      0,
                      BUTTON_WIDTH,
                      bounds.size.height);
}

#pragma mark -

- (void)setTitle:(NSString *)title
{
    [_title release];
    _title = [title retain];
    self.label.text = title;
    [self setNeedsLayout];
}

- (UIImage *)imageForState:(UIControlState)state
{
    return [self.button imageForState:state];
}

- (void)setImage:(UIImage *)image forState:(UIControlState)state
{
    [self.button setImage:image forState:state];
}

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
{
    [self.button addTarget:target action:action forControlEvents:controlEvents];
}

- (void)setShowButton:(BOOL)showButton
{
    self.button.hidden = !showButton;
    _showButton = showButton;
    [self setNeedsLayout];
}

- (MyView *)backgroundView
{
    [self setNeedsDisplay];
    return _my_backgroundView;
}
- (void)dealloc
{
    [_my_backgroundView release];
    [label_ release];
    [button_ release];

    [super dealloc];
}

@end

【问题讨论】:

  • 您是否覆盖了 initWithFrame:?如果是这样,您还需要覆盖 initiWithCoder:,这是 UINib 初始化的方式。
  • 是的,我确实覆盖了 initWithCoder:。除了文字,一切看起来都很好。
  • 今晚我去看看。
  • 谢谢,非常感谢。

标签: objective-c ios uitextfield


【解决方案1】:

问题在于,对于 Apple 的代码,initWithCoder 和 initWithFrame 的路径略有不同,因此它调用此方法一次与占位符字符串无关。

所以在我的测试中,我有两个标签,一个是在代码中创建的,一个是在 nib 中创建的,它们都有一个相当长的占位符字符串。

核心问题与“textRectForBounds:”有关,因为有一条与显示的占位符无关的附加消息。不仅如此,而且边界很大,这会导致您返回一个超出控件边界的矩形。我不太了解您的代码,无法提出解决方案,但至少您现在知道要修复什么。

有了这个额外的日志记录:

- (CGRect)textRectForBounds:(CGRect)bounds
{
    CGRect rect ;
    rect = [super textRectForBounds:bounds];
    NSLog(@"REAL textRectForBounds %@", NSStringFromCGRect(rect) );

    CGSize labelSize = [self.label.text sizeWithFont:self.label.font constrainedToSize:CGSizeMake(MAX_LABEL_WIDTH, bounds.size.height)];
    CGSize textSize = [@"Test" sizeWithFont:self.font]; 

    NSLog(@"labelSize=%@ textSize=%@ bounds=%@", NSStringFromCGSize(labelSize), NSStringFromCGSize(textSize), NSStringFromCGRect(bounds));

    rect = CGRectMake(10 + labelSize.width,
                      (bounds.size.height-textSize.height)/2,
                      bounds.size.width - (20 + labelSize.width + ((self.showButton) ? BUTTON_WIDTH : 0)),
                      textSize.height);

NSLog(@"%@: textRectForBounds %@", type, NSStringFromCGRect(rect) );
    return rect;
}

我看到的是这样的:

labelSize={0, 100} textSize={28, 18} bounds={{0, 0}, {100, 100}}
textRectForBounds {{10, 41}, {80, 18}}

因此系统出于某种原因传入了 100x100 的边界,然后您的代码创建了一个矩形,其 y 偏移量低于文本字段 10 点。您需要考虑到这一点。

【讨论】:

  • 感谢您的回答。我设置了一个断点,发现调用了 layoutSubviews(可能是由于在视图控制器中格式化代码和在 nib 中用户定义的键值对)。我尝试了您的解决方案以获得良好的效果,但仍然没有绘制文本。
  • 糟糕——我太专注于让 ...RectForBounds 方法出现而忘记了显示文本——我会再看一下我的代码。你能澄清一下“没有文字”吗?笔尖里到底有什么(占位符?文字?)
  • 文本字段中没有要开始的文本,但是当我点击该字段并开始输入时,文本和光标未绘制。我可以键入并读回该值,只是看不到它。另外,当我按住字段时,放大镜中什么也没有。
  • Austin,我想帮忙,但整体设计是你的。通过覆盖您计算的屏幕外矩形,我确实得到了占位符字符串的一种情况。我怀疑如果您像我一样添加大量日志记录,您可以追踪每个案例。我猜想在不同的时间返回的矩形超出了控制范围,或者被其他东西覆盖了。通过在你的 textSize 例程和使用 super 之间来回切换,我可以看到发生了什么变化。
  • 我的自定义 UITextField 也被称为 textRectForBounds: 中的 100x100 矩形。您是否从 Apple 那里听到过有关您的错误的消息?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 2016-03-19
  • 2021-03-07
  • 1970-01-01
相关资源
最近更新 更多