最终效果图:
项目中多处用到SegmentedControl,系统自带控件在不同IOS系统中风格不一样。在code4app上找到一个PPFlatSegmentedControl能实现很不错的效果,但是由于用到了NSAttributedString等IOS6.0才支持的方法,不能兼容5.0。想了下其实实现带两个按钮的分栏控件还是很简单的,干脆自己写一个吧。
思路:
1.初始化时需要用户传入左右按钮的Title,以及控件frame。
2.界面实现上继承自UIView,重写drawRect方法:1.画整个控件背景;2.画选中按钮背景;3.画按钮Title。
3.加Tap手势,点击时判断点击位置,是位于左按钮还是右按钮来回调delegate中方法。
4.为了用户交互更好,希望在点击但还没有释放时,给选中按钮加一层半透明的遮罩。需要重写touchBegan、touchEnded和touchCancelled方法。
代码如下:
//
// FlatSegmentedControl.h
// TestDemo
//
// Created by differ on 14-4-25.
// Copyright (c) 2014年 xiayun. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef enum {
LeftButtonSelected = 0,
RightButtonSelected
} SelectedButtonSide;
@protocol FlatSegmentedControlDelegate <NSObject>
- (void)buttonPressed:(SelectedButtonSide)selectedSide;
@end
@interface FlatSegmentedControl : UIView
{
@private
NSString *_leftTitle;
NSString *_rightTitle;
SelectedButtonSide _selectedSide;
BOOL _isTouching;
SelectedButtonSide _touchingSide;
}
- (id)initWithFrame:(CGRect)frame leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle;
@property(nonatomic,assign) id<FlatSegmentedControlDelegate> delegate;
@end
//
// FlatSegmentedControl.m
// TestDemo
//
// Created by differ on 14-4-25.
// Copyright (c) 2014年 xiayun. All rights reserved.
//
#import "FlatSegmentedControl.h"
@implementation FlatSegmentedControl
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_selectedSide = LeftButtonSelected;
}
return self;
}
- (id)initWithFrame:(CGRect)frame leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_selectedSide = LeftButtonSelected;
_leftTitle = leftTitle;
_rightTitle = rightTitle;
// 加点击手势
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self addGestureRecognizer:tapGesture];
}
return self;
}
#pragma mark - actions
- (void)handleTap:(UITapGestureRecognizer *)tapGesture
{
CGPoint touchPoint = [tapGesture locationInView:self];
CGRect leftRect = CGRectMake(0, 0, self.frame.size.width/2, self.frame.size.height);
if (CGRectContainsPoint(leftRect, touchPoint)) {
// 按左按钮
_selectedSide = LeftButtonSelected;
[self setNeedsDisplay];
} else {
// 按右按钮
_selectedSide = RightButtonSelected;
[self setNeedsDisplay];
}
if ([self.delegate respondsToSelector:@selector(buttonPressed:)]) {
[self.delegate buttonPressed:_selectedSide];
}
}
#pragma mark - drawing
- (void)drawRect:(CGRect)rect
{
// 取当前画笔
CGContextClearRect(UIGraphicsGetCurrentContext(),rect);
CGContextRef context = UIGraphicsGetCurrentContext();
// 画背景
CGRect rectangle = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
CGContextAddRect(context, rectangle);
CGContextSetFillColorWithColor(context, COLOR(247, 247, 247).CGColor);
CGContextFillPath(context);
// 画圆角矩形
CGContextSetStrokeColorWithColor(context, COLOR(57, 151, 243).CGColor);
CGContextSetLineWidth(context, 1);
[self CGContextAddRoundRect:context rect:CGRectMake(1, 1, self.frame.size.width-2, self.frame.size.height-2) radius:5.0f];
// 填充选中按钮背景
if (_selectedSide == LeftButtonSelected) {
[self CGContextFillLeftHalfRoundRect:context rect:CGRectMake(1, 1, self.frame.size.width/2+1, self.frame.size.height-2) radius:5.0f isMask:NO];
} else {
[self CGContextFillRightHalfRoundRect:context rect:CGRectMake(self.frame.size.width/2-1, 1, self.frame.size.width/2+1, self.frame.size.height-2) radius:5.0f isMask:NO];
}
// 画触摸遮罩
if (_isTouching && _touchingSide != _selectedSide) {
if (_touchingSide == LeftButtonSelected) {
[self CGContextFillLeftHalfRoundRect:context rect:CGRectMake(1, 1, self.frame.size.width/2+1, self.frame.size.height-2) radius:5.0f isMask:YES];
} else {
[self CGContextFillRightHalfRoundRect:context rect:CGRectMake(self.frame.size.width/2-1, 1, self.frame.size.width/2+1, self.frame.size.height-2) radius:5.0f isMask:YES];
}
}
// 画左标题
if (_selectedSide == LeftButtonSelected) {
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
} else {
CGContextSetFillColorWithColor(context, COLOR(57, 151, 243).CGColor);
}
[_leftTitle drawInRect:CGRectMake(0, (self.frame.size.height-16)/2, self.frame.size.width/2, self.frame.size.height) withFont:[UIFont systemFontOfSize:14.0f] lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentCenter];
// 画右标题
if (_selectedSide == RightButtonSelected) {
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
} else {
CGContextSetFillColorWithColor(context, COLOR(57, 151, 243).CGColor);
}
[_rightTitle drawInRect:CGRectMake(self.frame.size.width/2, (self.frame.size.height-16)/2, self.frame.size.width/2, self.frame.size.height) withFont:[UIFont systemFontOfSize:14.0f] lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentCenter];
}
// 画圆角矩形
- (void) CGContextAddRoundRect:(CGContextRef)context rect:(CGRect)rect radius:(CGFloat)radius
{
float x1=rect.origin.x;
float y1=rect.origin.y;
float x2=x1+rect.size.width;
float y2=y1;
float x3=x2;
float y3=y1+rect.size.height;
float x4=x1;
float y4=y3;
CGContextMoveToPoint(context, x1, y1+radius);
CGContextAddArcToPoint(context, x1, y1, x1+radius, y1, radius);
CGContextAddArcToPoint(context, x2, y2, x2, y2+radius, radius);
CGContextAddArcToPoint(context, x3, y3, x3-radius, y3, radius);
CGContextAddArcToPoint(context, x4, y4, x4, y4-radius, radius);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathStroke);
}
// 填充左半边圆角矩形
- (void)CGContextFillLeftHalfRoundRect:(CGContextRef)context rect:(CGRect)rect radius:(CGFloat)radius isMask:(BOOL)isMask
{
float x1=rect.origin.x;
float y1=rect.origin.y;
float x2=x1+rect.size.width;
float y2=y1;
float x3=x2;
float y3=y1+rect.size.height;
float x4=x1;
float y4=y3;
CGContextMoveToPoint(context, x1, y1+radius);
CGContextAddArcToPoint(context, x1, y1, x1+radius, y1, radius);
CGContextAddLineToPoint(context, x2, y2);
CGContextAddLineToPoint(context, x3, y3);
CGContextAddArcToPoint(context, x4, y4, x4, y4-radius, radius);
CGContextClosePath(context);
if (isMask) {
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:57/255.0 green:151/255.0 blue:243/255.0 alpha:.5].CGColor);
} else {
CGContextSetFillColorWithColor(context, COLOR(57, 151, 243).CGColor);
}
CGContextFillPath(context);
}
// 填充右半边圆角矩形
- (void)CGContextFillRightHalfRoundRect:(CGContextRef)context rect:(CGRect)rect radius:(CGFloat)radius isMask:(BOOL)isMask
{
float x1=rect.origin.x;
float y1=rect.origin.y;
float x2=x1+rect.size.width;
float y2=y1;
float x3=x2;
float y3=y1+rect.size.height;
float x4=x1;
float y4=y3;
CGContextMoveToPoint(context, x1, y1);
CGContextAddArcToPoint(context, x2, y2, x2, y2+radius, radius);
CGContextAddArcToPoint(context, x3, y3, x3-radius, y3, radius);
CGContextAddLineToPoint(context, x4, y4);
CGContextClosePath(context);
if (isMask) {
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:57/255.0 green:151/255.0 blue:243/255.0 alpha:.1].CGColor);
} else {
CGContextSetFillColorWithColor(context, COLOR(57, 151, 243).CGColor);
}
CGContextFillPath(context);
}
#pragma mark - Touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
_isTouching = YES;
CGRect leftRect = CGRectMake(0, 0, self.frame.size.width/2, self.frame.size.height);
if (CGRectContainsPoint(leftRect, touchPoint)) {
// 按左按钮
_touchingSide = LeftButtonSelected;
} else {
// 按右按钮
_touchingSide = RightButtonSelected;
}
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
_isTouching = NO;
[self setNeedsDisplay];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
_isTouching = NO;
[self setNeedsDisplay];
}
@end
使用:
FlatSegmentedControl *view = [[FlatSegmentedControl alloc] initWithFrame:CGRectMake(30, 30, 170, 30) leftTitle:@"分组1" rightTitle:@"分组2"];
view.delegate = self;
因为在项目中都是显示在导航栏上,所以按钮背景,字体,字体颜色,选中背景,都直接写在代码中。如果要扩展到其他项目应用,最好把这些都抽出来做成属性。
总结,CoreGraphics绘图Api使用简单,功能强大。在某些需要性能优化的地方,如TableViewCell可以发挥奇效。