系统控件
苹果在iOS7很多系统界面中都使用了毛玻璃效果,增加了界面的美观性,具有该效果的控件有
- UINavigationBar
- UIToolBar
- UIToolbar
这些控件的毛玻璃效果是基于同一套高斯模糊算法,为了问题的简单化,下文只对UINavigationBar进行分析。
相信很多人遇到过如下的问题:
- navigationBar.translucent为NO时,无高斯模糊,生硬
- navigationBar.translucent为YES时,有高斯模糊,颜色会变浅
预计效果
实际效果
根本原因是系统所用的高斯模糊算法会对色值进行一个转化,从设置值到表现值的转化关系如下
y = (x - 102) / 0.6; // 设置值y的范围[0, 255]
y = (x - 0.4) / 0.6; // 设置值y的范围[0, 1.0]
这样导致表现值无法覆盖完整的色域
x = 0.6y + 102; // 表现值x均>=102
x = 0.6y + 0.4; // 表现值x均>=0.4
解决方案有两种
方案一:盖一个layer到navigationBar上,色彩叠加
方案二:盖一个layer到navigationBar上,直接显示
色彩叠加方案
layer1:navigationBar的设置值y1,表现值l1,满足l1 = 0.6y1 + 0.4
layer2:stickView的透明度a,表现值l2,设置值待求
叠加后色值: (1 - a) * l1 + a * l2 = (1 - a) * (0.6 * y1 + 0.4) + a * l2
所设即所得就是叠加后色值==y1,也就是 (1 - a) * (0.6 * y1 + 0.4) + a * l2 = y1
可推导出:l2 = 0.4 * y1 / a + 0. 6 * y1 + 0.4 - 0.4 / a
为了保证 l2 > 0
可推导出:a > (0.4 - 0.4 * y1) / (0.6 * y1 + 0.4)
相关代码
- (CGFloat)minOpacityForValue:(CGFloat)value
{
return (0.4 - 0.4 * value) / (0.6 * value + 0.4);
}
- (CGFloat)convertValue:(CGFloat)value withOpacity:(CGFloat)opacity
{
return 0.4 * value / opacity + 0.6 * value - 0.4 / opacity + 0.4;
}
直接显示方法
自定义控件
苹果在iOS8后新增了UIBlurEffect类和UIVisualEffectView类,可以更简单高效地实现毛玻璃效果。
UIImageView * imageView = [[UIImageView alloc] init];
UIBlurEffect * blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView * effectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
effectView.frame = imageView.bounds;
effectView.alpha = 0.5f;
[imageView addSubview:effectView];