iOS实现雷达扫描效果

时间:2022-06-02 00:23:14

本文实例为大家分享了iOS实现雷达扫描的具体代码,供大家参考,具体内容如下

iOS实现雷达扫描效果

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import <UIKit/UIKit.h>
 
@interface LTIndicatiorView : UIView
@property(nonatomic,strong)UIColor *color;
@property(nonatomic,assign)float repeatCount;
@property(nonatomic,strong)UIColor *borderColor;
@property(nonatomic,assign)float borderWidth;
@end
 
@interface LTRadarView : UIView
@property(nonatomic,strong)UIColor *color;
@property(nonatomic,strong)UIColor *borderColor;
@property(nonatomic,assign)float borderWidth;
@property(nonatomic,assign)int pulsingCount;
@property(nonatomic,assign)float duration;
@property(nonatomic,assign)float repeatCount;
@property(nonatomic,strong)CALayer *pulsingLayer;
 
 
@end

.m文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
//
//  LTRadarView.m
//  raderScan
//
//  Created by mac on 17/2/5.
//  Copyright © 2017年 mac. All rights reserved.
//
 
#import "LTRadarView.h"
 
#define Angel 15
 
@interface LTRadarButton : UIButton
 
@end
 
@implementation LTRadarButton
 
- (void)removeFromSuperview
{
    [UIView beginAnimations:@"" context:nil];
    [UIView setAnimationDuration:0.5];
    self.transform = CGAffineTransformMakeScale(0.2, 0.2);
    self.alpha = 0;
    [UIView setAnimationDidStopSelector:@selector(callSuperRemoveFromSuperview)];
    [UIView commitAnimations];
 
}
 
- (void)callSuperRemoveFromSuperview
{
    [super removeFromSuperview];
}
 
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    self.alpha = 0;
    return self;
}
 
- (void)didMoveToWindow
{
    [super didMoveToWindow];
     self.transform = CGAffineTransformMakeScale(0.2, 0.2);
    if (self.window) {
        [UIView animateWithDuration:0.5 animations:^{
            self.transform = CGAffineTransformIdentity;
            self.alpha = 1;
        }];
    }
    
}
 
 
 
@end
 
 
@implementation LTIndicatiorView
 
- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        _color = [UIColor greenColor];
        _repeatCount = HUGE_VALF;
        _borderColor = [UIColor redColor];
        _borderWidth = 1.0f;
    }
    return self;
}
 
 
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
 - (void)drawRect:(CGRect)rect {
 // Drawing code
     
     self.backgroundColor = [UIColor whiteColor];
     [super drawRect:rect];
     self.layer.cornerRadius = self.frame.size.height/2.0f;
     self.clipsToBounds = YES;
     self.layer.borderColor = [UIColor clearColor].CGColor;
     self.layer.borderWidth = 50;
     self.layer.masksToBounds = YES;
     
     
     CGContextRef context = UIGraphicsGetCurrentContext();
     for (int i = 0; i < Angel; i++) {
         CGFloat alpha = (float)i /(float)600;
         CGColorRef shadowColor = [[UIColor greenColor] colorWithAlphaComponent:alpha].CGColor;//计算扇形填充颜色
         CGContextSetFillColorWithColor(context, shadowColor);
         CGContextMoveToPoint(context, self.center.x, self.center.y);//指定员心
         CGFloat startAngle =  (-Angel+i+1.15)/Angel*(float)M_PI;
         CGFloat endAngle = (-Angel+i-1.15)/Angel*(float)M_PI;
//         NSLog(@"startAngle = %f endAngle = %f ,alpha = %f",startAngle,endAngle,alpha);
         CGContextAddArc(context, self.center.x, self.center.y, self.frame.size.height/2.0f,0, 25, 1);//画一个扇形
         CGContextClosePath(context);
         
         CGContextDrawPath(context, kCGPathFill);//绘制扇形
 
     }
     
     CGContextSetLineWidth(context, 1);//扫描线宽度
     CGContextSetStrokeColorWithColor(context, [_color colorWithAlphaComponent:1].CGColor);//扫描线颜色
     CGContextMoveToPoint(context, self.center.x, self.center.y);
     CGContextAddLineToPoint(context, self.frame.size.height, self.center.y);
     CGContextStrokePath(context);
     
     CGContextSetRGBStrokeColor(context,255/255.0, 255/255.0, 255/255.0, 0.1);//最外面圆颜色
     CGContextSetLineWidth(context, 10);//线宽度
     CGContextAddArc(context, self.center.x, self.center.y, self.frame.size.height/2.0, 0, 2*M_PI, 1);//添加一个圆
     CGContextDrawPath(context, kCGPathStroke);//绘制路径
     
     CGContextStrokePath(context);//显示绘制
     
     
     //扫描动画
     CABasicAnimation *rotateAnimation = [CABasicAnimation animation];
     rotateAnimation.keyPath = @"transform.rotation.z";
     rotateAnimation.toValue = @(2*M_PI);
     rotateAnimation.duration = 3;
     rotateAnimation.removedOnCompletion = NO;
     rotateAnimation.repeatCount = _repeatCount;
    
     [self.layer addAnimation:rotateAnimation forKey:@"rotate_layer"];
 }
 
 
