因而这些相对属于流媒体范畴.,那么须求通晓滑动的趋向

尊重知识,转载请注脚出处:iOS流媒体开发之二:滑入手势控制音量、亮度和速度

现在App摄像之中常用到手势滑动来决定音量及荧屏亮度,不难达成下


既然如此是滑动控制,那么须求精通滑动的趋势,一般左侧上下滑动为亮度,左边上下滑动为音量,左右滑行为快进快推。

概要

在最开端的时候初叶入头文件,才能应用MPVolumeView

见到文章的题目,小伙伴们大致会有二种反应:①那和流媒体技术没关系吧②网上有很多那个意义的得以完结方案。
1、对于第一种反应,从开发者的角度看这几个确实不属于流媒体技术层面,可是对于用户来讲那一个已经是看视频时理所当然应该有的效益,密不可分,鉴于用户就是上帝,所以那个相对属于流媒体范畴.
2、第三种反应确实是真情,可是能真的周全兑现的不多。有6s
Plus的同伴可以打开爱奇艺或者博客园乐乎,随便打开一个视频,手势增大音量出现音量无法调节到最大的bug,会剩余4格音量,只可以先调节到很小的音量再度增大才足以到最大音量,当然那一个是系统在6s上的一个bug,但不要不可以解决,即便是爱奇艺和博客园也绝非周详兑现(您看到此小说的时候有可能早已修复此bug)。还有一点一般的完成方案是添加UIPanGestureRecognizer手势,那些方案一经只是简短的视频播放器或者写一个Demo完全没问题,不过放在一个稍稍复杂点的视频播放器会挑起许多题材,前边再说,由此我那边提供另一种方案。


和讯博客园手势调节音量bug.png

#import<MediaPlayer/MediaPlayer.h>

思考

第一来定义一个枚举来判定滑动方向

以此职能对于有一对开发经历的人来说并简单,只要勤快点,别碰着点难点没怎么考虑就去找第三方库,都足以靠自己弄个八九不离十。我那里想通过这些功用向大家介绍自身平日解决一些难题的心路历程,希望能帮到大家的不光是技术本身,还有一种缓解难题的力量。对于爱好“废话少说,直接上代码”的伙伴,那篇小说可能会让您有点不舒服,因为在我看来代码一钱不值,值钱的是大家的沉思,别急,我们逐步来。

// 枚举值,包蕴水平位移方向和垂直运动方向

  • 浅析难题,抽离本质
    当大家获得那几个需要的时候,首先不要想自己用怎样类可以兑现,我要添加在哪个view上,大家第一要分析出那几个题材的精神,对于手势调节那么些标题的本质很粗略,就是用户左右、上下滑动时依照手指运动的动向和偏移量改变音量等装置。
  • 捋顺逻辑,列出方案
    浅析出标题标本质后,依然不要去想和代码有关的作业,接着大家要考虑处理难点的逻辑并付诸一个脚下看来可行的方案。我平时会找一张白纸,画一些草图援救回想和清楚,当然曾多次想用xmind等思想导图,然则发现仍旧一步一个脚印的白纸适合自身,小伙伴们得以依照自己拔取,只要能辅助捋顺思路就足以了。
    第一步我们要检测到手指在屏幕上的滑动,可以使用UIPanGestureRecognizer手势,前面说了这个会引起很多问题,比如一个视频播放器不仅仅有滑动手势还是单击、双击、左滑退出UINavigationController,各种手势会冲突,其次我们有时会在拖动前或者结束后处理一些事情在再执行拖动,虽然UIPanGestureRecognizer有UIGestureRecognizerStateBegan、UIGestureRecognizerStateEnded这些状态,可是手指点击屏幕没有滑动的时候无法触发,因此我最后弃用这个方案,改为使用- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;系列方法,具体实现看后面代码; 第二步要判断用户向哪个方向移动了,以便调用相应的设置,这可以根据手指在上下左右的偏移量来计算,我的方案是设置一个初始偏移量的数值,比如30,上下左右哪个方向偏移量先到达30,手势就设定为对应的方向; 第三步就是调用对应的方法去改变音量、亮度和进度了,具体实现看后面。

typedef NS_ENUM(NSInteger, PanDirection){

行动

PanDirectionHorizontalMoved, // 横向移动

逻辑通了,方案有了,现在初阶走路吧,首先你要有个可以播放视频demo,最好是点播摄像,可参考上篇博文:iOS流媒体开发之一:计算系统提供的接口,那里不赘述。

PanDirectionVerticalMoved    // 纵向活动

  • 自定义一个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”

@property (nonatomic,strong) UIPanGestureRecognizer* panGes;           
//控制音量及亮度手势

    @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

@property (nonatomic, assign) PanDirection panDirection;     
//定义枚举变量

注意:之所以选择UIButton有2点原因: 1、不用手动开启userInteractionEnabled用户交互 2、同时可以很方便的为UIButton添加Target,不需要像UIView那样在再定义一个UITapGestureRecognizer,当然UIButton添加各种状态的背景颜色各背景图也要比UIView方便得多。

@property (nonatomic, strong) UISlider *volumeViewSlider;     
//调节滑竿

  • 将自定义的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
    };
    并且声雀巢(Nestle)个象征方向的变量、一个笔录用户触摸视频时的坐标变量、一个记下用户触摸摄像时的亮度和音量大小的变量和一个笔录用户3D显示屏是视频进度的变量
    @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;//控制音量
    

@property (nonatomic, assign) BOOL isVolume;                   
//是还是不是在调节音量

      //设置self.volumeView的frame
      self.volumeView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width * 9.0 / 16.0);

