1

是否可以为标签的某些部分设置背景颜色?我正在尝试创建类似于本文底部的标签部分的内容,必要时会自动换行和字符换行。此外,文本块可以是多个单词。基本上我需要类似的东西:

[label setBackgroundColor:UIColor forRange:NSRange];

我需要支持 iOS 5.0+。

4

2 回答 2

2

我无法使用 NSAttributedString 让它工作。这是我的解决方案。它不是超级干净,但它工作正常。Phrases 是一个 NSStrings 数组。每个短语可以是单个词或多个词。

-(void)addBackgroundsToContainer:(UIView*)container color:(UIColor*)color phrases:(NSArray*)phrases {
    CGFloat x = 0.0;
    CGFloat y = 0.0;
    UIView *lbl;

    for(NSString *phrase in phrases) {
        NSLog(@"Phrase: '%@'", phrase);
        NSArray *words = [phrase componentsSeparatedByString:@" "];
        NSString *text = @"";

        for(int i = 0; i < words.count; i++) {
            NSString *word = [words objectAtIndex:i];
            CGSize wordSize = [word sizeWithFont:[self labelFont]];
            CGSize textSize = [text sizeWithFont:[self labelFont]];

            //if the word appended with the new text fits on one line, concatenate the two
            if(textSize.width + wordSize.width + x < container.frame.size.width) {
                text = [text isEqualToString:@""] ? word : [NSString stringWithFormat:@"%@ %@", text, word];

                if(i == words.count -1 ) {//add the label if it's the last word
                    lbl = [self addLabelWithX:x y:y container:container color:color text:text];
                    x = lbl.frame.size.width + lbl.frame.origin.x + 1.0;
                    text = @"";
                }

            //if the word fits on one line but can't fit on the current line.
            } else if(wordSize.width < container.frame.size.width) {
                //if it's not the first word, add the text that came before it
                if(i != 0) {
                    lbl = [self addLabelWithX:x width:container.frame.size.width - x y:y container:container color:color text:text];
                }

                x = 0.0;
                y = lbl.frame.size.height + lbl.frame.origin.y + 1.0;
                text = word;

                //if it's the last word
                if(i == words.count - 1) {
                    lbl = [self addLabelWithX:x y:y container:container color:color text:text];
                    x = lbl.frame.size.width + lbl.frame.origin.x + 1.0;
                    text = @"";
                }

            //if the word doesn't fit on one line and it 
            } else if(wordSize.width > container.frame.size.width) {
                //I don't need to do char wrapping, but this would be where it'd go

            } 
        }
    }
}

-(UIView*)addLabelWithX:(CGFloat)x y:(CGFloat)y container:(UIView*)container color:(UIColor*)color text:(NSString*)text {
    CGFloat width = [text sizeWithFont:[self labelFont]].width + 4.0;
    return [self addLabelWithX:x width:width y:y container:container color:color text:text];
}
-(UIView*)addLabelWithX:(CGFloat)x width:(CGFloat)width y:(CGFloat)y container:(UIView*)container color:(UIColor*)color text:(NSString*)text {
    CGFloat lineHeight = [@" " sizeWithFont:[self labelFont]].height;

    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(2.0, 0.0, width, lineHeight)];
    [lbl setBackgroundColor:[UIColor clearColor]];
    [lbl setTextColor:[UIColor whiteColor]];
    [lbl setText:text];
    [lbl setFont:[self labelFont]];

    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(x, y, width, lbl.frame.size.height)];
    [v setBackgroundColor:color];
    [v addSubview:lbl];
    [container addSubview:v];

    return v;
}
-(UIFont*)labelFont {
    return [UIFont fontWithName:@"Lato-Regular" size:12.0];
}

编辑:我回去让这不那么可怕.h

#import <UIKit/UIKit.h>

@protocol WATagCloudDelegate;

@interface WATagCloud : UIView
@property(weak, nonatomic) id<WATagCloudDelegate> delegate;
@property(strong, nonatomic) NSArray *dataTags;
@property(strong, nonatomic) UIColor *tagColor;
@property(strong, nonatomic) UIFont *tagFont;

-(void)expand;
-(void)expandWithAnimation;
-(void)collapse;
-(void)collapseWithAnimation;
@end


