简体   繁体   中英

NSAttributedString with image attachment and NSTextTab, text not aligned

I'm trying to have a UIlabel with an image and title on the left and a list of descriptions with bullets on the right, to do that I'm using NSAttributedString like this :

        NSMutableParagraphStyle *pStyle = [[NSMutableParagraphStyle alloc] init];
    pStyle.tabStops =
        @[ [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:tabLocation options:[NSDictionary dictionary]] ];

    NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init];
    NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
    textAttachment.image = [UIImage imageNamed:@"test_image"];
    textAttachment.bounds = CGRectMake(0, -3, 15, 15);//resize the image
    attString = [NSAttributedString attributedStringWithAttachment:textAttachment].mutableCopy;
    [attString appendAttributedString:[[NSAttributedString alloc]
                                          initWithString:[NSString stringWithFormat:@"title\t\u2022 %@",
                                                                                    [@[ @"description1", @"description2" ]
                                                                                        componentsJoinedByString:@"\n\t\u2022 "]]
                                              attributes:@{NSParagraphStyleAttributeName : pStyle}]];
    label.attributedText = attString;

I expect the list on the right to be left aligned but that's not the case, here is the result I get :

在此处输入图片说明

What I expect is the list to be aligned like this : 在此处输入图片说明

The issue is with location parameter in NSTextTab

  • According to description, location parameter helps to position text from left margin. So this is what we needed, just replace below lines

     pStyle.tabStops = @[ [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:tabLocation options:[NSDictionary dictionary]] ]; 

    with

     pStyle.tabStops = @[[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:[self getTextLocationFor:@"test"] options:[NSDictionary dictionary]] ]; 
  • Add getTextLocationFor: method to calculate location as follows

     -(CGFloat)getTextLocationFor:(NSString *)inputStr{ CGSize maximuminputStringWidth = CGSizeMake(FLT_MAX, 30); CGRect textRect = [inputStr boundingRectWithSize:maximuminputStringWidth options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil]; UIImageView * testImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"close_red"]];//Change image name with yours return textRect.size.width + testImage.frame.size.width +2; } 
  • That's it we are ready to go run your project now everything will be fine.

RESULT:

在此处输入图片说明

if I understand you correctly then try these code:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 460, 460)];
label.numberOfLines = 0;
[self.view addSubview:label];

NSMutableParagraphStyle *pStyle = [[NSMutableParagraphStyle alloc] init];
pStyle.tabStops = @[ [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:40 options:@{}] ];

NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:@"img"];
textAttachment.bounds = CGRectMake(0, -3, 30, 30);


NSString *string = [NSString stringWithFormat:@"title\n\r\u2022 %@", [@[ @"description1", @"description2" ] componentsJoinedByString:@"\n\r\u2022 "]];

NSMutableAttributedString *attributedString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] mutableCopy];
[attributedString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:string attributes:@{NSParagraphStyleAttributeName : pStyle}]];

label.attributedText = attributedString;

Here is result

在此处输入图片说明

UPDATE

You can only achieve this using TextKit (NSTextLayoutManager) and specify area which should be use to draw text, or use simple solution and subclass from UIView.

Here is solution with view

ListView.h

@interface ListView : UIView

@property(nonatomic,strong) UIImage *image;
@property(nonatomic,strong) NSString *title;
@property(nonatomic,strong) NSArray *list;

@end

ListView.m

static const CGFloat ImageWidth = 13.f;

@interface ListView()
@property (nonatomic,weak) UIImageView *imageView;
@property (nonatomic,weak) UILabel *titleLabel;
@property (nonatomic,weak) UILabel *listLabel;
@end

@implementation ListView
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    [self setup];
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    [self setup];
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self setup];
}

- (void)setup {
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:imageView];
    self.imageView = imageView;

    UILabel *titleLabel = [[UILabel alloc] init];
    titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    titleLabel.numberOfLines = 0;
    [titleLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
    [titleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
    [self addSubview:titleLabel];
    self.titleLabel = titleLabel;

    UILabel *listLabel = [[UILabel alloc] init];
    listLabel.translatesAutoresizingMaskIntoConstraints = NO;
    listLabel.numberOfLines = 0;
    [listLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    [listLabel setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    [self addSubview:listLabel];
    self.listLabel = listLabel;

    NSDictionary *views = NSDictionaryOfVariableBindings(imageView,titleLabel,listLabel);
    NSDictionary *metrics = @{ @"ImageHeight" : @(ImageWidth) };

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[imageView(ImageHeight)]-0-[titleLabel]-0-[listLabel]-0-|" options:0 metrics:metrics views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[imageView(ImageHeight)]" options:NSLayoutFormatAlignAllTop metrics:metrics views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[titleLabel]" options:NSLayoutFormatAlignAllTop metrics:metrics views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[listLabel]-0-|" options:NSLayoutFormatAlignAllTop metrics:metrics views:views]];
}

- (void)setImage:(UIImage *)image {
    _image = image;
    self.imageView.image = image;
    [self setNeedsLayout];
}

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

- (void)setList:(NSArray *)list {
    _list = list;

    NSMutableParagraphStyle *pStyle = [[NSMutableParagraphStyle alloc] init];
    pStyle.tabStops = @[ [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:40 options:@{}] ];

    NSString *string = [NSString stringWithFormat:@"\u2022 %@", [list componentsJoinedByString:@"\n\u2022 "]];
    self.listLabel.attributedText = [[NSAttributedString alloc] initWithString:string attributes:@{NSParagraphStyleAttributeName : pStyle}];

    [self setNeedsLayout];
}

@end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM