剑客
关注科技互联网

卡牛-首页自定义壁纸功能实现思路及部分代码

卡牛信用卡管家项目简介:6000万卡族的共同选择!信用卡人士必备的手机应用。业内唯一通过 CFCA 国家级金融机构安全认证的信用卡管理应用。

进随手科技工作有一段日子了,卡牛 App 作为一个信用卡业界领跑的 App 居然没有自定义壁纸的功能……(可能现在你看到的版本依然没有这个功能,笔者在写这篇文章的时候 feature 刚做好还没有发版本)也是让人有些摸不着头脑。

后面了解到其实之前是有做这个功能的,后面因为不好看给去掉了(一会儿上图告诉大家为啥不好看),如果做好看的话实现起来有几个难点。

自定义壁纸难点

先 po 个图出来看图说话:

卡牛-首页自定义壁纸功能实现思路及部分代码

如图是卡牛 App 的首页,上面的天鹅是壁纸,壁纸下面是卡片信息,图中红色笔框出的区域是一些按钮和推广以及办卡业务入口。上面说如果用户自定义壁纸的话会很丑,比如把上面的天鹅壁纸换成一张色调不同的壁纸,下面的卡片区域背景色依然是这种暖色会非常突兀而且如果用户自定义的壁纸颜色太浅会导致上面红框圈住的部分得不到凸显甚至看不到按钮,所以当时就把这个功能下架了……

解决问题

当时的解决方案是预留了 6 张壁纸并且为壁纸做了卡片背景色和上面红框圈住的主题色,切换壁纸的时候同时改变卡片背景色和相关入口的主题色。

不过这个解决方案放在现在的角度看自然是不过关的,一个有着一定用户规模的业内领跑级 App 连个自定义壁纸功能都不放出来?说出来跟闹着玩似得……于是我们要解决问题

解决问题思路

首先我们可以向之前的解决方案学习,用户切换壁纸的时候上传自己手机相册的图片或者随手拍照一张,怎么能很好的修改卡片背景色和上面相关入口的颜色呢?

首先,要获取用户自定义壁纸的主色调。

获取自定义壁纸主色

获取主色调的代码如下:

/**
* 根据图片获取图片的主色调
*
* @param image 要获取主色调的图片
*
* @return 所提供图片的主色
*/

+ (UIColor *)mostColor:(UIImage *)image {
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
int bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
#else
int bitmapInfo = kCGImageAlphaPremultipliedLast;
#endif

//第一步 先把图片缩小 加快计算速度. 但越小结果误差可能越大
CGSize thumbSize = CGSizeMake(20, 20);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
thumbSize.width,
thumbSize.height,
8,//bits per component
thumbSize.width*4,
colorSpace,
bitmapInfo);

CGRect drawRect = CGRectMake(0, 0, thumbSize.width, thumbSize.height);
CGContextDrawImage(context, drawRect, image.CGImage);
CGColorSpaceRelease(colorSpace);

//第二步 取每个点的像素值
unsigned char *data = CGBitmapContextGetData (context);

if (data == NULL) return nil;

NSCountedSet *cls = [NSCountedSet setWithCapacity:thumbSize.width * thumbSize.height];

for (int x = 0; x < thumbSize.width; ++x) {
for (int y = 0; y < thumbSize.height; ++y) {
int offset = 4 * (x * y);

int red = data[offset];
int green = data[offset + 1];
int blue = data[offset + 2];
int alpha = data[offset + 3];

NSArray *clr=@[@(red), @(green), @(blue), @(alpha)];
[cls addObject:clr];
}
}
CGContextRelease(context);

//第三步 找到出现次数最多的那个颜色
NSEnumerator *enumerator = [cls objectEnumerator];
NSArray *curColor = nil;

NSArray *MaxColor = nil;
NSUInteger MaxCount = 0;

while ((curColor = [enumerator nextObject]) != nil)
{
NSUInteger tmpCount = [cls countForObject:curColor];

if (tmpCount < MaxCount) continue;

MaxCount = tmpCount;
MaxColor = curColor;
}

return [UIColor colorWithRed:([MaxColor[0] intValue]/255.0f) green:([MaxColor[1] intValue]/255.0f) blue:([MaxColor[2] intValue]/255.0f) alpha:([MaxColor[3] intValue]/255.0f)];
}

Note:

这里面有一个坑:如果用户选择的图片特别大,这个函数调用时长难以把控,而用户需要立马看到自定义壁纸设置上去的效果,这时候不可以用异步处理(用户回到主页面看不到自己刚才设置的壁纸)出个提示让用户苦等显然是一个不成熟的解决思路,于是加入代码:

//第一步 先把图片缩小 加快计算速度. 但越小结果误差可能越大
CGSize thumbSize = CGSizeMake(20, 20);

是不是看着不错???

看着挺不错的解决了问题,却在解决之余挖出了第二个坑:压缩图片之后获取主色速度很快,但是获取主色可能与原始图片的主色有偏差(压缩程度越大偏差越大),我们是要把这个主色当做卡片背景色的如果偏差明显一样会使得壁纸与卡片衔接处突兀不自然。

所以我们要解决的第二个问题:自定义壁纸与卡片背景色的过渡

自定义壁纸与卡片背景色的过渡

这里用到了 CAGradientLayer
,代码就不贴了,上网一查应该有相关介绍,是 iOS 开发中用于做颜色过渡的图层。

Note:

这里 CAGradientLayer
用法有两处坑:

  • 过渡时设置两种颜色(在这两种颜色之间过渡)如果一个设置为 [UIColor clearColor].CGColor
    另一个是我们获取到的主色,那么过渡效果会很不自然
  • 卡牛 App 首页是可以下拉刷新的,由于 CALayer
    不能设置约束,如果动态计算的话会卡顿

第一个问题,解决方法是设置两个颜色均为我们获取到的主色,靠近壁纸的一端设置透明度为 0
就好了……

第二个问题,解决方法是自定义一个 UIView
如下:

+ (Class)layerClass {
return [CAGradientLayer class];
}

用这个 UIView
去替换之前的 CALayer
遮盖在壁纸与卡片背景色衔接处。

修改其他入口按钮颜色

最后一步就是处理之前图片中红框圈住的部分业务入口按钮的颜色,代码简单贴一部分:

// 如果背景色色值和 > 600 则返回深色 反之 浅色
CGFloat red = 0;
CGFloat green = 0;
CGFloat blue = 0;
if ([[self customBackgroundColor] getRed:&red green:&green blue:&blue alpha:nil]) {
if ((red + green + blue) * 255 > 600) {
return [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6];
}else {
return [UIColor colorWithRed:1 green:1 blue:1 alpha:0.7];
}
}else {
return [UIColor colorWithHex:0xaa8146];
}

我们这里的解决方式是获取主色色值,计算色值和如果大于阈值(这里是600)则认为主色为浅色,返回一个透明的黑色。反之,主色为深色,则返回一个透明的白色,很简单的处理方式。

笔者认为这里也可以用取反色等等方式来做,只要能使按钮颜色与主色相差大,能够凸显出按钮来就好。

解决成果

卡牛-首页自定义壁纸功能实现思路及部分代码
卡牛-首页自定义壁纸功能实现思路及部分代码
卡牛-首页自定义壁纸功能实现思路及部分代码
卡牛-首页自定义壁纸功能实现思路及部分代码

Note:

这里壁纸上面的入口并没有按照上面说的那样识别深浅色返回黑白透明色,而是默认白色(PM 的意思)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址