@protocol WATagCloudDelegate <NSObject>
@required
-(void)tagCloudExpandDown:(WATagCloud*)tagCloud;
-(void)tagCloudCollapseDown:(WATagCloud*)tagCloud;
@end

.m

#import "WATagCloud.h"
#import "WAControlsUtility.h"

@interface WATagCloud()
@property(strong, nonatomic) UIButton *btnToggleVisibility;
@property(strong, nonatomic) UIView *vExpand;
@property(strong, nonatomic) UILabel *lblExpand;
@end

@implementation WATagCloud
@synthesize dataTags = _dataTags;
@synthesize tagColor = _tagColor;
@synthesize tagFont = _tagFont;
@synthesize btnToggleVisibility;
@synthesize vExpand;
@synthesize lblExpand;

-(void)setTagColor:(UIColor *)color {
    _tagColor = color;
    [self setColorOfSubviews];
}
-(void)setDataTags:(NSArray *)tags {
    _dataTags = tags;
    [self addTags];
}
-(UIFont*)tagFont {
    if(_tagFont) {
        return _tagFont;
    } else {
        _tagFont = [UIFont fontWithName:@"Lato-Regular" size:14.0];
        return _tagFont;
    }
}
-(void)setTagFont:(UIFont *)font {
    _tagFont = font;
    [self addTags];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setClipsToBounds:YES];

        self.btnToggleVisibility = [UIButton buttonWithType:UIButtonTypeCustom];
        [self.btnToggleVisibility setFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)];
        [self.btnToggleVisibility addTarget:self action:@selector(onToggleVisibilityDown:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.btnToggleVisibility];

        self.vExpand = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
        [self addSubview:self.vExpand];

        self.lblExpand = [[UILabel alloc] initWithFrame:CGRectMake(2.0, 0.0, 0.0, 0.0)];
        [self.lblExpand setBackgroundColor:[UIColor clearColor]];
        [self.lblExpand setTextColor:[UIColor whiteColor]];
        [self.vExpand addSubview:self.lblExpand];
    }
    return self;
}

//======================================================================
//LAYOUT LABELS
//======================================================================
-(void)addTags {
    [self clearTags];
    CGFloat x = 0.0;
    CGFloat y = 0.0;
    UIView *lbl;

    for(int j = 0; j < self.dataTags.count; j++) {
        NSString *tag = [self.dataTags objectAtIndex:j];
        NSArray *words = [tag componentsSeparatedByString:@" "];
        NSString *text = @"";

        for(int i = 0; i < words.count; i++) {
            NSString *word = [words objectAtIndex:i];
            CGSize wordSize = [word sizeWithFont:self.tagFont];
            CGSize textSize = [text sizeWithFont:self.tagFont];

            if(textSize.width + wordSize.width + x < self.frame.size.width) {//if the word appended with the new text fits on one line, concatenate the two
                text = [text isEqualToString:@""] ? word : [NSString stringWithFormat:@"%@ %@", text, word];

                if(i == words.count -1 ) {//add the label if it's the last word
                    lbl = [self addLabelWithX:x y:y text:text tag:j];
                    x = lbl.frame.size.width + lbl.frame.origin.x + 1.0;
                    text = @"";
                }


            } else if(wordSize.width < self.frame.size.width) {//if the word fits on one line but can't fit on the current line.
                //if it's not the first word, add the text that came before it
                if(i != 0) {
                    lbl = [self addLabelWithX:x width:self.frame.size.width - x y:y text:text tag:j];
                }

                x = 0.0;
                y = lbl.frame.size.height + lbl.frame.origin.y + 1.0;
                text = word;

                //if it's the last word
                if(i == words.count - 1) {
                    lbl = [self addLabelWithX:x y:y text:text tag:j];
                    x = lbl.frame.size.width + lbl.frame.origin.x + 1.0;
                    text = @"";
                }

            } else if(wordSize.width > self.frame.size.width) {//if the word doesn't fit on one line 
                NSArray *characters = [self getCharacterArrayFromString:word];  
            }
        }
    }

    //update the frame height
    [self setFrame:[WAControlsUtility updateFrame:self.frame withX:nil y:nil width:nil height:[NSNumber numberWithFloat:[WAControlsUtility getHeightOfView:self]]]];
    [self.btnToggleVisibility setFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)];
}

