【问题标题】:How can I create a UIButton supporting dynamic multiline text with image background?如何创建支持具有图像背景的动态多行文本的 UIButton?
【发布时间】:2015-06-11 10:31:51
【问题描述】:

我正在尝试在 iOS 上创建一个 UI 元素,它可以扩展或收缩以适应动态的、通常是多行的文本。我需要在看起来很像消息气泡的文本下方放置一个图像。但是,我在整个 UI 中只需要其中一个,因此表格视图似乎有点过头了——除非有合理的必要性。

我已尝试为此目的使用 UILabel,但它似乎对背景图像的支持非常有限。我只能让它平铺图像,这不是我想要的。

似乎 UIButton 是最简单的构造,应该可以合理地完成我的要求,但我无法让它工作。这是一个在其他方面为空的单一视图应用程序中的代码提炼形式。

- (void)viewDidLoad {
  [super viewDidLoad];

  NSString *text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
  UIImage *image = [[UIImage imageNamed:@"speak_bubble_solid"] resizableImageWithCapInsets:UIEdgeInsetsMake(16, 24, 30, 12)];

  UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
  [button setBackgroundImage:image forState:UIControlStateNormal];
  [button setTitle:text forState:UIControlStateNormal];
  button.titleLabel.textColor = [UIColor whiteColor];
  button.titleLabel.textAlignment = NSTextAlignmentLeft;
  button.titleLabel.numberOfLines = 0;
  button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
  button.contentEdgeInsets = UIEdgeInsetsMake(16, 10, 30, 10);
  button.translatesAutoresizingMaskIntoConstraints = NO;

  [self.view addSubview:button];
  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[button]-|"
                                                                    options:NSLayoutFormatAlignAllTop
                                                                    metrics:0
                                                                      views:NSDictionaryOfVariableBindings(button)]];

}

这是我运行应用程序时的样子:

显然,我正在寻找的是用于展开以包含其内容的按钮。所以即使最初的渲染是错误的,但是当我稍后动态更改文本时,我还需要正确调整它的大小。

我怎样才能创建这个?我需要在代码中看到答案,因为我还是 iOS 开发的新手。

