//
|
// HDLwaveSeekBar.m
|
// HDL_Widget_iOS
|
//
|
// Created by HDL on 2019/8/27.
|
// Copyright © 2019 JLChen. All rights reserved.
|
//
|
|
#import "HDLWaveSeekBar.h"
|
#import "HDLUtlisXM.h"
|
|
#define APP_DEFAULT_BG [UIColor colorWithRed:72/255.0f green:72/255.0f blue:73/255.0f alpha:1.0f]
|
|
#define APP_DEFAULT_BG_LINE [UIColor colorWithRed:73/255.0f green:87/255.0f blue:128/255.0f alpha:1.0f]
|
|
//#define APP_DEFAULT_BAR [UIColor colorWithRed:252/255.0f green:59/255.0f blue:62/255.0f alpha:0.8f]
|
|
#define DEFAULT_WAVE_COLOR HEXCOLOR(0xFD692E)
|
#define DEFAULT_WAVE_END_COLOR HEXCOLOR(0xFB3140)
|
|
|
#define ToRad(deg) ( (M_PI * (deg)) / 180.0 )
|
#define ToDeg(rad) ( (180.0 * (rad)) / M_PI )
|
#define SQR(x) ( (x) * (x) )
|
#define GETEndAngle(X) ( ((90-X) < 0) ? ((90-X)+360) : (90-X) )
|
#define GETStartAngle(X) ( 90 + X)
|
//#define DEFAULT_DISTANCE_BETWEEN_TEXTPOINT_AND_ARC 30 // 进度显示文字坐标与进度圆弧的距离
|
#define DEFAULT_PADDING 5 //圆弧自带PADDING值,为了显示进度test文字
|
#define DEFAULT_OPEN_ANGLE 30.0f // 开口角度
|
|
|
@interface HDLWaveSeekbar ()
|
|
|
|
/**
|
是否正在移动
|
*/
|
@property (nonatomic, assign) BOOL bTouchMove;
|
|
/**
|
进度单位符号
|
*/
|
@property (nonatomic, strong) NSString *mProgressBarUnitSring;
|
|
/**
|
最小值
|
*/
|
@property (nonatomic, assign) float mMinValue;
|
|
/**
|
最大值
|
*/
|
@property (nonatomic, assign) float mMaxValue;
|
|
/**
|
进度渐变颜色数组
|
*/
|
@property (nonatomic, strong) NSArray *mWaveProgressBarColors;
|
|
/**
|
背景线宽
|
*/
|
@property (nonatomic, assign) int mBackLineWidth;
|
|
/**
|
边距
|
*/
|
@property (nonatomic, assign) int WavePadding;
|
|
|
|
@end
|
|
|
@implementation HDLWaveSeekbar{
|
|
int _mMoveCount;
|
|
CGPoint _mCenterPoint; //圆心坐标
|
|
bool _bIsInWaveProgress;
|
|
CGFloat _mWaveHeight;
|
CGFloat _mWaveWidth;
|
|
CGFloat _mWaveStartX;
|
CGFloat _mWaveEndX;
|
|
|
CGFloat _waveA; // A
|
CGFloat _waveW; // ω
|
// CGFloat _offsetF; // φ firstLayer
|
// CGFloat _offsetS; // φ secondLayer
|
CGFloat _currentK; // k
|
|
float _mPercent;
|
|
CGFloat _mWavePadding;
|
CGFloat _mCurtainY;
|
|
}
|
|
-(instancetype)initWithFrame:(CGRect)frame{
|
self = [super initWithFrame:frame];
|
if (self) {
|
_isClickable = YES;
|
_mMoveCount = 0;
|
|
_mProgress = 0;
|
_mPercent = 0;
|
_mMaxValue = 100.0f;
|
_mMinValue = 0.0f;
|
_mBackLineWidth = 2;
|
_mCornerRadius = 10;
|
_WavePadding = 10;
|
_mProgressTextColor = [UIColor blackColor];
|
_mProgressTextSize = 15;
|
_mProgressBarUnitSring = @"%";
|
_mWaveBorderColor = APP_DEFAULT_BG_LINE;
|
|
_isProgressTextShow = YES;
|
// _mWaveProgressBarColor = APP_DEFAULT_BAR;
|
_waveA = 6.0f;
|
|
|
// [self setProgressBarColor:APP_DEFAULT_BAR];
|
_mWaveProgressBarColors = @[
|
(id) DEFAULT_WAVE_COLOR.CGColor,
|
(id)DEFAULT_WAVE_END_COLOR.CGColor
|
];
|
|
[self refreshFrame];
|
|
|
self.backgroundColor = [UIColor clearColor];
|
}
|
|
return self;
|
}
|
|
|
|
/**
|
刷新布局,更新关键值
|
|
*/
|
-(void)refreshFrame{
|
_mCenterPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
|
_mWavePadding = _WavePadding*2 + _mBackLineWidth;
|
_mWaveHeight = self.frame.size.height - _mWavePadding*2;
|
_mWaveWidth = self.frame.size.width - _mWavePadding*2;
|
_mWaveStartX = _mWavePadding;
|
_mWaveEndX = _mWaveWidth + _mWaveStartX;
|
}
|
|
#pragma mark drawRect 绘制图形
|
-(void)drawRect:(CGRect)rect{
|
[super drawRect:rect];
|
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
//将当前图形状态推入堆栈
|
CGContextSaveGState(ctx);
|
//*********绘制边框背景*********
|
[self drawBorderPath:ctx];
|
//*********绘制动态的进度条*********
|
[self drawProgressBar:ctx];
|
//*********绘制显示进度值文字*********
|
[self drawProgressText:ctx];
|
|
// [self drawArcWithGradient:ctx rect:rect];//绘制渐变效果
|
|
//把堆栈顶部的状态弹出
|
CGContextRestoreGState(ctx);
|
|
}
|
|
/**
|
绘制边框
|
|
@param ctx 画布
|
*/
|
-(void)drawBorderPath:(CGContextRef)ctx{
|
CGRect drawRect = {_WavePadding+_mBackLineWidth/2, _WavePadding+_mBackLineWidth/2, self.frame.size.width-_WavePadding*2-_mBackLineWidth, self.frame.size.height-_WavePadding*2-_mBackLineWidth};
|
|
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:drawRect cornerRadius:_mCornerRadius];
|
path.lineWidth = _mBackLineWidth; //线宽
|
path.lineCapStyle = kCGLineCapRound; //弯角样式
|
path.lineJoinStyle = kCGLineJoinBevel; //交点的样式
|
[_mWaveBorderColor set];
|
|
CGContextSetLineWidth(ctx, _mBackLineWidth);
|
CGContextAddPath(ctx, path.CGPath);
|
CGContextDrawPath(ctx, kCGPathStroke);
|
// [path stroke]; //边框线颜色
|
}
|
|
|
|
/*
|
y = Asin(ωx+φ)+k
|
A表示振幅,使用这个变量来调整波浪的高度
|
ω表示频率,使用这个变量来调整波浪密集度
|
φ表示初相,使用这个变量来调整波浪初始位置
|
k表示高度,使用这个变量来调整波浪在屏幕中y轴的位置。
|
*/
|
|
/**
|
绘制进度条
|
|
@param ctx 画布
|
*/
|
-(void)drawProgressBar:(CGContextRef)ctx{
|
|
//*******绘制剪裁限制显示区域*********
|
CGRect drawRect2 = CGRectMake(_mWaveStartX, _mWavePadding , _mWaveWidth, _mWaveHeight );
|
UIBezierPath *path2 = [UIBezierPath bezierPathWithRoundedRect:drawRect2 cornerRadius:_mCornerRadius];;
|
CGContextAddPath(ctx, path2.CGPath);
|
// 剪裁路径
|
CGContextClip(ctx);
|
//*******绘制剪裁限制显示区域*********
|
|
|
CGFloat y = _mWaveHeight - _mPercent * _mWaveHeight + _mWavePadding;
|
_mCurtainY = y;
|
CGContextBeginPath( ctx );
|
//1、添加第一点
|
CGContextMoveToPoint( ctx, _mWaveStartX, y );
|
CGFloat h = y;
|
|
if(_mPercent>0 && _mPercent<1){
|
//2、添加水波浪效果,正玄函数 来计算每一个像素的坐标
|
for (int i = _mWaveStartX; i <= _mWaveEndX; ++i) {
|
y= h + _waveA * sin((i+h)*M_PI/60);
|
CGContextAddLineToPoint(ctx, i, y);
|
}
|
CGContextAddLineToPoint(ctx, _mWaveEndX, _mWavePadding + _mWaveHeight);
|
CGContextAddLineToPoint(ctx, _mWaveStartX, _mWavePadding + _mWaveHeight);
|
}else{
|
//起点-终点
|
CGPoint pointsRect[4] = {CGPointMake(_mWaveStartX, h),CGPointMake(_mWaveStartX, _mWavePadding + _mWaveHeight), CGPointMake(_mWaveEndX, _mWavePadding + _mWaveHeight),CGPointMake(_mWaveEndX, h)};
|
CGContextAddLines(ctx, pointsRect, 4);
|
}
|
|
[self drawArcWithGradient:ctx rect:drawRect2];
|
|
// CGContextClosePath(ctx);
|
//
|
// CGContextSetFillColorWithColor( ctx, _mWaveProgressBarColor.CGColor );
|
//
|
//// CGContextSetStrokeColorWithColor( ctx, APP_DEFAULT_BAR.CGColor );
|
//
|
//// CGContextSetLineWidth( ctx, 1 );
|
//
|
// CGContextDrawPath( ctx, kCGPathFill );
|
|
}
|
|
/**
|
绘制进度显示值文字
|
|
@param ctx 画布
|
*/
|
-(void)drawProgressText:(CGContextRef)ctx{
|
if(_isProgressTextShow){
|
if(_mPercent > 0.6){
|
_mProgressTextColor = [UIColor whiteColor];
|
}else{
|
_mProgressTextColor = [UIColor blackColor];
|
}
|
[self drawString:[NSString stringWithFormat:@"%d%@", _mProgress, _mProgressBarUnitSring] outsidePoint:_mCenterPoint];
|
}
|
}
|
|
/**
|
drawString 现在当前进度值
|
@param mText 显示文本
|
@param outsidePoint 坐标
|
*/
|
- (void) drawString:(NSString *)mText outsidePoint:(CGPoint)outsidePoint{
|
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
|
paragraph.alignment = NSTextAlignmentCenter;
|
NSDictionary *dic = @{NSFontAttributeName : [UIFont systemFontOfSize:_mProgressTextSize],
|
NSForegroundColorAttributeName : _mProgressTextColor,
|
NSParagraphStyleAttributeName : paragraph
|
};
|
|
// CGRect textRect = CGRectMake(outsidePoint.x, outsidePoint.y, 80, 20);
|
// [mText drawInRect:textRect withAttributes:dic];
|
|
//2019-08-15 修改文字绘制方法,最终实现文本居中效果
|
CGSize textSize = [mText sizeWithAttributes:dic];
|
CGPoint textPoint = CGPointMake(outsidePoint.x - textSize.width/2, outsidePoint.y - textSize.height/2);//根据中点坐标绘制
|
[mText drawAtPoint:textPoint withAttributes:dic];
|
|
}
|
|
|
/**
|
绘制渐变效果
|
*/
|
-(void)drawArcWithGradient:(CGContextRef)ctx rect:(CGRect)rect{
|
// 创建一个渐变色
|
// 创建RGB色彩空间,创建这个以后,context里面用的颜色都是用RGB表示
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)_mWaveProgressBarColors, NULL);
|
// 释放色彩空间
|
CGColorSpaceRelease(colorSpace);
|
colorSpace = NULL;
|
// 剪裁路径
|
CGContextClip(ctx);
|
// 用渐变色填充
|
CGContextDrawLinearGradient(ctx, gradient, CGPointMake(rect.origin.x, rect.origin.y), CGPointMake(rect.origin.x+rect.size.width, rect.origin.y+rect.size.height), 0);
|
// 释放渐变色
|
CGGradientRelease(gradient);
|
gradient = NULL;
|
|
CGContextRestoreGState(ctx);// 恢复到之前的context
|
CGContextSaveGState(ctx);
|
}
|
|
///**
|
// 计算2点坐标之间的距离
|
//
|
// @param startPoint 起点坐标
|
// @param endPonit 终点坐标
|
// @return 距离
|
// */
|
//-(float) getTwoPointDistance:(CGPoint)startPoint endPonit:(CGPoint)endPonit{
|
// CGPoint v = CGPointMake(startPoint.x - endPonit.x, startPoint.y - endPonit.y);
|
// float d = sqrt(SQR(v.x) + SQR(v.y));
|
// NSLog(@"2点距离:%f ", d);
|
// return d;
|
//
|
//}
|
|
|
|
#pragma mark Touch Event 点击事件
|
-(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
|
[super beginTrackingWithTouch:touch withEvent:event];
|
if(!_isClickable) return YES;//禁止点击
|
_bTouchMove = NO;
|
_mMoveCount = 0;
|
// CGPoint startPoint = [touch locationInView:self];
|
// _bIsInArcProgress = [self getStartPointIsInArcProgress:startPoint];//判断开始坐标是否在可点击区域
|
|
_bIsInWaveProgress = YES;//不限制点击区域
|
[self.mProgressChangedDelegate onStartTrackingTouch];
|
return YES;
|
}
|
|
-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
|
[super endTrackingWithTouch:touch withEvent:event];
|
if(!_isClickable) return;//禁止点击
|
if(!_bTouchMove){//没移动,仅点击
|
CGPoint lastPoint = [touch locationInView:self];
|
[self getCurrentProgressWithLastPoint:lastPoint];
|
[self sendActionsForControlEvents:UIControlEventValueChanged];
|
}
|
[self.mProgressChangedDelegate onStopTrackingTouch:_mProgress];
|
}
|
|
|
-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
|
[super continueTrackingWithTouch:touch withEvent:event];
|
if(!_isClickable) return YES;//禁止点击
|
if(_mMoveCount < 2){
|
_mMoveCount++;
|
}else{
|
_bTouchMove = YES; //开始移动
|
}
|
|
if(_bIsInWaveProgress){//如果刚开始点击的坐标在可点击区域
|
CGPoint lastPoint = [touch locationInView:self];
|
[self getCurrentProgressWithLastPoint:lastPoint];
|
}
|
[self sendActionsForControlEvents:UIControlEventValueChanged];
|
return YES;
|
}
|
|
|
///**
|
// 判断最后离开坐标是否在可点击区域
|
//
|
// @param lastPoint 最后的坐标
|
// */
|
//-(void)getEndPointIsInArcProgress:(CGPoint)lastPoint {
|
// [self getCurrentProgressWithLastPoint:lastPoint];
|
//}
|
|
|
/**
|
根据坐标计算出当前进度百分比和对应的进度值
|
|
@param point 当前坐标
|
*/
|
-(void)getCurrentProgressWithLastPoint:(CGPoint)point {
|
|
_mPercent = (point.y - 10 - _mBackLineWidth ) / _mWaveHeight;
|
// NSLog(@"point.y:%f _mWaveHeight:%f",point.y,_mWaveHeight);
|
// NSLog(@"_mPercent:%f",_mPercent);
|
//
|
if(_mPercent > 1){
|
_mPercent = 1;
|
}else if(_mPercent < 0){
|
_mPercent = 0;
|
}
|
_mPercent = 1 - _mPercent;
|
_mProgress = _mPercent * (_mMaxValue - _mMinValue) + _mMinValue;
|
|
if(_bTouchMove){
|
[self.mProgressChangedDelegate onProgressChanged:_mProgress];
|
}
|
|
[self setNeedsDisplay];
|
}
|
|
|
/**
|
根据进度值,计算当前 _mProgressAngle值
|
|
@param mProgress 进度值
|
*/
|
-(void)setSeekBarProgressToValue:(int)mProgress{
|
if(mProgress < _mMinValue){
|
mProgress = _mMinValue;
|
}
|
if(mProgress > _mMaxValue){
|
mProgress = _mMaxValue;
|
}
|
_mProgress = mProgress;
|
_mPercent = (_mProgress - _mMinValue) / (_mMaxValue - _mMinValue);
|
// [self.mProgressChangedDelegate onProgressChanged:_mProgress];
|
}
|
|
#pragma mark 设置进度条位置
|
/**
|
设置进度值
|
|
@param mProgress 进度值
|
*/
|
-(void)setProgress:(int)mProgress{
|
[self setSeekBarProgressToValue:mProgress];
|
[self setNeedsDisplay];
|
}
|
|
|
/**
|
设置进度显示值单位
|
|
@param mString 单位字符
|
*/
|
-(void)setProgressBarUnitSring:(NSString *)mString{
|
_mProgressBarUnitSring = mString;
|
}
|
|
|
/**
|
设置最大值最小值
|
|
@param mMinValue 最小值
|
@param mMaxValue 最大值
|
*/
|
-(void)setMinAndMaxValue:(float)mMinValue mMaxValue:(float)mMaxValue{
|
if(mMinValue < mMaxValue){
|
_mMinValue = mMinValue;
|
_mMaxValue = mMaxValue;
|
}else{
|
_mMinValue = mMaxValue;
|
_mMaxValue = mMinValue;
|
}
|
_mProgress = _mMinValue;
|
_mPercent = 0.0f;
|
}
|
|
|
/**
|
重置布局
|
|
@param mCGRect 布局
|
|
*/
|
-(void)initWithFrameWaveSeekBar:(CGRect) mCGRect{
|
self.frame = mCGRect;
|
[self refreshFrame];
|
}
|
|
|
//
|
///**
|
// 设置渐变效果
|
//
|
// @param mColors 颜色数组
|
// */
|
//-(void)setProgressBarColors:(NSArray *)mColors{
|
//
|
// // NSArray * colors = [NSArray arrayWithObjects:(id)startColor.CGColor,(id)endColor.CGColor,nil];
|
//
|
//}
|
|
|
|
/**
|
设置渐变效果
|
|
@param startColor 开始颜色
|
@param endColor 结束颜色
|
*/
|
-(void)setProgressBarColors:(UIColor *)startColor endColor:(UIColor*)endColor{
|
// _mArcProgressBarColors = [NSArray arrayWithObjects(id)startColor.CGColor,(id)endColor.CGColor,nil];
|
_mWaveProgressBarColors = @[
|
(id)startColor.CGColor,
|
(id)endColor.CGColor
|
];
|
}
|
|
|
/**
|
设置进度条颜色 单一颜色
|
|
@param oneColor 单一颜色
|
*/
|
-(void)setProgressBarColor:(UIColor *)oneColor{
|
// // _mArcProgressBarColors = [NSArray arrayWithObjects(id)startColor.CGColor,(id)endColor.CGColor,nil];
|
_mWaveProgressBarColors = @[
|
(id)oneColor.CGColor,
|
(id)oneColor.CGColor
|
];
|
|
// _mWaveProgressBarColor = oneColor;
|
}
|
|
|
/**
|
设置边距
|
*/
|
-(void)setWavePadding:(int)Padding{
|
_WavePadding = Padding;
|
[self onWaveSizeChange];
|
}
|
|
/**
|
设置背景边框宽度
|
*/
|
-(void)setBorderWidth:(int)borderWidth{
|
_mBackLineWidth = borderWidth;
|
[self onWaveSizeChange];
|
}
|
|
/**
|
获取高度 Y值
|
*/
|
-(CGFloat)getProgressY{
|
return _mCurtainY;
|
}
|
|
/**
|
刷新布局,更新关键值
|
|
*/
|
-(void)onWaveSizeChange{
|
_mWavePadding = _WavePadding*2 + _mBackLineWidth;
|
_mWaveHeight = self.frame.size.height - _mWavePadding*2;
|
_mWaveWidth = self.frame.size.width - _mWavePadding*2;
|
_mWaveStartX = _mWavePadding;
|
_mWaveEndX = _mWaveWidth + _mWaveStartX;
|
}
|
@end
|