//======================================================================
//ADD TO CONTAINER
//======================================================================
-(UIView*)addLabelWithX:(CGFloat)x y:(CGFloat)y text:(NSString*)text tag:(int)tag {
    CGFloat width = [text sizeWithFont:[self tagFont]].width + 4.0;
    return [self addLabelWithX:x width:width y:y text:text tag:tag];
}
-(UIView*)addLabelWithX:(CGFloat)x width:(CGFloat)width y:(CGFloat)y text:(NSString*)text tag:(int)tag {
    CGFloat lineHeight = [@" " sizeWithFont:[self tagFont]].height;

    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(2.0, 0.0, width, lineHeight)];
    [lbl setBackgroundColor:[UIColor clearColor]];
    [lbl setTextColor:[UIColor whiteColor]];
    [lbl setText:text];
    [lbl setFont:[self tagFont]];

    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(x, y, width, lbl.frame.size.height)];
    [v setBackgroundColor:self.tagColor];
    [v setTag:tag];
    [v addSubview:lbl];
    [self addSubview:v];

    return v;
}

//======================================================================
//UI EVENTS
//======================================================================
-(void)onToggleVisibilityDown:(id)sender {
    if(self.delegate ==nil)
        return;

    if(self.frame.size.height > [@" " sizeWithFont:[self tagFont]].height * 2.0 + 2) {//plus 2 for the spacing between lines
        [self.delegate tagCloudCollapseDown:self];
    } else {
        [self.delegate tagCloudExpandDown:self];
    }
}

//======================================================================
//PUBLIC METHODS
//======================================================================
//EXPAND
-(void)expand {
    [self modifyViewsForExpanding];
    [self setFrame:[WAControlsUtility updateFrame:self.frame withX:nil y:nil width:nil height:[NSNumber numberWithFloat:[WAControlsUtility getHeightOfView:self]]]];
    [self.btnToggleVisibility setFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)];
    [self bringSubviewToFront:self.btnToggleVisibility];
}
-(void)expandWithAnimation {
    [UIView animateWithDuration:.4 animations:^{
        [self expand];
    }];
}

//COLLAPSE
-(void)collapse {
    CGFloat height = [@" " sizeWithFont:[self tagFont]].height * 2.0 + 2;//plus 2 for the spacing between lines

    [self setFrame:[WAControlsUtility updateFrame:self.frame withX:nil y:nil width:nil height:[NSNumber numberWithFloat:height]]];
    [self.btnToggleVisibility setFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)];
    [self modifyViewsForCollapsing];
    [self bringSubviewToFront:self.btnToggleVisibility];
}
-(void)collapseWithAnimation {
    [UIView animateWithDuration:.4 animations:^{
        [self collapse];
    }];
}

//======================================================================
//UTILITY
//======================================================================
-(NSArray*)getCharacterArrayFromString:(NSString*)string {
    NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[string length]];
    for (int i=0; i < [string length]; i++) {
        NSString *ichar  = [NSString stringWithFormat:@"%c", [string characterAtIndex:i]];
        [characters addObject:ichar];
    }
    return characters;
}
-(void)setColorOfSubviews {
    for(UIView *view in self.subviews) {
        if([view isKindOfClass:[UIButton class]] == NO) {
            if(view != self.vExpand) {
                [view setBackgroundColor:self.tagColor];
            } else {
                [view setBackgroundColor:[self.tagColor colorWithAlphaComponent:.5]];
            }

        }
    }
}
-(void)clearTags {
    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [self addSubview:self.btnToggleVisibility];
    [self addSubview:self.vExpand];
}

