在看 kittenyang:在iOS中实现Smartisan OS中首页的PageControll效果视错觉:从一个看似简单的自定义控件说起 这两篇文章感觉可以更好的实现实现 Smartisan OS 中首页的 PageControl 效果。

锤子的效果:

首先kittenyang实现的,当亮点划过两个暗点的中间是还是显示的

再看视错觉文章里的效果:

最终实现的效果:


实现原理

首先从效果看锤子的亮点,像是从孔的下方移动。所以给人感觉是上面挖了一排孔,亮点在地道移动所以两个空中间的地方看不到移动的亮点。所以不能直接使用一个 view 移动来解决。

恰巧看到另一篇文章,想到也许可以试试。

原理就是:使用mask隐藏和利用相对移动产生时差。

实现步骤:

1.在自定义的 LHPageControlview 上创建几个未选中状态颜色的圆darkCircle。

2.在自定义的 LHPageControlview 上创建一个圆大小的但透明的_hightLightView,它的作用就是利用 mask 属性将它子视图中超出 _hightLightView 显示区域的其他高亮的几个圆藏起来。

3._hightLightView 上添加 _topHidenHightLightCircles 视图,然后在 _topHidenHightLightCircles 上面添加相应数量的选中状态的圆lightCircle,注意他们的位置相对于 LHPageControlview 上的 darkCircle要一一对应。

整个控件结构如下图:

移动的时候,移动 _hightLightView 的同时 _topHidenHightLightCircles 往相反方向移动同样距离,这样在视觉上就好像 _topHidenHightLightCircles 是静止的,看上去只是 _hightLightView 在移动。

这样当 _hightLightView 移动到选中状态的圆 lightCircle 时,相应的未选中状态的 darkCircle 上就像有高亮的圆 lightCircle 移动过来遮住并显示。

移动时如图:

移动的关键代码:

//---计算两个圆圈间移动的范围 ( 0 ~ 1 )
CGFloat scale = distance - (int)distance;
if (scale == 0 && distance>=1) {
    scale = 1;
}
//移动距离
CGFloat moveDistance = distance*(kPageHeight+5);
//设置房射变换
CGAffineTransform transform = CGAffineTransformIdentity;

//------_hightLightView
//设置移动距离
transform = CGAffineTransformTranslate(transform, moveDistance, 0);

//---移动的范围 ( 0 ~ 0.2 )之间,缩小可视大小
if (scale >= 0 && scale <= 0.2) {
    transform = CGAffineTransformScale(transform, 1.0-scale, 1.0-scale);
}
//---移动的范围 ( 0.2 ~ 0.8 )之间,缩小可视大小固定为0.8
if (scale > 0.2 && scale < 0.8) {
    transform = CGAffineTransformScale(transform, 0.8, 0.8);
}
//---移动的范围 ( 0.8 ~ .0 )之间,缩小可视大小
if (scale > 0.8 && scale <= 1) {
    transform = CGAffineTransformScale(transform, scale, scale);
}

//---应用变换到layer
_hightLightView.layer.affineTransform = transform;


//------_topHidenHightLightCircles
//---重置变换,应用到 _topHidenHightLightCircles
transform = CGAffineTransformIdentity;
//---设置移动距离与 _hightLightView 往相反方向移动相应距离。造成错觉
transform = CGAffineTransformTranslate(transform, -moveDistance, 0);
//---应用变换到layer
_topHidenHightLightCircles.layer.affineTransform = transform;

这样就实现了基本效果。

我在中间为了实现缩小效果,使用实时改变 _hightLightView layer的cornerRadius 大小。如果慢慢拖动会发现中间是有些问题的。(希望指教有什么好的方法=。=谢过)

解决
还是得自己解决。=。=。最近看到 CGAffineTransform 这个类,可以直接根据自己的中心点来进行缩放和移动。省去了再去计算在父view的坐标去移动。

Github代码:传送门