【问题讨论】:

    标签: ios objective-c cocoa-touch uibutton


    【解决方案1】:

    实际上我会使用标签和图像。不是背景图像:图像视图中的图像。

    • 使标签环绕,并根据其内容的大小垂直增长或收缩。这很简单,而且是一个现成的、以前解决过的问题。

    • 使标签的背景清晰。

    • 将图像视图限制在与标签相同的位置和大小,在其后面。

    • 确保图像视图的内容模式是按比例填充的,这样图像的大小将始终与图像视图的大小完全一致。

    • 为图像视图提供一个“可拉伸”的图像,这样无论图像视图的大小如何,它都能正常显示。

    以下是我尝试此操作时得到的一些屏幕截图,其中包含不同长度的自包装标签文本:

    这似乎非常接近您所追求的那种东西。在我的实现中,棘手的部分是调整图像视图的大小/位置,以响应标签在包装时的大小变化,并根据其内容改变其高度。我的解决方法是设置从图像视图到标签的约束,使图像视图大于标签,以便气球出现在标签的外部;然后,我将此代码添加到我的视图控制器中,以根据标签的布局(lab)进一步实时调整图像视图(iv):

    override func viewDidLayoutSubviews() {
        iv.bounds.size.height = lab.bounds.size.height + 60
        iv.frame.origin.y = lab.frame.origin.y - 20
    }
    

    EDIT:但实际上不需要任何代码;正如我在这个 github 示例中演示的那样,它可以完全通过约束来完成:https://github.com/mattneub/MessageBubble

    【讨论】:

    • 您是说不能对具有不应拉伸边缘的图像执行此操作吗?
    • “可拉伸”图像“有一些不应拉伸的边缘”的图像。例如,使用消息气球,您希望中​​间增长,但边界应该继续看起来不错。这就是您使用“可拉伸”图像的原因。你没有必须这样做,但我给你最好的建议,让结果看起来不错。
    • 添加了一些屏幕截图,表明我的建议可以提供您想要的结果。
    • 你成功了。如果您已经编写了一些代码,您也可以发布吗?我需要一段时间才能弄清楚如何将你的指令翻译成代码
    • 好的,谢谢。根据您之前的描述,我已经接近了。我应该尽快让它工作,然后我会接受你的回答。
    【解决方案2】:

    另一种可能的方法是使用绘制的形状而不是图像作为背景。这需要比 Matt 的方法更多的代码,但如果您想更改点的颜色或形状,可能会给您更多的灵活性。我创建了一个名为 RDLabelView 的 UIView 类,它绘制背景形状,并添加一个标签作为子视图。它有一个 text 属性,因此您可以像设置标签一样设置其文本。

    #import "RDLabelView.h"
    
    @interface RDLabelView ()
    @property (strong,nonatomic) UILabel *label;
    @property (strong,nonatomic) CAShapeLayer *bubble;
    @end
    
    @implementation RDLabelView
    
    -(void)awakeFromNib {
    
        self.tapper = [UITapGestureRecognizer new];
        [self addGestureRecognizer:self.tapper];
        self.bubble = [CAShapeLayer layer];
        self.bubble.fillColor = [UIColor colorWithRed:.5 green:1 blue:1 alpha:1].CGColor;
        [self.layer addSublayer:self.bubble];
        self.label = [UILabel new];
        self.label.numberOfLines = 0;
        self.label.translatesAutoresizingMaskIntoConstraints = NO;
        [self addSubview:self.label];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[label]-10-|" options:0 metrics:nil views:@{@"label":self.label}]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[label]-10-|" options:0 metrics:nil views:@{@"label":self.label}]];
    }
    
    -(void)setColor:(UIColor *)color { // The color property is declared in the .h file to allow color changes to the bubble
        _color = color;
        self.bubble.fillColor = _color.CGColor;
    }
    
    -(void)setText:(NSString *)text { // The text property is declared in the .h file to allow you to set the text as you would for a UILabel
        _text = text;
        self.label.text = text;
    }
    
    -(UIBezierPath *)appendShapeToRoundedRect:(UIBezierPath *) shape {
        CGPoint lowerLeftCorner = CGPointMake(0, shape.bounds.size.height);
        CGPoint pointToStart = CGPointMake(lowerLeftCorner.x + 30, lowerLeftCorner.y);
        UIBezierPath * arrow = [UIBezierPath bezierPath];
        [arrow moveToPoint:pointToStart];
        [arrow addLineToPoint:CGPointMake(pointToStart.x, pointToStart.y + 20)];
        [arrow addLineToPoint:CGPointMake(pointToStart.x + 10, pointToStart.y)];
        [shape appendPath:arrow];
        return shape;
    }
    
    
    -(void)layoutSubviews {
        [super layoutSubviews];
        UIBezierPath *shape = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:16];
        shape = [self appendShapeToRoundedRect:shape];
        self.bubble.path = shape.CGPath;
    }
    

    【讨论】:

    • 实际上在我的屏幕截图中,我的图像“绘制的形状”。也就是说,我在代码中创建了气泡语音标题图像。但归根结底,它仍然是一个图像;我本可以事先在 Photoshop 中创建它。重要的是它是可拉伸的。
    • 谢谢,但我已经接受了另一个答案,因为在提交您的答案时我已经非常接近复制它了。此外,这篇文章V:|-10-[label]-10-| 向我表明它可能无法满足所有要求。
    • @EbenGeer,没问题,我只是想展示另一种可能的方法。那块只是为了插入标签,所以它不会超出圆角。它基本上完成了 Matt 在 vi​​ewDidLayoutSubview 中的代码所做的事情。
    • 哦,我明白了。我还是新手,抱歉。感谢您的解释。我也试试看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 2019-05-21
    相关资源
    最近更新 更多