//下一个标签宽度,iOS和Android的图样色调提取算

2019-09-19 22:07栏目:大奖888官网登录
TAG:

在发现百日大战时景项目中。有一个创新玩法,就是通过筛选图片主色调来显示如红色系,蓝色系照片。这就涉及到了图片主色调的提取。技术选型为客户端进行图片颜色提取,上传到服务端。但是由于项目时间限制,iOS和Android的图片色调提取算法不一样。Android采用的是Google官方推出的Palette算法,为了统一,在这一期我去研究了一下Palette算法,并将它OC化。最终将作为一个两端统一的技术方案,提供SDK到海纳平台上。

//

废话不多说 直接上头文件 自己去Git下载吧 Git Link, press here to download

Palette算法是Android Lillipop中新增的特性。它可以从一张图中提取主要颜色,然后把提取的颜色融入的App的UI之中。现在在很多设计出彩的泛前端展示届非常普遍,如知乎等。大致效果如下:

//  PHTagViewFrame.m

先看一下JSON 格式<pre><code>[{"width": 200,"height": 100,"url": "": "img"},{"color": "blue","content": "this is first part and you can set your txt here. remember set default config","size": 30,"type": "txt"},{"color": "orange","content": "this is second part","size": 14,"type": "txt"},{"width": 100,"height": 200,"url": "": "img"},{"color": "red","content": "this is third part","size": 20,"type": "txt"},{"color": "blue","content": "press here to jump","size": 40,"url": "": "link"}]</code></pre>

www.88pt88.com 1

//  标签的使用二

然后看一下使用方法<pre><code>XDisplayView * showView = [[XDisplayView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth([UIScreen mainScreen].bounds), 100)];

可以看出来Android在Material Design上下了一番功夫。在很多Android官方的demo里,各种炫酷效果层出不穷。那我们就顺势站在巨人的肩膀上,将他人拿手之处,为我所用!

//

XViewHandle * config = [[XViewHandle alloc] init];config.width = showView.width;NSString * path = [[NSBundle mainBundle] pathForResource:@"content" ofType:@"json"];XCoreTextData * data = [XFrameParser parseTemplateFile:path config:config];showView.data = data;showView.height = data.height;showView.backgroundColor = [UIColor whiteColor];[self.view addSubview:showView];

相比于很多传统的图片提取算法,Palette的特点是不单单是去筛选中出现颜色最多的。而是从使用角度出发,通过六种模式,如活力色彩,柔和色彩等,筛选出更符合人眼筛选视觉焦点的颜色。如夜晚中的霓虹灯,白色背景的产品照。同时,也可以自定义筛选模式,输入自己的筛选规则,得到目标颜色。下面将逐步分析一下每个步骤。

//  Created by 123 on 16/9/6.

</code></pre>

unsignedintpixelCount;

//  Copyright © 2016年 彭洪. All rights reserved.

然后看一下实现的头文件<pre><code>//// XViewHandle.h// XCoreText//// Created by Dylan on 15/1/17.// Copyright 2015年 Dylan. All rights reserved.//

unsignedcharrawData = [self rawPixelDataFromImage:_image pixelCount:&pixelCount];*

//

/*!

if{

 

  • @brief 这里是DebugLog 大家都很常用吧 所以不啰嗦了*/

return;

/**

/*!

}

 *  计算多个标签的位置 标签根据文字自适应宽度 每行超过的宽度平均分配给每个标签 每个标签左右对齐

  • @brief 颜色的定义呦*/

NSIntegerred,green,blue;

 *

/*!

for (intpixelIndex =0; pixelIndex < pixelCount; pixelIndex++){

 *  @return

  • @brief 快速单例呦*/

red= (NSInteger)rawData[pixelIndex4+0];*

 */

green= (NSInteger)rawData[pixelIndex4+1];*

 

  • (__class *)sharedInstance;

blue= (NSInteger)rawData[pixelIndex4+2];*

#import "PHTagViewFrame.h"

