iOS實現(xiàn)雷達掃描效果
更新時間:2021年10月10日 13:14:51 作者:huangmindong
這篇文章主要為大家詳細介紹了iOS實現(xiàn)雷達掃描效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了iOS實現(xiàn)雷達掃描的具體代碼,供大家參考,具體內(nèi)容如下

#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文件
//
// 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]
/*
生成一個在圓里面的坐標(biāo)
生成的坐標(biāo)要圍繞中心的綠點(圓心),讓我們重新翻開數(shù)學(xué)課本,看看高中數(shù)學(xué)對三角函數(shù)的定義:
在一個平面直角坐標(biāo)系中,以原點為圓心,1 為半徑畫一個圓,這個圓交 x 軸于 A 點。以 O 為旋轉(zhuǎn)中心,將 A 點逆時針旋轉(zhuǎn)一定的角度α至 B 點,設(shè)此時 B 點的坐標(biāo)是(x,y),那么此時 y 的值就叫做α的正弦,記作 sinα;此時 x 的值就叫做α的余弦,記作 cosα;y 與 x 的比值 y/x 就叫做α的正切,記作 tanα。
任意角三角函數(shù) 正弦sinθ=y/r, 余弦cosθ=x/r,正切tanθ=y/x,余切cotθ=x/y,正割secθ=r/x,余割cscθ=r/y
銳角三角函數(shù) 正弦sinA=a/c, 余弦cosA=b/c,正切tanA=a/b,余切cotA=b/a,正割secA=c/b,余割cscA=c/a
還有一個很重要的公式:圓的參數(shù)方程:以點O(a,b)為圓心,以r為半徑的圓的參數(shù)方程是 x=a+r*cosθ, y=b+r*sinθ, (其中θ為參數(shù))
到這里為止,思路就清晰了,以下是generateCenterPointInRadar的方法實現(xiàn):
*/
- (CGPoint)generateCenterPointInRadar
{
float angle = arc4random() % 360;//隨機一個角度
float radius = arc4random() % (int)((self.bounds.size.width - 44)/2);//隨機一個半徑, 這里減去44是因為要把這個view顯示在圓里面,如果不減44,則有可能會顯示在圓外面
double x = cos(angle) * radius;//計算隨機出現(xiàn)的一個角度的x坐標(biāo) x=a+r*cosθ r = radius, θ = angle ,a = 圓心的x坐標(biāo)
double y = sin(angle) * radius;//計算隨機出現(xiàn)的一個角度的y坐標(biāo) y=b+r*sinθ r = radius, θ = angle ,b = 圓心的y坐標(biāo)
return CGPointMake(x + self.bounds.size.width / 2, y + self.bounds.size.height / 2);//x y 分別加個圓心的坐標(biāo)即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];
}
}
/*
我們現(xiàn)在在生成每個item的center的時候,沒有和已有的item進行比較,這是一個比較耗性能的操作,如果你的itemSize過大,maxCount過多,這甚至能導(dǎo)致死循環(huán),如果是那樣的話,你可能在對itemSize以及maxCount做出限制的同時,也對循環(huán)的數(shù)量也進行控制,如果在生成一個item的center的時候,進行了過多的循環(huán),就可以視為進入死循環(huán)了,在這種情況下,你只能重新計算已有的centers。這里不考慮這種極端情況,因為目前的itemSize和maxCount的配合,不會出現(xiàn)死循環(huán)。
我們添加一個itemFrameIntersectsInOtherItem私有方法來判斷是否和之前生成的center有了重疊:
*/
- (BOOL)itemFrameIntersectsInOtherItem:(CGRect)frame
{
for (UIView *item in items)
{
if (CGRectIntersectsRect(item.frame, frame))
{
return YES;
}
}
return NO;
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS開發(fā)中使用屏幕旋轉(zhuǎn)功能的相關(guān)方法
這篇文章主要介紹了iOS開發(fā)中使用屏幕旋轉(zhuǎn)功能的相關(guān)方法,包括Transform變化矩陣原理的講解,需要的朋友可以參考下2015-09-09
iOS應(yīng)用設(shè)計模式開發(fā)中對簡單工廠和工廠方法模式的運用
這篇文章主要介紹了iOS應(yīng)用設(shè)計模式開發(fā)中對簡單工廠和工廠方法模式的運用,示例代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-03-03
詳解iOS應(yīng)用使用Storyboard布局時的IBOutlet與IBAction
這篇文章主要介紹了iOS應(yīng)用使用Storyboard布局時的IBOutlet與IBAction,文中還附帶講解了為什么IBOutlet屬性是weak的,需要的朋友可以參考下2016-04-04

