QQ消息提示移除粘性效果
几何原理
创建一个继承UIButton的自定义Button
#import "StickyButton.h"
@interface StickyButton()
@property (strong, nonatomic)UIView *smallCircle;
@property (strong, nonatomic)CAShapeLayer *shapeLayer;
@end
@implementation StickyButton
- (void)awakeFromNib
{
[super awakeFromNib];
[self config];
}
- (void)config
{
//设置背景颜色,设置layer的cornerRadius属性,添加手势,重写setHighlighted方法,屏蔽按钮的高亮状态
[self.layer setMasksToBounds:YES];
[self.layer setCornerRadius:self.bounds.size.width * 0.5];
self.titleLabel.font = [UIFont systemFontOfSize:12];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.backgroundColor = [UIColor redColor];
[self.superview addSubview:self.smallCircle];
[self.superview insertSubview:self.smallCircle belowSubview:self];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
}
//创建一个小圆于大圆之下,初始和大圆一样大
- (UIView *)smallCircle
{
if(_smallCircle == nil)
{
_smallCircle = [[UIView alloc]initWithFrame:self.frame];
_smallCircle.layer.cornerRadius = self.layer.cornerRadius;
_smallCircle.backgroundColor = [UIColor redColor];
}
return _smallCircle;
}
//创建一个形状图层,用于绘制两个圆之间的形状
- (CAShapeLayer *)shapeLayer
{
if(_shapeLayer == nil)
{
_shapeLayer= [CAShapeLayer layer];
_shapeLayer.fillColor = [UIColor redColor].CGColor;
[self.superview.layer insertSublayer:_shapeLayer atIndex:0];
}
return _shapeLayer;
}
//添加拖动手势,
- (void)pan:(UIPanGestureRecognizer*)gesture
{
//实现自定义控件的移动
//注意修改控件的形变,其ceter的值并不会改变
CGPoint transPoint = [gesture translationInView:self];
CGPoint center = self.center;
center.x += transPoint.x;
center.y += transPoint.y;
self.center = center;
//注意利用CGAffineTransformTranslate修改形变,center的值不会改变
//self.transform = CGAffineTransformTranslate(self.transform, trans.x, trans.y);
[gesture setTranslation:CGPointZero inView:self];
CGFloat distance = [self distanceWithSmallCircle:self.smallCircle BigCircle:self];
NSLog(@"%f",distance);
CGFloat smallRadius = self.bounds.size.width * 0.5;
smallRadius -= distance / 10.0;
if(smallRadius <= 0)smallRadius = 0;
self.smallCircle.bounds = CGRectMake(0, 0, smallRadius * 2, smallRadius * 2);
self.smallCircle.layer.cornerRadius = smallRadius;
if(self.smallCircle.hidden == NO)
{
self.shapeLayer.path = [self pathWithSmallCircle:self.smallCircle BigCircle:self].CGPath;
}
if(distance > 100)
{
self.smallCircle.hidden = YES;
[self.shapeLayer removeFromSuperlayer];
self.shapeLayer = nil;
}
//当手指离开时,判断当前两圆心的距离
//若两圆心距离大于规定的距离,则加载gif动画,移除当前控件
//若两圆心距离小于规定的距离,则返回最开始的位置,即小圆的位置,隐藏小圆,移除不规则矩形
if(gesture.state == UIGestureRecognizerStateEnded)
{
if(distance < 100)
{
self.center = self.smallCircle.center;
self.smallCircle.hidden = NO;
[self.shapeLayer removeFromSuperlayer];
self.shapeLayer = nil;
}
else
{
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
} completion:^(BOOL finished) {
self.center = self.smallCircle.center;
self.smallCircle.hidden = NO;
[self.shapeLayer removeFromSuperlayer];
self.shapeLayer = nil;
self.alpha = 1;
}];
}
}
}
//若两圆心距离大于规定的距离,则隐藏小圆,移除不规则矩形
- (CGFloat)distanceWithSmallCircle:(UIView*)smallCircle BigCircle:(UIView*)bigCircle
{
CGFloat offsetX = bigCircle.center.x - smallCircle.center.x;
CGFloat offsetY = bigCircle.center.y - smallCircle.center.y;
return sqrt(offsetX * offsetX + offsetY * offsetY);
}
//该矩形路径的计算公式如下(原理如顶部图片所示)
- (UIBezierPath*) pathWithSmallCircle:(UIView*)smallCircle BigCircle:(UIView*)bigCircle
{
CGFloat x1 = smallCircle.center.x;
CGFloat y1 = smallCircle.center.y;
CGFloat x2 = bigCircle.center.x;
CGFloat y2 = bigCircle.center.y;
CGFloat d = [self distanceWithSmallCircle:self.smallCircle BigCircle:self];
if(d <= 0)
{
return nil;
}
CGFloat cosθ = (y2 - y1) / d;
CGFloat sinθ = (x2 - x1) / d;
CGFloat r1 = smallCircle.bounds.size.width * 0.5;
CGFloat r2 = bigCircle.bounds.size.width * 0.5;
CGPoint pointA = CGPointMake(x1 - r1 * cosθ, y1 + r1 * sinθ);
CGPoint pointB = CGPointMake(x1 + r1 * cosθ, y1 - r1 * sinθ);
CGPoint pointC = CGPointMake(x2 + r2 * cosθ, y2 - r2 * sinθ);
CGPoint pointD = CGPointMake(x2 - r2 * cosθ, y2 + r2 * sinθ);
CGPoint pointO = CGPointMake(pointA.x + d * 0.5 * sinθ, pointA.y + d * 0.5 * cosθ);
CGPoint pointP = CGPointMake(pointB.x + d * 0.5 * sinθ, pointB.y + d * 0.5 * cosθ);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:pointA];
[path addLineToPoint:pointB];
[path addQuadCurveToPoint:pointC controlPoint:pointP];
[path addLineToPoint:pointD];
[path addQuadCurveToPoint:pointA controlPoint:pointO];
return path;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self config];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
//屏蔽高亮状态
- (void)setHighlighted:(BOOL)highlighted
{
}
@end