red= [TRIPPaletteColorUtils modifyWordWidthWithValue:redcurrentWidth:8targetWidth:QUANTIZE_WORD_WIDTH];

#define padding10 10

  • (__class *)sharedInstance { static dispatch_once_t once; static __class * singleton; dispatch_once( &once, ^{ singleton = [[__class alloc] init]; } ); return singleton; }

green= [TRIPPaletteColorUtils modifyWordWidthWithValue:greencurrentWidth:8targetWidth:QUANTIZE_WORD_WIDTH];

@implementation PHTagViewFrame

/*!

blue= [TRIPPaletteColorUtils modifyWordWidthWithValue:bluecurrentWidth:8targetWidth:QUANTIZE_WORD_WIDTH];

  • (id)init {
  • @brief 主线程呦*/

NSInteger quantizedColor =red<<2QUANTIZE_WORD_WIDTH |green<< QUANTIZE_WORD_WIDTH |blue; hist [quantizedColor] ++;*

    self = [super init];

if ([NSThread isMainThread]) {block();} else {dispatch_async(dispatch_get_main_queue;}

}

    if (self) {

/*!

Palette算法为了减少运算量,加快运算速度。一共做了两个事情,第一是将图片压缩。第二个是将RGB888颜色空间的颜色转变成RGB555颜色空间,这样就会使整个直方图数组以及颜色数组长度大大减小,又不会太影响计算结果。

        _tagsFrames = [[NSMutableArray alloc] init];

  • @brief Frame ParserConfig Attributes*/@interface XViewHandle : NSObject

颜色直方图的概念可以想象成一个颜色柱状分布图,某一柱越高,这柱代表的颜色在图片中也就越多。它本质上是一个int类型的一维数组。

        _tagsMinPadding = padding10;

X_SINGLETON_DEC(XViewHandle)

NSInteger distinctColorCount =0;

        _tagsMargin = padding10;

/*!

NSIntegerlength= sizeof/sizeof;

        _tagsLineSpaceing = padding10;

  • @brief 一些基本的配置属性 Model*/@property (assign, nonatomic) CGFloat width;@property (assign, nonatomic) CGFloat fontSize;@property (assign, nonatomic) CGFloat lineSpace;@property (strong, nonatomic) UIColor * textColor;

for (NSIntegercolor=0;color < length;color++){

    }

/*!

if(hist[color] >0&& [self shouldIgnoreColor:color]){

    return self;

  • @brief 两个关于颜色的类方法 根据名称得到颜色 根据JSON得到颜色*/

hist[color] =0;

}

}

 

  • (UIColor *)colorWithName: (NSString *)string;

if (hist[color] >0){

  • (void)setTagsArray:(NSArray *)tagsArray {

// JSON: [12, 22, 33]

distinctColorCount ++;

    _tagsArray = tagsArray;

  • (UIColor *)colorWithRGBArray: (NSArray *)array;

}

    

@end

}

    CGFloat btnX = _tagsMargin;

/*!

NSInteger distinctColorIndex =0;

    CGFloat btnW = 0;

  • @brief UIView ex*/@interface UIView (frameHandle)

_distinctColors = [[NSMutableArray alloc]init];

    CGFloat nextWidth = 0;//下一个标签宽度

/*!

for(NSIntegercolor=0;color0;color < length;color++){

    CGFloat moreWidth = 0;//每一行多出来的宽度

  • @brief 关于UIView的一些扩展喽 很方便的 开发中也可以使用呦*/

if (hist[color] > 0){

    //每一行的最后一个tag的索引数组和每一行多出来的宽度的数组

[_distinctColors addObject: [NSNumber numberWithInt:color]];

    NSMutableArray *lastIndexs = [[NSMutableArray alloc] init];

  • x;

  • y;

  • width;

  • height;

  • setX: x;

  • setY: y;

  • setWidth: width;

  • setHeight: height;

distinctColorIndex++;

    NSMutableArray *moreWidths = [[NSMutableArray alloc] init];

@end

}

    