在getter方法中起始化:

概念落成后,先去获取系统音量,当然捎带把耳机的插拔状态写进去,该方法在开首化播放器的时候向来self调用

  • (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;
              }
          }
      

      }

– (void)setLightAndVolume

注意: 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) {
      //在这里处理速度设置成功后的作业
      }];
      }
      }

MPVolumeView *volumeView = [[MPVolumeView alloc] init];

真机运行效果如图

_volumeViewSlider = nil;

Demo.png

for (UIView *view in [volumeView subviews]){

尾巴

if ([view.class.description isEqualToString:@”MPVolumeSlider”]){

到此处我们就成功了手指滑动摄像控制音量、亮度和速度的必要,大家在祥和的档次中实际上使用时还必要按照项目必要加上适当的UI,处理任何一些逻辑和业务流程。希望大家通过那几个小小的示例可以有谈得来的解决难点的思路和流程,力争将一个即便很简短的功用做到尽量完美。Demo可以在那边下载:示例<small>Demo</small>

_volumeViewSlider = (UISlider *)view;

break;

}

}

// 监听耳麦插入和拔掉文告

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mic:) name:AVAudioSessionRouteChangeNotification
object:nil];

}

/**

*  耳机插入、拔出事件

*/

– (void)mic:(NSNotification*)notify

{

NSDictionary *dic = notify.userInfo;

NSInteger isEarPhone = [[dic
valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

switch (isEarPhone) {

case AVAudioSessionRouteChangeReasonNewDeviceAvailable:

// 耳麦插入

break;

case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:

{

// 拔掉耳麦继续播放

[self StartPlay];

}

break;

case AVAudioSessionRouteChangeReasonCategoryChange:

// called at start – also when other audio wants to play

NSLog(@”AVAudioSessionRouteChangeReasonCategoryChange”);

break;

}

}


而后是对此手势的丰硕,在视频未全屏播放的意况下,不须要使用手势去控制,所以在点击全屏的时候去丰裕手势(全屏按钮点击事件),在回去竖屏的时候释放

-(void)fullScreenOrShrinkScreen:(UIButton*)sender

{

sender.selected = !sender.selected;

[self addControlVolmeAndLight:sender.selected];

if (_mjPlayerViewDelegate&&[_mjPlayerViewDelegate
respondsToSelector:@selector(fullScreenOrShrinkScreenDelegate:)]) {

[_mjPlayerViewDelegate fullScreenOrShrinkScreenDelegate:sender];

}

}

#pragma 马克 — 添加手势控制声音及亮度

-(void)addControlVolmeAndLight:(BOOL)isLandscape

{

if (isLandscape) {

_panGes = [[UIPanGestureRecognizer alloc]initWithTarget:self
action:@selector(controlVolmeAndLight:)];

[self addGestureRecognizer:_panGes];

}else

{

[self removeGestureRecognizer:_panGes];

}

}


在充足完手势后,就是敌手势举行拍卖,响应该手势的事件,具体注释在代码中

#pragma 马克—-滑出手势响应事件

-(void)controlVolmeAndLight:(UIPanGestureRecognizer*)ges

{

//依照职责,确定是调音量照旧亮度

CGPoint locationPoint = [ges locationInView:self];

// 获取滑动速度

CGPoint speed = [ges velocityInView:self];

// 判断是垂直运动仍然水平位移

switch (ges.state) {

case UIGestureRecognizerStateBegan:{ // 起先运动

// 使用相对化值来判断移动的主旋律

CGFloat x = fabs(speed.x);

CGFloat y = fabs(speed.y);

if (x < y){ // 垂直运动

self.panDirection = PanDirectionVerticalMoved;

// 发轫滑动的时候,状态改为正值控制音量

if (locationPoint.x > self.bounds.size.width / 2) {

self.isVolume = YES;

}else { // 状态改为显示亮度调节

self.isVolume = NO;

}

}

break;

}

case UIGestureRecognizerStateChanged:{ // 正在活动

switch (self.panDirection) {

case PanDirectionHorizontalMoved:{

//[self horizontalMoved:veloctyPoint.x]; //
水平位移的主意只要x方向的值

break;

}

case PanDirectionVerticalMoved:{

[self verticalMoved:speed.y]; // 垂直运动方法只要y方向的值

break;

}

default:

break;

}

break;

}

case UIGestureRecognizerStateEnded:{ // 移动停止

// 移动截至也亟需判定垂直或者平移

//
比如水平位移停止时,要快进到指定地点,假使那里没有看清,当大家调节高低完将来,会并发显示屏跳动的bug

switch (self.panDirection) {

case PanDirectionHorizontalMoved:{

break;

}

case PanDirectionVerticalMoved:{

// 垂直运动为止后,把状态变成不再控制音量

self.isVolume = NO;

break;

}

default:

break;

}

break;

}

default:

break;

}

}


最终一步是调剂情势(PS:亮度调节功能已有,可是它的view要自定义,还没增加)


(void)verticalMoved:(CGFloat)value{//该value为手指的滑行速度,一般最连忙度值不会超过10000,保障在0-1里头,往下滑为正,往上滑为负
所以用 “-=”NSLog(@”%f”,value);if(self.isVolume)
{self.volumeViewSlider.value-= value /10000;    }else{       
([UIScreenmainScreen].brightness-= value /10000);    }}

文/Sign_in_with_yo(简书小编)

初稿链接:http://www.jianshu.com/p/738211b94282

小说权归小编所有,转发请联系小编得到授权,并标明“简书小编”。


相关文章