//EXPAND/COLLAPSE UTILITY
-(NSArray*)getNthRow:(int)nth {//starts at 1 //not zero based
    NSMutableArray *rowViews = [[NSMutableArray alloc] initWithCapacity:self.subviews.count];

    CGFloat rowOrigin = [@" " sizeWithFont:self.tagFont].height * (nth - 1) + (nth - 1);
    for(UIView *view in self.subviews) {
        if([view isEqual:self.btnToggleVisibility] || [view isEqual:self.vExpand]) {//ignore the button and expand view
            continue;
        }

        if(view.frame.origin.y == rowOrigin) {
            [rowViews addObject:view];
        }
    }

    return rowViews;
}
-(UIView*)getGreatestXOriginViewForNthRow:(int)nthRow {
    NSArray *rowViews = [self getNthRow:nthRow];
    UIView *greatestXOriginView = nil;

    for(UIView *view in rowViews) {
        if(greatestXOriginView == nil || view.frame.origin.x > greatestXOriginView.frame.origin.x ) {
            greatestXOriginView = view;
        }
    }
    return greatestXOriginView;
}
-(void)modifyViewsForCollapsing {
    if([self getNthRow:3].count == 0) {
        return;
    }
    UIView *greatestXOriginView = [self getGreatestXOriginViewForNthRow:2];

    //update the label and the container
    [self.lblExpand setText:[NSString stringWithFormat:@"+%d", self.dataTags.count - greatestXOriginView.tag]];
    [self.lblExpand setFont:self.tagFont];
    [self.lblExpand setFrame:[WAControlsUtility updateFrame:self.lblExpand.frame withX:nil y:nil width:[NSNumber numberWithFloat:[self.lblExpand.text sizeWithFont:self.tagFont].width] height:[NSNumber numberWithFloat:greatestXOriginView.frame.size.height]]];
    [self resizeLabelContainer];

    //figure out where to place the expand and how to size it and the last label on the row
    CGFloat viewXValue = (greatestXOriginView.frame.size.width + greatestXOriginView.frame.origin.x);
    CGFloat expandXValue = self.frame.size.width - self.vExpand.frame.size.width;
    CGFloat xOrigin;

    if(viewXValue < expandXValue - 1.0) {//will it all fit without modifying any existing views
        xOrigin = viewXValue + 1.0;
    } else {//shrink the last view 
        [greatestXOriginView setFrame:[WAControlsUtility updateFrame:greatestXOriginView.frame withX:nil y:nil width:[NSNumber numberWithFloat:expandXValue - 1 - greatestXOriginView.frame.origin.x] height:nil]];
        for(UIView *view in greatestXOriginView.subviews) {//shrink the label
            [view setFrame:[WAControlsUtility updateFrame:view.frame withX:nil y:nil width:[NSNumber numberWithFloat:greatestXOriginView.frame.size.width - 4.0] height:nil]];
        }

        if(greatestXOriginView.frame.size.width < 20.0) {
            [greatestXOriginView setAlpha:0.0];//hide the last view if it got shrank down a lot
        }
        xOrigin = expandXValue;
    }

    [self.vExpand setFrame:[WAControlsUtility updateFrame:self.vExpand.frame withX:[NSNumber numberWithFloat:xOrigin] y:[NSNumber numberWithFloat:greatestXOriginView.frame.origin.y] width:nil height:nil]];
    [self.vExpand setAlpha:1.0];
    [self resizeLabelContainer];
}

-(void)modifyViewsForExpanding {
    UIView *view = [self getGreatestXOriginViewForNthRow:2];
    UILabel *label;
    if(view != nil) {
        label = (UILabel*)view.subviews[0];
        CGSize labelSize = [label.text sizeWithFont:self.tagFont];
        [label setFrame:[WAControlsUtility updateFrame:label.frame withX:nil y:nil width:[NSNumber numberWithFloat:labelSize.width] height:nil]];
        [view setFrame:[WAControlsUtility updateFrame:view.frame withX:nil y:nil width:[NSNumber numberWithFloat:labelSize.width + 4] height:nil]];
        [view setAlpha:1.0];
    }

    //hide expand
    [self.vExpand setAlpha:0.0];
}
-(void)resizeLabelContainer {
    [self.vExpand setFrame:[WAControlsUtility updateFrame:self.vExpand.frame withX:nil y:nil width:[NSNumber numberWithFloat:self.lblExpand.frame.size.width + 4.0] height:[NSNumber numberWithFloat:self.lblExpand.frame.size.height]]];
}
@end
于 2013-04-02T17:26:16.560 回答
1

您可以尝试NSAttributedStringNSBackgroundColorAttributeName属性一起使用。我还没有尝试过。

于 2013-03-28T17:08:13.107 回答