/*!

}

    for (int i=0; i<tagsArray.count; i++) {

  • @brief Build CTFrameRef.*/@class XCoreTextData;

将不同的颜色存进distinctColors,留在后面进行判断。

        btnW = [self sizeWithText:tagsArray[i] font:TagTitleFont].width + _tagsMinPadding *2;

static NSMutableAttributedString * result;

最大颜色数在设计上可以设计为接收入参,满足不同使用者的需要,默认值为16。这个值不宜过大,因为如果过大的话,图片颜色会分的很散,图片颜色比较分散的时候,得出来的颜色可能会偏向某一小部分颜色,而不是从整体上来综合判断。而当图片筛选出来的颜色种类小于MaxColorNum的时候,整个流程会简单很多。

        if (i <tagsArray.count-1) {

@interface XFrameParser : NSObject

for(NSInteger i =0;i < distinctColorCount ; i++){

            nextWidth = [self sizeWithText:tagsArray[i+1] font:TagTitleFont].width + _tagsMinPadding*2;

/*!

NSIntegercolor= [_distinctColors[i] integerValue];

        }

  • @brief 解析的内容 仅限文字内容的多样化
    • @param content 内容
  • @param config 配置 就是上边说的基本配置嘿嘿
    • @return 返回这个东西喽 一个TextData模型*/

NSInteger population = hist[color];

        CGFloat nextBtnX = btnX+btnW + _tagsMargin;

NSIntegerred= [TRIPPaletteColorUtils quantizedRed:color];

        //如果下一个按钮 标签最右边则换行

  • www.88pt88.com,(XCoreTextData *)parseContent: (NSString *)content config: (XViewHandle *)config;

NSIntegergreen= [TRIPPaletteColorUtils quantizedGreen:color];

        if ((nextBtnX

/*!

NSIntegerblue= [TRIPPaletteColorUtils quantizedBlue:color];

  • nextWidth)>(SCREEN_W-_tagsMargin)) {
  • @brief 解析AttributeString喽、
    • @param content 内容 就是一个AttributeString
  • @param config 配置
    • @return 返回TextData模型*/

red= [TRIPPaletteColorUtils modifyWordWidthWithValue:redcurrentWidth:QUANTIZE_WORD_WIDTH targetWidth:8];

            //计算超过的宽度

green= [TRIPPaletteColorUtils modifyWordWidthWithValue:greencurrentWidth:QUANTIZE_WORD_WIDTH targetWidth:8];

            moreWidth = SCREEN_W - nextBtnX;

  • (XCoreTextData *)parseAttributesContent: (NSMutableAttributedString *)content config: (XViewHandle *)config;

blue= [TRIPPaletteColorUtils modifyWordWidthWithValue:bluecurrentWidth:QUANTIZE_WORD_WIDTH targetWidth:8];color=red<<2*8|green<<8|blue;

            [lastIndexs addObject:[NSNumber numberWithInteger:i]];

/*!

TRIPPaletteSwatch *swatch = [[TRIPPaletteSwatch alloc]initWithColorInt:colorpopulation:population];

            [moreWidths addObject:[NSNumber numberWithFloat:moreWidth]];

  • @brief 这个是最重要的方法 解析JSON文件
    • @param filePath JSON文件的路径 也可以自己去更改方法 改为JSON内容 都是可以的呦
  • @param config 这里的配置就用来配置一下width 别的属性的值 你当然写到JSON文档中了、 JSON格式可以参考下边的content.JSON 文件呦
    • @return 返回TextData这个玩意*/

[swatchs addObject:swatch]; }

            

这里引出了一个新的概念,叫Swatch。Swatch是最终被作为参考进行模式筛选的数据结构,它有两个最主要的属性,一个是Color,这个Color是最终要被展示出来的Color,所以需要的是RGB888空间的颜色。另外一个是Population,它来自于hist直方图。是作为之后进行模式筛选的时候一个重要的权重因素。但是如果颜色个数超出了最大颜色数,则需要进行第3步。

            btnX = _tagsMargin;

  • (XCoreTextData *)parseTemplateFile: (NSString *)filePath config: (XViewHandle *)config;

_priorityArray = [[TRIPPaletteVBoxArray alloc]init];

        }

@end

_colorVBox = [[VBox alloc]initWithLowerIndex:@upperIndex:distinctColorIndexcolorArray:_distinctColors]; [_priorityArrayaddVBox:_colorVBox];

        else {

/*!

// split the VBox

            btnX += (btnW + _tagsMargin);

  • @brief Save CTFrameRef and Frame.*/@interface XCoreTextData : NSObject

[selfsplitBoxes:_priorityArray];

        }

/*!

//Switch VBox to Swatch

        //如果是最后一个且数组中没有 则加入数组中

  • @brief 其实绘制 就是要ctFrame*/@property (assign, nonatomic) CTFrameRef ctFrame;@property (assign, nonatomic) CGFloat height;

self.swatchArray = [selfgenerateAverageColors:_priorityArray];

        if (i == tagsArray.count - 1) {

// 包含的图片数组@property (strong, nonatomic) NSMutableArray * imageArray;

VBox是一个新的概念,它理解起来稍微抽象一点。可以这样来理解,我们拥有的颜色过多,但是我们只需要提取出例如16种颜色,需要需要用16个“筐”把颜色相近的颜色筐在一起,最终用每个筐的平均颜色来代表提取出来的16种主色调。它的属性如下:

            if (![lastIndexs containsObject:[NSNumber numberWithInt:i]]) {

// 包含的链接数组@property (strong, nonatomic) NSMutableArray * linkArray;

@interfaceVBox:NSObject

                [lastIndexs addObject:[NSNumber numberWithInt:i]];

@end

@property(nonatomic,assign)NSIntegerlowerIndex;

                [moreWidths addObject:[NSNumber numberWithFloat:0]];

/*!

@property(nonatomic,assign)NSIntegerupperIndex;

            }

  • @brief imageDataModel*/@interface XCoreImageData : NSObject

@property(nonatomic,strong)NSMutableArray*distinctColors;

        }

// 这是image的模型呦、@property (strong, nonatomic) NSString * url;@property (assign, nonatomic) CGFloat position;@property (assign, nonatomic) CGRect imagePosition;

@property(nonatomic,assign)NSIntegerpopulation;

    }

@end

@property(nonatomic,assign)NSIntegerminRed;

    NSInteger location = 0;//截取的位置

/*!

@property(nonatomic,assign)NSIntegermaxRed;

    NSInteger length = 0;//截取的长度

  • @brief linkDataModel*/@interface XCoreLinkData : NSObject

@property(nonatomic,assign)NSIntegerminGreen;

    CGFloat averageW = 0;//多出来的平均宽度

// 这是链接的模型@property (strong, nonatomic) NSString * title;@property (strong, nonatomic) NSString * url;@property (assign, nonatomic) NSRange range;

@property(nonatomic,assign)NSIntegermaxGreen;

    

@end

@property(nonatomic,assign)NSIntegerminBlue;

    CGFloat tagW = 0;

@interface XTouch : NSObject

@property(nonatomic,assign)NSIntegermaxBlue;

    CGFloat tagH = 30;

// 这是检测连接点击的方法 直接在tap手势的回掉方法里边 调用这个类方法就可以了。

@end

    

  • (XCoreLinkData *)touchLinkInView: view atPoint: point data: (XCoreTextData *)data;

其中lowerIndex和upperIndex指的是在所有的颜色数组distinctColors中,VBox所持有的颜色范围。Population代表的是这个颜色范围中,一共有多少个像素点。其它的则代表R,G,B值各自的最大最小值。

    for (int i=0; i<lastIndexs.count; i++) {

@end

它决定了该VBox的Volume。范围越大,Volume越大,当分裂VBox的时候,总是分裂当前队列中VBox里Volume最大的那个。

        NSInteger lastIndex = [lastIndexs[i]integerValue];

/*! JSON Format Example[{"color": "blue", // or you can change this with Array contains R G B"content": "With More Text", // content"size": 16 // font size"type": "txt" // type mains your content.},{"width": 12., // image size"height": 12.,"url": "image url", // image url"type": "img"},{"color": "blue", // link color"content": "Press Here", // link tip"url": "" // href"type": "link"}]*/</code></pre>

- splitBoxes:(TRIPPaletteVBoxArray*)queue{

        if (i == 0) {

注释很明确、 h文件中文注释 m文件英文注释、 懒得切输入法、 祝大家观影愉快。 - - - Dylan.

//queue is a priority queue.

            length = lastIndex + 1;

while(queue.count < maxColorNum) {

        }

VBox *vbox = [queueobjectAtIndex:0];

        else {

if (vbox != nil && [vbox canSplit]) {

            length = [lastIndexs[i]integerValue]-[lastIndexs[i-1]integerValue];

// First split the box, and offer the result

        }

[queueaddVBox:[vbox splitBox]];

        //从数组中截取每一行的数组

// Then offer the box back

        NSArray *newArr = [tagsArray subarrayWithRange:NSMakeRange(location, length)];

[queueaddVBox:vbox];

        location = lastIndex +1;

}else{

        

NSLog(@"All boxes split");

        averageW = [moreWidths[i]floatValue]/newArr.count;

return;

        CGFloat tagX = _tagsMargin;

}

        CGFloat tagY = _tagsLineSpaceing + (_tagsLineSpaceing + tagH)*i;

}

        

}

        for (int j=0; j<newArr.count; j++) {

VBox的分裂规则是像素中点分裂,从lowerIndex递增到upperIndex,如果某一个点让整个像素个数累加起来大于了VBox像素个数的一半,则这个点就是splitPoint。而优先队列的排序规则是,队首永远是Volume最大的VBox,从大概率上来讲,这总是代表像素个数最多的VBox。当VBox个数大于最大颜色个数的时候,则return,获得优先队列中每个VBox的平均颜色。并生成平均颜色,之后将每个VBox转换成了一个一个的Swatch。

            tagW = [self sizeWithText:newArr[j] font:TagTitleFont].width + _tagsMinPadding *2 + averageW;

在Palette算法里,“模式”对应的数据结构是target。它对颜色的识别和筛选不是使用的RGB色彩空间,而采用的是HSL颜色模型。它的主要属性如下:

            CGRect btnF = CGRectMake(tagX, tagY, tagW, tagH);

@interfaceTRIPPaletteTarget()

            [_tagsFrames addObject:NSStringFromCGRect(btnF)];

@property(nonatomic,strong)NSMutableArray*saturationTargets;

            

@property(nonatomic,strong)NSMutableArray*lightnessTargets;

            tagX += (tagW + _tagsMargin);

@property(nonatomic,strong)NSMutableArray* weights;

        }

@property(nonatomic,assign)BOOLisExclusive;// default to true

    }

@property(nonatomic,assign) PaletteTargetMode mode;

    _tagsHeight = (tagH + _tagsLineSpaceing) * lastIndexs.count + _tagsLineSpaceing;

@end

}

Target主要保存了饱和度和明度以及权重的数组。数组里保存了最小值,最大值,和目标值。这些参数都是后面用来给HSL颜色值评分用的。这些值是经过Google的团队进行调优之后,筛选出来的值。可以说是整套算法中最有价值的参数。

 

- (TRIPPaletteSwatch*)getMaxScoredSwatchForTarget:(TRIPPaletteTarget*)target{

/**

CGFloat maxScore =0;

 *  单行文本数据获取宽高

TRIPPaletteSwatch *maxScoreSwatch = nil;

 */

for (NSInteger i =0; i<_swatchArray.count; i++){

  • (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font {

TRIPPaletteSwatch *swatch= [_swatchArray objectAtIndex:i];

    NSDictionary *attrs = @{NSFontAttributeName:font};

if ([selfshouldBeScoredForTarget:swatchtarget:target]){

    return [text sizeWithAttributes:attrs];

CGFloatscore= [self generateScoreForTarget:targetswatch:swatch];

}

if (maxScore ==0||score> maxScore){

@end

maxScoreSwatch =swatch;

 

maxScore =score;

//

}

//  PHTagViewFrame.h

}

//  标签的使用二

}

//

return maxScoreSwatch;

//  Created by 123 on 16/9/6.

}

//  Copyright © 2016年 彭洪. All rights reserved.

通过这些已经经过调优的参数,可以得出每一项的得分:饱和度得分,明度得分,像素Population得分,将三项得分加起来,可以得到该Target评估得分最高的Swatch,也就是我们最终要提取的对应颜色值。分值具体的具体方法如下:

//

- generateScoreForTarget:(TRIPPaletteTarget*)targetswatch:(TRIPPaletteSwatch*)swatch{

 

NSArray *hsl = [swatch getHsl];

#import <Foundation/Foundation.h>

floatsaturationScore =0;

#import <UIKit/UIKit.h>

floatluminanceScore =0;

 

floatpopulationScore =0;

#define SCREEN_W    [UIScreen mainScreen].bounds.size.width

if([targetgetSaturationWeight] >0) {

#define SCREEN_H    [UIScreen mainScreen].bounds.size.height

saturationScore = [targetgetSaturationWeight]

#define TagTitleFont [UIFont systemFontOfSize:13]

* (1.0f - fabsf([hsl[1] floatValue] - [targetgetTargetSaturation]));

 

}

@interface PHTagViewFrame : NSObject

if([targetgetLumaWeight] >0) {

 

luminanceScore = [targetgetLumaWeight]

/**

* (1.0f - fabsf([hsl[2] floatValue] - [targetgetTargetLuma]));

 *  标签名字数组

}

 */

if([targetgetPopulationWeight] >0) {

@property (nonatomic,strong) NSArray *tagsArray;

populationScore = [targetgetPopulationWeight]

/**

* ([swatch getPopulation] / _maxPopulation);

 *  标签frame数组

}

 */

returnsaturationScore + luminanceScore + populationScore;

@property (nonatomic,strong) NSMutableArray *tagsFrames;

}

/**

www.88pt88.com 2

 *  标签高度

图上红框部分即是筛选出来的主题色。

 */

该算法已经运用在了飞猪发现广场的时景项目中(Android版本)。下一期,iOS端也会切换成这种提取算法。并且将这套算法沉淀在基础线,只需要使用UIImage+Palette的接口即可调用。考虑到它的使用场景,会尽快沉淀为SDK,供集团内其它App使用。

@property (nonatomic,assign) CGFloat tagsHeight;

/**

 *  标签间距

 */

@property (nonatomic,assign) CGFloat tagsMargin;

/**

 *  标签行间距

 */

@property (nonatomic,assign) CGFloat tagsLineSpaceing;

/**

 *  标签最小内边距 

 */

@property (nonatomic,assign) CGFloat tagsMinPadding;

 

@end

 

 

 

//

//  PHTagView.h

//  标签的使用二

//

//  Created by 123 on 16/9/6.

//  Copyright © 2016年 彭洪. All rights reserved.

//

 

#import <UIKit/UIKit.h>

#import "PHTagViewFrame.h"

#define TextColor     [UIColor colorWithRed:51.0/255.0 green:51.0/255.0 blue:51.0/255.0 alpha:1.0]

#define UIColorRGBA(r,g,b,a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]

@class PHTagViewFrame;

@protocol TagViewDelegate <NSObject>

 

  • (void)tagView:(NSArray *)tagArray;

 

@end

 

@interface PHTagView : UIView

{

    //储存选中按钮的tag

    NSMutableArray *selectedBtnList;

}

@property (nonatomic,weak) id<TagViewDelegate>delegate;

 

/** 是否能选中 需要在frame钱调用 默认yes */

@property (nonatomic,assign) BOOL clickBool;

 

/** 未选中边框大小 需要在frame前调用 默认0.5 */

@property (nonatomic,assign) CGFloat borderSize;

 

/** frame */

@property (nonatomic,strong) PHTagViewFrame *tagsFrame;

 

/** 选中背景颜色 默认白色 */

@property (nonatomic,strong) UIColor *clickBackgroundColor;

 

/** 选中字体颜色 默认 */

@property (nonatomic,strong) UIColor *clickTitleColor;

 

/** 多选选中 默认未选中 */

@property (nonatomic,strong) NSArray *clickArray;

 

/** 单选选中 默认未选中 */

@property (nonatomic,strong) NSString *clickString;

 

/** 选中边框大小 默认0.5 */

@property (nonatomic,assign) CGFloat clickBorderSize;

 

/** 1-多选 0-单选 默认单选 */

@property (nonatomic,assign) NSInteger clickStart;

@end

 

 

//

//  PHTagView.m

//  标签的使用二

//

//  Created by 123 on 16/9/6.

//  Copyright © 2016年 彭洪. All rights reserved.

//

 

#import "PHTagView.h"

 

@implementation PHTagView

  • (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];

    if (self) {

        selectedBtnList = [[NSMutableArray alloc] init];

        self.clickBackgroundColor = [UIColor whiteColor];

        self.clickTitleColor = TextColor;

        self.clickArray = nil;

        self.clickBool = YES;

        self.borderSize = 0.5;

        self.clickBorderSize = 0.5;

    }

    return self;

}

 

  • (void)setTagsFrame:(PHTagViewFrame *)tagsFrame {

    _tagsFrame = tagsFrame;

    for (NSInteger i=0; i<tagsFrame.tagsArray.count; i++) {

        UIButton *tagsBtn = [UIButton buttonWithType:UIButtonTypeCustom];

        [tagsBtn setTitle:tagsFrame.tagsArray[i] forState:UIControlStateNormal];

        [tagsBtn setTitleColor:TextColor forState:UIControlStateNormal];

        tagsBtn.titleLabel.font = TagTitleFont;

        tagsBtn.tag = i;

        tagsBtn.backgroundColor = [UIColor whiteColor];

//        [self ma]

    }

}

 

#pragma mark 选中背景颜色

  • (void)setClickBackgroundColor:(UIColor *)clickBackgroundColor {

    if (_clickBackgroundColor != _clickBackgroundColor) {

        _clickBackgroundColor = clickBackgroundColor;

    }

}

 

#pragma mark 选中字体颜色 

  • (void)setClickTitleColor:(UIColor *)clickTitleColor {

    if (_clickTitleColor != clickTitleColor) {

        _clickTitleColor = clickTitleColor;

    }

}

 

#pragma mark 能否被选中 

  • (void)setClickBool:(BOOL)clickBool {

    _clickBool = clickBool;

}

 

#pragma mark 选中边框大小 

  • (void)setBorderSize:(CGFloat)borderSize {

    if (_borderSize != borderSize) {

        _borderSize = borderSize;

    }

}

 

#pragma mark 选中边框大小

  • (void)setClickBorderSize:(CGFloat)clickBorderSize {

    if (_clickBorderSize != clickBorderSize) {

        _clickBorderSize = clickBorderSize;

    }

}

 

#pragma mark 默认选择 单选

  • (void)setClickString:(NSString *)clickString {

    if (_clickString != clickString) {

        _clickString = clickString;

    }

    if ([_tagsFrame.tagsArray containsObject:_clickString]) {

        NSInteger index = [_tagsFrame.tagsArray indexOfObject:_clickString];

        [self clickString:index];

    }

}

 

#pragma mark 默认选则 多选

  • (void)setClickArray:(NSArray *)clickArray {

    if (_clickArray != clickArray) {

        _clickArray = clickArray;

    }

    

    for (NSString *string in clickArray) {

        if ([_tagsFrame.tagsArray containsObject:string]) {

            NSInteger index = [_tagsFrame.tagsArray indexOfObject:string];

            NSString *x = [[NSString alloc] initWithFormat:@"%ld",(long)index];

            [self clickArray:x];

        }

    }

}

 

#pragma mark 单选

  • (void)clickString:(NSInteger)index {

    UIButton *btn ;

    for (id obj in self.subviews) {

        if ([obj isKindOfClass:[UIButton class]]) {

            btn = (UIButton *)obj;

            if (btn.tag == index) {

                btn.backgroundColor = [UIColor whiteColor];

                [btn setTitleColor:_clickTitleColor forState:UIControlStateNormal];

                [self makeCorner:_clickBorderSize view:btn color:_clickTitleColor];

                [_delegate tagView:@[[NSString stringWithFormat:@"%ld",(long)index]]];

            }

            else {

                btn.backgroundColor = [UIColor whiteColor];

                [btn setTitleColor:TextColor forState:UIControlStateNormal];

                [self makeCorner:_borderSize view:btn color:UIColorRGBA(221, 221, 221, 1)];

            }

        }

    }

}

 

#pragma mark 多选

  • (void)clickArray:(NSString *)index {

    UIButton *btn;

    for (id obj in self.subviews) {

        if ([obj isKindOfClass:[UIButton class]]) {

            btn = (UIButton *)obj;

            if (btn.tag == [index integerValue]) {

                btn.backgroundColor = [UIColor whiteColor];

 

                if ([selectedBtnList containsObject:index]) {

 

                    [btn setTitleColor:TextColor forState:UIControlStateNormal];

                    [self makeCorner:_clickBorderSize view:btn color:_clickTitleColor];

                    [selectedBtnList addObject:index];

                }

                else {

 

                    [btn setTitleColor:_clickTitleColor forState:UIControlStateNormal];

                    [self makeCorner:_clickBorderSize view:btn color:_clickTitleColor];

                    [selectedBtnList addObject:index];

                }

                [_delegate tagView:selectedBtnList];

            }

        }

    }

}

 

//设置角标

  • (void)makeCorner:(CGFloat)corner view:(UIView *)view color:(UIColor *)color {

    CALayer *filesLayer = [view layer];

    filesLayer.borderColor = [color CGColor];

    filesLayer.borderWidth = corner;

}

 

  • (void)tagsBtn:(UIButton *)sender {

    

    if (self.clickStart == 0) {

        //单选

        [self clickString:sender.tag];

    }

    else {

        //多选

        NSString *x = [[NSString alloc] initWithFormat:@"%ld",(long)sender.tag];

        [self clickArray:x];

    }

    

}

@end

 

 

  • (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = UIColorRGBA(238, 238, 238, 1);

    

    NSArray *array = @[@"code4app",@"轻音少女",@"花季少女",@"我们仍未知道那天所看见的花的名字",@"华语",@"花有重开日",@"空之境界"];

    PHTagViewFrame *frame = [[PHTagViewFrame alloc] init];

    frame.tagsMinPadding = 4;

    frame.tagsMargin = 10;

    frame.tagsLineSpaceing = 10;

    frame.tagsArray = array;

    

    PHTagView *tagView = [[PHTagView alloc] initWithFrame:CGRectMake(0, 30, SCREEN_W, frame.tagsHeight)];

    tagView.clickBool = YES;

    tagView.borderSize = 0.5;

    tagView.clickBorderSize = 0.5;

    tagView.tagsFrame = frame;

    tagView.clickBackgroundColor = BACKGROUNDCOLOR;

    tagView.clickTitleColor = BACKGROUNDCOLOR;

    tagView.clickStart = 0;

    tagView.clickString = @"华语";//单选  tagView.clickStart 为0

    //    tagView.clickArray = @[@"误解向",@"我们仍未知道那天所看见的花的名字"];//多选 tagView.clickStart 为1

    tagView.delegate = self;

    [self.view addSubview:tagView];

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文由大奖888-www.88pt88.com-大奖888官网登录发布于大奖888官网登录,转载请注明出处://下一个标签宽度,iOS和Android的图样色调提取算