@end
 
 
@implementation LTRadarView
{
    NSMutableArray *items;
}
 
 
- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        
        items = [NSMutableArray array];
        _color = [UIColor redColor];
      
        _borderColor = [UIColor greenColor];
        _pulsingCount = 3;
        _duration = 3;
        _repeatCount = HUGE_VALF;
        _borderWidth = 3.0f;
    }
    return self;
}
 
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
    [super drawRect:rect];
    
    self.layer.cornerRadius = self.frame.size.height/2;
    self.clipsToBounds = YES;
    self.layer.borderColor = [UIColor clearColor].CGColor;
    self.layer.borderColor = [UIColor clearColor].CGColor;
    self.layer.borderWidth = 50;
    self.layer.masksToBounds = YES;
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(ctx, 0/255.0, 0/255.0, 0/255.0, 1);//圆颜色
    CGContextSetLineWidth(ctx, 1);//宽度
    CGContextAddArc(ctx, self.center.x, self.center.y, self.frame.size.height/2, 0, 2*M_PI, 1);//添加一个圆
    CGContextDrawPath(ctx, kCGPathStroke);//绘制
    CGContextStrokePath(ctx);//显示
    
    CALayer *animationLayer = [CALayer layer];
    animationLayer.frame = self.layer.frame;
    for (int i = 0; i < _pulsingCount; i++) {
        
        CALayer *pulsingLayer = [CALayer layer];
        pulsingLayer.frame = CGRectMake(0, 0, rect.size.width, rect.size.height);
        pulsingLayer.borderColor = [UIColor clearColor].CGColor;
        pulsingLayer.borderWidth = 1;
        pulsingLayer.cornerRadius = rect.size.height/2;
        pulsingLayer.backgroundColor = [UIColor redColor].CGColor;
        
        CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
        animationGroup.fillMode = kCAFillModeBoth;
        animationGroup.beginTime = CACurrentMediaTime() + (float) i * _duration / _pulsingCount;
        animationGroup.duration = _duration;
        animationGroup.repeatCount = HUGE_VALF;
        animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        animationGroup.autoreverses = NO;
        animationGroup.delegate = self;
        animationGroup.removedOnCompletion = NO;
        
        CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
        scaleAnimation.keyPath = @"transform.scale";
        scaleAnimation.removedOnCompletion = NO;
        scaleAnimation.fromValue = @(0.0f);
        scaleAnimation.toValue = @1.0f;
        scaleAnimation.autoreverses = NO;
        
        
        CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animation];
        opacityAnimation.keyPath = @"opacity";
        opacityAnimation.values = @[@1.0,@0.75,@0.5,@0.25,@0.0];
        opacityAnimation.keyTimes = @[@0.0,@0.25,@0.5,@0.75,@1];
        opacityAnimation.autoreverses = NO;
        opacityAnimation.removedOnCompletion = NO;
        
        animationGroup.animations = @[scaleAnimation,opacityAnimation];
        [pulsingLayer addAnimation:animationGroup forKey:@"pulsing"];
        
        [animationLayer addSublayer:pulsingLayer];
    }
    
    [self.layer addSublayer:animationLayer];
    
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(addOrReplaceItem) userInfo:nil repeats:YES];
}
 
 
- (void)animation:(CALayer *)layer
{
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.fillMode = kCAFillModeBoth;
    animationGroup.beginTime = CACurrentMediaTime() + 1 * _duration / _pulsingCount;
    animationGroup.duration = _duration;
    animationGroup.repeatCount = HUGE_VALF;
    animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animationGroup.autoreverses = NO;
    animationGroup.delegate = self;
    animationGroup.removedOnCompletion = NO;
    
    CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
    scaleAnimation.keyPath = @"transform.scale";
    scaleAnimation.removedOnCompletion = NO;
    scaleAnimation.fromValue = @(0.0f);
    scaleAnimation.toValue = @1.0f;
    scaleAnimation.autoreverses = NO;
    
    
    CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animation];
    opacityAnimation.keyPath = @"opacity";
    opacityAnimation.values = @[@1.0,@0.75,@0.5,@0.25,@0.0];
    opacityAnimation.keyTimes = @[@0.0,@0.25,@0.5,@0.75,@1];
    opacityAnimation.autoreverses = NO;
    opacityAnimation.removedOnCompletion = NO;
    
    animationGroup.animations = @[scaleAnimation,opacityAnimation];
    [layer addAnimation:animationGroup forKey:@"pulsing"];
    
    
}
 
