摘要:自定义类似于系统UISegmentedControl的切换控件,带动画效果,封装比较完善。
效果图
项目地址
https://github.com/XaoflySho/XSSegmentedView
说明
/*
使用说明:
初始化:
可以在代码中通过alloc-init的方法初始化;
例如:
//初始化
self.segmentedView = [[XSSegmentedView alloc]initWithFrame:CGRectMake(0, 0, 200, 30)];
//设置标题
[self.segmentedView setTitles:@[@"消息",@"电话",@"视频",@"空间",@"圈子"]];
或者:
//初始化并设置标题
self.segmentedView = [[XSSegmentedView alloc]initWithFrame:CGRectMake(0, 0, 200, 44) titles:@[@"消息",@"电话",@"视频",@"空间",@"游戏"]];
或者在Xib(Storyboard)中拖拽View,设置继承自 XSSegmentedView 类。
在Xib(Storyboard)中可设置TintColor,改变主体颜色。
设置代理:
代码与Xib(Storyboard)均使用
self.segmentedView.delegate = self;
设置代理
代理方法:
提供
- (void)xsSegmentedView:(XSSegmentedView *)XSSegmentedView selectTitleInteger:(NSInteger)integer;
- (BOOL)xsSegmentedView:(XSSegmentedView *)XSSegmentedView didSelectTitleInteger:(NSInteger)integer;
代理方法,
具体功能见代码注释
*/
实现原理
核心原理
整个效果的核心就是,移动滑块,标题反色。
实现原理也非常简单,就是简单的实用视差效果来实现。
下面是分层图:
可以看见,每个按钮对应的区域是有两个除了颜色不同,其他完全相同的Label,顶部Label是加在中间遮盖层上的,遮盖层设置裁切。这样,在中间遮盖层移动的时候,对应的使顶层Label反方向移动相同的距离,就会使顶层Label与底层Label保持相对静止。这样,就会看到如效果图中滑块移动,标题反色的这样一个效果。
//获取手指滑动距离
CGPoint pt = [sender translationInView:self];
//获取遮盖层、顶部Label层中心
CGPoint shadeViewCenter = self.shadeView.center;
CGPoint topLabelViewCenter = self.topLabelView.center;
//遮盖层与手指滑动方向相同
shadeViewCenter.x += pt.x;
//顶部Label层与手指滑动方向相反
topLabelViewCenter.x -= pt.x;
//设置遮盖层、顶部Label层中心
self.shadeView.center = shadeViewCenter;
self.topLabelView.center = topLabelViewCenter;
其他原理
滑动结束后自动对齐
//判断手势是否结束
if (sender.state == UIGestureRecognizerStateEnded) {
//手势结束后,对滑块中心X坐标除单个Label宽度取整。
int select = shadeViewCenter.x / labelWidht;
//在动画中设置遮盖层与顶层LabelView的Frame。
[UIView animateWithDuration:0.3 animations:^{
self.shadeView.frame = CGRectMake(integer * labelWidht, 0, labelWidht, labelHeight);
self.topLabelView.frame = CGRectMake(- integer * labelWidht, 0, self.frame.size.width, self.frame.size.height);
}];
}
左右回弹效果
//左侧边界判断
if (shadeViewCenter.x < 0)
{
shadeViewCenter.x = 0 ;
topLabelViewCenter.x = labelWidht / 2 + self.frame.size.width / 2;
}
//右侧边界判断
if (shadeViewCenter.x > self.frame.size.width - 1)
{
shadeViewCenter.x = self.frame.size.width - 1;
topLabelViewCenter.x = - self.frame.size.width / 2 + labelWidht / 2 + 1;
}
//然后在手势结束时,设置自动对齐。
最后再说几句
Segment虽然是控件中比较不起眼的一个控件,但是,一个优秀的APP应该从设计到体验,从细节到整体都应该是追求完美的,可能一个小的效果,并不会给一个APP增添很多特色,但是,一个小细节就可能会抓住用户!