iOS流媒体开发:滑动手势控制音量、亮度和进度(转)
2017-03-30 本文已影响142人
Goldfish_jinyu
自定义一个UIButton
我们需要在视频上添加一个透明的button来捕捉和响应用户的点击滑动屏幕的事件,同时在.h文件中声明一个代理,向相应的页面传递自定义button的响应事件,代码如下:
.h文件
#import <UIKit/UIKit.h>
@protocol ZYLButtonDelegate <NSObject>
/**
* 开始触摸
*/
- (void)touchesBeganWithPoint:(CGPoint)point;
/**
* 结束触摸
*/
- (void)touchesEndWithPoint:(CGPoint)point;
/**
* 移动手指
*/
- (void)touchesMoveWithPoint:(CGPoint)point;
@end
@interface ZYLButton : UIButton
/**
* 传递点击事件的代理
*/
@property (weak, nonatomic) id <ZYLButtonDelegate> touchDelegate;
@end
.m文件
#import "ZYLButton.h"
@implementation ZYLButton
//触摸开始
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
//获取触摸开始的坐标
UITouch *touch = [touches anyObject];
CGPoint currentP = [touch locationInView:self];
[self.touchDelegate touchesBeganWithPoint:currentP];
}
//触摸结束
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentP = [touch locationInView:self];
[self.touchDelegate touchesEndWithPoint:currentP];
}
//移动
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentP = [touch locationInView:self];
[self.touchDelegate touchesMoveWithPoint:currentP];
}
@end
注意:之所以选择UIButton有2点原因:1、不用手动开启userInteractionEnabled用户交互2、同时可以很方便的为UIButton添加Target,不需要像UIView那样在再定义一个UITapGestureRecognizer,当然UIButton添加各种状态的背景颜色各背景图也要比UIView方便得多。
将自定义的Button添加到视频上
//添加自定义的Button到视频画面上
self.button = [[ZYLButton alloc] initWithFrame:playerLayer.frame];
self.button.touchDelegate = self;
[playerView addSubview:self.button];
在代理方法中改变定音量、亮度和进度
首先定义个一枚举表示上下左右,这里只需要判断手指是上下还是左右滑动
typedef NS_ENUM(NSUInteger, Direction) {
DirectionLeftOrRight,
DirectionUpOrDown,
DirectionNone
};
同时声明一个表示方向的变量、一个记录用户触摸视频时的坐标变量、一个记录用户触摸视频时的亮度和音量大小的变量和一个记录用户触摸屏幕是视频进度的变量
@property (assign, nonatomic) Direction direction;
@property (assign, nonatomic) CGPoint startPoint;
@property (assign, nonatomic) CGFloat startVB;
@property (assign, nonatomic) CGFloat startVideoRate;
刚开始触摸视频的代理
当用户首次触摸视频时,记录首次触摸的坐标、当前音量或者亮度、当前视频的进度,为了获取当前音量要首先定义MPVolumeView、 UISlider
@property (strong, nonatomic) MPVolumeView *volumeView;//控制音量的view
@property (strong, nonatomic) UISlider* volumeViewSlider;//控制音量
//设置self.volumeView的frame
self.volumeView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width * 9.0 / 16.0);
在getter方法中初始化:
- (MPVolumeView *)volumeView {
if (_volumeView == nil) {
_volumeView = [[MPVolumeView alloc] init];
[_volumeView sizeToFit];
for (UIView *view in [_volumeView subviews]){
if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
self.volumeViewSlider = (UISlider*)view;
break;
}
}
}
return _volumeView;
}
然后在开始触摸的代理里记录
#pragma mark - 开始触摸
- (void)touchesBeganWithPoint:(CGPoint)point {
//记录首次触摸坐标
self.startPoint = point;
//检测用户是触摸屏幕的左边还是右边,以此判断用户是要调节音量还是亮度,左边是亮度,右边是音量
if (self.startPoint.x <= self.button.frame.size.width / 2.0) {
//亮度
self.startVB = [UIScreen mainScreen].brightness;
} else {
//音量
self.startVB = self.volumeViewSlider.value;
}
}
CMTime ctime = self.avPlayer.currentTime;
self.startVideoRate = ctime.value / ctime.timescale / self.total;
接着在拖动的代理方法里改变音量、亮度和进度
#pragma mark - 拖动
- (void)touchesMoveWithPoint:(CGPoint)point {
//得出手指在Button上移动的距离
CGPoint panPoint = CGPointMake(point.x - self.startPoint.x, point.y - self.startPoint.y);
//分析出用户滑动的方向
if (self.direction == DirectionNone) {
if (panPoint.x >= 30 || panPoint.x <= -30) {
//进度
self.direction = DirectionLeftOrRight;
} else if (panPoint.y >= 30 || panPoint.y <= -30) {
//音量和亮度
self.direction = DirectionUpOrDown;
}
}
if (self.direction == DirectionNone) {
return;
} else if (self.direction == DirectionUpOrDown) {
//音量和亮度
if (self.startPoint.x <= self.button.frame.size.width / 2.0) {
//调节亮度
if (panPoint.y < 0) {
//增加亮度
[[UIScreen mainScreen] setBrightness:self.startVB + (-panPoint.y / 30.0 / 10)];
} else {
//减少亮度
[[UIScreen mainScreen] setBrightness:self.startVB - (panPoint.y / 30.0 / 10)];
}
} else {
//音量
if (panPoint.y < 0) {
//增大音量
[self.volumeViewSlider setValue:self.startVB + (-panPoint.y / 30.0 / 10) animated:YES];
if (self.startVB + (-panPoint.y / 30 / 10) - self.volumeViewSlider.value >= 0.1) {
[self.volumeViewSlider setValue:0.1 animated:NO];
[self.volumeViewSlider setValue:self.startVB + (-panPoint.y / 30.0 / 10) animated:YES];
}
} else {
//减少音量
[self.volumeViewSlider setValue:self.startVB - (panPoint.y / 30.0 / 10) animated:YES];
}
}
} else if (self.direction == DirectionLeftOrRight ) {
//进度
CGFloat rate = self.startVideoRate + (panPoint.x / 30.0 / 20.0);
if (rate > 1) {
rate = 1;
} else if (rate < 0) {
rate = 0;
}
}
}
注意:1、前面提到一个增大音量的bug,我这里的解决办法是如果检测到用户设置的音量比系统当前的音量大于0.1,表示此时设置的音量已经无效了,然后把音量设置为0.1后再设置为我们设置无效的那个音量就可以了,具体做法参考代码;2、在修改视频播放进度的时候,最好不在移动的方法中实时修改视频播放进度,一方面会造成卡顿的现象,一方面没有必要这么做,所以这里只是记录了用户想要调整的进度,然后在触摸结束的方法中设置进度;3、这改变音量会调用系统自己的UI显示音量大小,但是在设置亮度的时候是系统没有提供相应的UI,需要我们自己设置,这个小伙伴们按照项目的需求自行添加一个UI效果就好了。
触摸结束的代理
#pragma mark - 结束触摸
- (void)touchesEndWithPoint:(CGPoint)point {
if (self.direction == DirectionLeftOrRight) {
[self.avPlayer seekToTime:CMTimeMakeWithSeconds(self.total * self.currentRate, 1) completionHandler:^(BOOL finished) {
//在这里处理进度设置成功后的事情
}];
}
}