#define RandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]
/*
 生成一个在圆里面的坐标
 生成的坐标要围绕中心的绿点(圆心),让我们重新翻开数学课本,看看高中数学对三角函数的定义:
 在一个平面直角坐标系中,以原点为圆心,1 为半径画一个圆,这个圆交 x 轴于 A 点。以 O 为旋转中心,将 A 点逆时针旋转一定的角度α至 B 点,设此时 B 点的坐标是(x,y),那么此时 y 的值就叫做α的正弦,记作 sinα;此时 x 的值就叫做α的余弦,记作 cosα;y 与 x 的比值 y/x 就叫做α的正切,记作 tanα。
 
 任意角三角函数 正弦sinθ=y/r, 余弦cosθ=x/r,正切tanθ=y/x,余切cotθ=x/y,正割secθ=r/x,余割cscθ=r/y
 锐角三角函数 正弦sinA=a/c, 余弦cosA=b/c,正切tanA=a/b,余切cotA=b/a,正割secA=c/b,余割cscA=c/a
 
 还有一个很重要的公式:圆的参数方程:以点O(a,b)为圆心,以r为半径的圆的参数方程是 x=a+r*cosθ, y=b+r*sinθ, (其中θ为参数)
 到这里为止,思路就清晰了,以下是generateCenterPointInRadar的方法实现:
 */
 
- (CGPoint)generateCenterPointInRadar
{
    float  angle = arc4random() % 360;//随机一个角度
    float radius = arc4random() % (int)((self.bounds.size.width - 44)/2);//随机一个半径, 这里减去44是因为要把这个view显示在圆里面,如果不减44,则有可能会显示在圓外面
    double x = cos(angle) * radius;//计算随机出现的一个角度的x坐标 x=a+r*cosθ r = radius, θ = angle ,a = 圆心的x坐标
    double y = sin(angle) * radius;//计算随机出现的一个角度的y坐标 y=b+r*sinθ r = radius, θ = angle ,b = 圆心的y坐标
    return CGPointMake(x + self.bounds.size.width / 2, y + self.bounds.size.height / 2);//x y 分别加个圆心的坐标即self.center.x.y
}
 
- (void)addOrReplaceItem
{
    int maxCount = 10;
    
    LTRadarButton *radarButton = [LTRadarButton buttonWithType:UIButtonTypeCustom];
    radarButton.frame = CGRectMake(0, 0, 44, 44);
    radarButton.backgroundColor = RandomColor;
    radarButton.layer.cornerRadius = 44/2;
    
 
    do {
        CGPoint center = [self generateCenterPointInRadar];
        radarButton.center = CGPointMake(center.x, center.y);
    } while ([self itemFrameIntersectsInOtherItem:radarButton.frame]);
        
 
    [self addSubview:radarButton];
    [items addObject:radarButton];
    
    if (items.count > maxCount)
    {
        UIView * view = [items firstObject];
        [view removeFromSuperview];
        [items removeObject:view];
    }
}
 
 
/*
 我们现在在生成每个item的center的时候,没有和已有的item进行比较,这是一个比较耗性能的操作,如果你的itemSize过大,maxCount过多,这甚至能导致死循环,如果是那样的话,你可能在对itemSize以及maxCount做出限制的同时,也对循环的数量也进行控制,如果在生成一个item的center的时候,进行了过多的循环,就可以视为进入死循环了,在这种情况下,你只能重新计算已有的centers。这里不考虑这种极端情况,因为目前的itemSize和maxCount的配合,不会出现死循环。
 我们添加一个itemFrameIntersectsInOtherItem私有方法来判断是否和之前生成的center有了重叠:
 */
- (BOOL)itemFrameIntersectsInOtherItem:(CGRect)frame
{
    for (UIView *item in items)
    {
        if (CGRectIntersectsRect(item.frame, frame))
        {
            return YES;
        }
    }
    return NO;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/huangmindong/article/details/54881163