一.storyboard裏面如下:
二.自定義BageValueBtn
// BageValueBtn.h
#import <UIKit/UIKit.h>
@interface BageValueBtn : UIButton
@end
// BageValueBtn.m
#import "BageValueBtn.h"
@interface BageValueBtn()
/** <#註釋#> */
@property (nonatomic, weak) UIView *smallCircle;
/** <#註釋#> */
@property (nonatomic, weak) CAShapeLayer *shapL;
@end
@implementation BageValueBtn
-(CAShapeLayer *)shapL {
if (_shapL == nil) {
CAShapeLayer *shapL = [CAShapeLayer layer];
[self.superview.layer insertSublayer:shapL atIndex:0];
shapL.fillColor = [UIColor redColor].CGColor;
_shapL = shapL;
}
return _shapL;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUp];
}
return self;
}
-(void)awakeFromNib {
[self setUp];
//添加手勢
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan {
//拖動
CGPoint transP = [pan translationInView:self];
//transform,transform並沒有修改center.它修改的是frame
//self.transform = CGAffineTransformTranslate(self.transform, transP.x, transP.y);
CGPoint center = self.center;
center.x += transP.x;
center.y += transP.y;
self.center = center;
//NSLog(@"%@",NSStringFromCGPoint(self.center));
//復位
[pan setTranslation:CGPointZero inView:self];
CGFloat distance = [self distanceWithSmallCircle:self.smallCircle BigCirCle:self];
//讓小圓半徑根據距離的增大,半徑在減小
CGFloat smallR = self.bounds.size.width * 0.5;
smallR -= distance / 10.0;
self.smallCircle.bounds = CGRectMake(0, 0, smallR * 2, smallR * 2);
self.smallCircle.layer.cornerRadius = smallR;
NSLog(@"%f",distance);
UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle BigCirCle:self];
// 形狀圖層
if (self.smallCircle.hidden == NO) {
self.shapL.path = path.CGPath;
}
if (distance > 60) {
//讓小圓隱藏,讓路徑隱藏
self.smallCircle.hidden = YES;
[self.shapL removeFromSuperlayer];
}
if (pan.state == UIGestureRecognizerStateEnded) {
//判斷距離是否大於60.
//大於60讓按鈕消失
if(distance < 60) {
//小於60,復位
[self.shapL removeFromSuperlayer];
self.center = self.smallCircle.center;
self.smallCircle.hidden = NO;
}else {
//播放一個動畫消失
UIImageView *imageV = [[UIImageView alloc] initWithFrame:self.bounds];
NSMutableArray *imageArray = [NSMutableArray array];
for (int i = 0 ; i < 8; i++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i +1]];
[imageArray addObject:image];
}
imageV.animationImages = imageArray;
imageV.animationDuration = 1;
[imageV startAnimating];
[self addSubview:imageV];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self removeFromSuperview];
});
}
}
}
//給定兩個圓,描述一個不規則的路徑
- (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:smallCircle BigCirCle:bigCircle];
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];
//AB
[path moveToPoint:pointA];
[path addLineToPoint:pointB];
//BC(曲線)
[path addQuadCurveToPoint:pointC controlPoint:pointP];
//CD
[path addLineToPoint:pointD];
//DA(曲線)
[path addQuadCurveToPoint:pointA controlPoint:pointO];
return path;
}
//求兩個圓之間距離
- (CGFloat)distanceWithSmallCircle:(UIView *)smallCircle BigCirCle:(UIView *)bigCircle {
//x軸方法向的偏移量
CGFloat offsetX = bigCircle.center.x - smallCircle.center.x;
//y軸方法向的偏移量
CGFloat offsetY = bigCircle.center.y - smallCircle.center.y;
return sqrt(offsetX * offsetX + offsetY * offsetY);
}
- (void)setUp {
//圓角
self.layer.cornerRadius = self.bounds.size.width * 0.5;
//設置背景顏色
[self setBackgroundColor:[UIColor redColor]];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.titleLabel.font = [UIFont systemFontOfSize:12];
//添加小圓
UIView *smallCircle = [[UIView alloc] initWithFrame:self.frame];
smallCircle.layer.cornerRadius = self.layer.cornerRadius;
smallCircle.backgroundColor = self.backgroundColor;
[self.superview addSubview:smallCircle];
self.smallCircle = smallCircle;
//把一個UIView添加到指定的位置
[self.superview insertSubview:smallCircle belowSubview:self];
}
//取消高亮狀態
-(void)setHighlighted:(BOOL)highlighted {
}
@end
三.控制器.m代碼如下:
// ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.translatesAutoresizingMaskIntoConstraints = NO;
}
@end
筆記:
整體思路徑: 指移動,按鈕跟着移動.按鈕跟着 指移動.移動時底部有 個圓,
根據上 的 圓按鈕拖動的距離, 圓的半徑在變 .移動時中間有 塊不規則的填充區域.
指移動超出 定的範圍,填充效果消失,當 指鬆開時.判斷當前 圓距離與 圓之間的距離.
如果 於60就讓 圓回來原來的位置.下次拖動時,同樣具有填充效果.如果 於60, 指鬆開時,播放 個動畫.動畫完成時,刪除動畫按鈕.
實現步驟:1. 定義 圓控件(UIButton)可以顯 背景圖 ,和 字
按鈕定義的時候要在初始 法中,把它的基本屬性設置好.在開始加載的時候設置.基本屬性包括顏,圓, 字顏,.
實現代碼:
self.backgroundColor = [UIColor redColor];
self.layer.cornerRadius = self.bounds.size.width * 0.5;self.titleLabel.font = [UIFont systemFontOfSize:12];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
2.讓 圓控件隨着 指移動 移動
添加 勢.同樣也是在初始化 法當中進 設置.注意不能根據形變修改 圓的位置,只能通過center,因爲全程都需要 到中 點計算。tansform並沒有修改center,它修改的是Frame.
添加 勢代碼爲:
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:selfaction:@selector(pan:)];
[self addGestureRecognizer:pan];
勢實現 法爲:
CGPoint transP = [pan translationInView:self];CGPoint center = self.center;
center.x += transP.x;
center.y +=transP.y;
self.center = center;注意要做復位,相對於上 次.
[pan setTranslation:CGPointZero inView:self];
3.在拖動的時候,添加 個 圓控件在原來 圓控件的位置
在初始化 法中添加 圓注意:添加 圓時不能夠直接添加在當前按鈕上,因爲按鈕是可以移動的,如果直接添加在
按鈕,它會跟着按鈕 起移動.所以以把 圓添加到按鈕 控件當中.添加時注意,要把 圓添加到按鈕底部.不然會把按
鈕給蓋起來.
UIView *smallCircle = [[UIView alloc] init];smallCircle.frame = self.frame;smallCircle.layer.cornerRadius = self.layer.cornerRadius;
smallCircle.backgroundColor = self.backgroundColor;self.smallCircle = smallCircle;
[self.superview insertSubview:smallCircle belowSubview:self];
當 指拖動 圓時, 圓的半徑會根據拖動的距離進 減 .所以要計算出兩個圓之間的距
離.計算完畢後.讓 圓的原始半徑每次都減去 個距離 例.重新設置尺.和 圓的半
徑.
計算兩個圓之間距離是 個功能單獨抽出來.
法爲:
- (CGFloat)distanceWithSmallCircle:(UIView *)smallView bigCircle:(UIView *)bigCircle{
X軸的便宜量
CGFloat offsetX = bigCircle.center.x - smallView.center.x;Y軸的便宜量
CGFloat offsetY = bigCircle.center.y - smallView.center.y;CGFloat distance = sqrt(offsetX * offsetX + offsetY * offsetY);return distance;
}
在 指拖動 法計算兩個圓之間的距離,根據拖動的距離讓 圓的半徑增 減.
實現代碼爲:
CGFloat distance = [self distanceWithSmallCircle:self.smallCircle bigCircle:self];
取出 圓的半徑
注意這 是取出 圓最初的寬度,由於每次拖動的時候都會去修改 圓的寬 .所以這 不能直接 圓的寬度
這 的是 圓的寬度,開始 圓和 圓的寬度是 樣的. 圓在移動時, 圓的寬 沒有發現變化,所以可以拿到 圓的寬
CGFloat smallR = self.bounds.size.width * 0.5;
讓 圓的半徑每次減去 個距離 例
smallR = smallR - distance / 10.0;每次移動時,重新設置 圓的寬
self.smallCircle.bounds = CGRectMake(0, 0, smallR * 2, smallR * 2);
重新設置 圓的圓
self.smallCircle.layer.cornerRadius = smallR;
4.添加粘性效果中間的粘性效果其實就是 塊填充區域.只要把這個填充區域的路徑給求出來就 了.中間的路徑通過確定6個點.把這些點連接出來就.
求點爲:x1,y1分別是 圓的圓 x2,y2分別是 圓的圓r1代表 圓的半徑r2代表 圓的半徑
d是兩個圓之間的距離
y軸的偏移量/兩個圓之間的距離cosθ= (y2 - y1) / d;x軸的偏移量/兩個圓之間的距離
sinθ= (x2 - x1) / d;
已知 個 , 個斜邊 的鄰邊=斜邊* cosθ 的對邊 =斜邊* sinθ
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];
AB
[path moveToPoint:pointA];
[path addLineToPoint:pointB];
BC(曲線)
[path addQuadCurveToPoint:pointC controlPoint:pointP];CD
[path addLineToPoint:pointD];
DA(曲線)
[path addQuadCurveToPoint:pointA controlPoint:pointO];
以上是根據兩個圓求出不規則的矩形
求出路徑後,要把路徑填充起來.但是不能夠直接給填充到當前的按鈕之上.按鈕是可以拖動的.
繪製東 ,當超出它的範圍以外就不會再繪製.
所以要把路徑添加到按鈕的 控件當中,但是當前是 個路徑,是不能夠直接添加到 控件當中的.
可能過形狀圖層添加.形狀圖層會根據 個路徑 成 個形狀.把這個形狀添加到當前控件的圖 層就可以了.添加時需要注意:形狀圖層之有 個,所以不能夠在 指拖動 法當中添加.由於當 指拖動的距離超過某個
範圍後,形狀圖 會被移除.
下 次再去移動時,還會有填充的路徑.所以把創建形狀圖層搞成 個懶加載的形式,如果發現下 次被刪除時,再重新創建.
形式爲:-(CAShapeLayer *)shap{if (_shap == nil) {
創建形狀圖層
CAShapeLayer *shap = [CAShapeLayer layer];
設置形狀圖層的填充顏
shap.fillColor = [UIColor redColor].CGColor;self.shap = shap;把形狀圖層添加到當前按鈕的 層當中.[self.superview.layer insertSublayer:shap atIndex:0];
_shap = shap;
}
return _shap;
}在 指移動 法當中,給形狀圖層賦值路徑就可以了.
5.粘性業務邏輯處理
在 指移動 法判斷兩個圓之間的距離,如果發現兩個圓之間的距離超過60時讓底部的 圓隱藏.把路徑移除
當 圓顯 的時候才繪製填充路徑
if (self.smallCircle.hidden == NO) {
UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle bigCircle:self];
self.shap.path = path.CGPath;}
當兩個圓之間的距離超過60時.if(distance > 60){
移除填充路徑
[self.shap removeFromSuperlayer];
讓底部的 圓隱匿
self.smallCircle.hidden = YES;}
6. 指停 拖動業務邏輯移動後 指鬆開時判斷兩個圓之間的距離,如果兩個圓之間的距離 於60時,讓 圓復位.
圓顯 . 指鬆開時,如果兩個圓之間的距離 於60時.播放 個動畫.動畫播放完畢時.把當前按鈕
從 控件當中移除.
播放 個動畫.
創建 個UIImageView,尺 和當前按鈕 樣 .
UIImageView *imageV = [[UIImageView alloc] initWithFrame:self.bounds];創建動畫圖
NSMutableArray *imageArray = [NSMutableArray array];
for (int i = 0; i < 8 ; i++) {
NSString *imageName = [NSString stringWithFormat:@"%d",i+1];UIImage *image = [UIImage imageNamed:imageName];[imageArray addObject:image];
}
設置動畫圖 數組
imageV.animationImages = imageArray;
設置動畫執 時
imageV.animationDuration = 1;
開始動畫
[imageV startAnimating];把UIImageView添加到當前按鈕上[self addSubview:imageV];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
[self removeFromSuperview];});
注意:
在控制器加載完畢後,要取消Autoresizing轉 動佈局不然會出現按鈕回原位的情況.self.view.translatesAutoresizingMaskIntoConstraints = NO;
粘性計算圖: