.h文件
#import @protocol WBYButtonDelegate <NSObject> /** * 開始觸摸 */ - (void)touchesBeganWithPoint:(CGPoint)point; /** * 結束觸摸 */ - (void)touchesEndWithPoint:(CGPoint)point; /** * 移動手指 */ - (void)touchesMoveWithPoint:(CGPoint)point; @end @interface ZYLButton : UIButton /** * 傳遞點擊事件的代理 */ @property (weak, nonatomic) id <WBYButtonDelegate> touchDelegate; @end .m文件 #import "WBYButton.h" @implementation WBYButton //觸摸開始 - (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 = [[WBYButton 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) { //在這裡處理進度設置成功後的事情 }]; } }