葡京网上娱乐场iOS流媒体开发之二:滑动手势控制音量、亮度和进度

swift:自定义UICollectionViewFlowLayout

尊重知识,转发呼吁注明出处:iOS流媒体开发之二:滑动手势控制音量、亮度和进度

写目的

UICollectionView举凡ios中一个格外雄的控件,利用她亦可充分简练的实现部分万分好看的功用。UICollectionView的作用还要指让UICollectionViewLayout要它的子类UICollectionViewFlowLayout。而有关从定义UICollectionViewFlowLayout网上介绍的可比少。出于这无异目的,写下这边文章,希望能够帮初学者(我耶是)实现部分简的流水布局功用。下面的示范就是本篇文章的目标。最终版本代码和所有图片素材(图片名和类别蒙发生硌不等同)已经上传至Github,大家可下载学习。


差一点个简易的定义

  • UICollectionViewLayout与UICollectionViewFlowLayout

UICollectionView的来得效果几乎百分之百由UICollectionViewLayout荷(甚至是cell的高低)。所以,一般开发中所说之自定义UICollectionView否不怕是起定义UICollectionViewLayout。而UICollectionViewFlowLayout大凡后续自UICollectionViewLayout的,由苹果官方实现的水流布局功能。如果想协调实现部分水流布局功能好持续自最老UICollectionViewLayout由头写,也可连续自UICollectionViewFlowLayout开展修改。文本是连续自UICollectionViewFlowLayt*

  • UICollectionViewLayoutAttributes

仲触及便说了UICollectionView的示力量几乎整个由于UICollectionViewLayout荷,而确存储在各级一个cell的职务、大小相当于特性的是UICollectionViewLayoutAttributes。每一个cell对诺在一个属自己之UICollectionViewLayoutAttributes,而UICollectionViewLayout幸亏利用UICollectionViewLayoutAttributes里在的音讯对各一个cel进行布局。

  • 流水布局

所谓流水布局就是:就是cell以得的原理进行如同流水般的来规律的一个随着一个底排。�最经典的流水布局就是九宫格布局,绝大部分底图片选择器也是流水布局。

概要

未雨绸缪工作

  • xcode7.0
  • swift2.0
  • 协调自提供的资料并当控制器中上加如下代码

class ViewController: UIViewController,UICollectionViewDelegate, UICollectionViewDataSource {

    lazy var imageArray: [String] = {

        var array: [String] = []

        for i in 1...20 {
            array.append("\(i)-1")
        }

        return array
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        let collectionView =  UICollectionView(frame: CGRectMake(0, 100, self.view.bounds.width, 200), collectionViewLayout: UICollectionViewFlowLayout())
        collectionView.backgroundColor = UIColor.blackColor()
        collectionView.dataSource  = self
        collectionView.delegate = self

        collectionView.registerClass(ImageTextCell.self, forCellWithReuseIdentifier: "ImageTextCell")
        self.view.addSubview(collectionView)
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.imageArray.count;
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageTextCell", forIndexPath: indexPath) as! ImageTextCell
        cell.imageStr = self.imageArray[indexPath.item]

        return cell
    }

}
//这里是自定义cell的代码
class ImageTextCell: UICollectionViewCell {

    var imageView: UIImageView?
    var imageStr: NSString? {

        didSet {
            self.imageView!.image = UIImage(named: self.imageStr as! String)
        }

    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.imageView = UIImageView()
        self.addSubview(self.imageView!)

    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.imageView?.frame = self.bounds
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

功能应是这么的

看看文章的题,小伙伴们大概会来三三两两种反应:①当下与流媒体技术没关系吧②网及有无数夫作用的兑现方案。
1、对此第一栽反应,从开发者的角度看这的确不属流媒体技术面,但是于用户来讲是已经是看视频时理所当然应该有的效益,密不可分,鉴于用户就是上帝,所以这个绝对属于流媒体范畴.
2、亚种植反应确实是真情,但是会真的到兑现的无多。有6s
Plus的伴可以打开爱奇艺或新浪微博,随便打开一个视频,手势增大音量出现音量无法调节到最好要命的bug,会剩余4格音量,只能优先调节到充分粗的音量再次增大才好到无限酷音量,当然者是网在6s上的一个bug,但并非无法化解,即使是爱奇艺和初浪啊绝非完善兑现(您看看此文章的时节发出或早已修复此bug)。还有一点一般的贯彻方案是增长UIPanGestureRecognizer手势,这个方案一经只是简单的视频播放器或者写一个Demo完全无问题,可是在一个小复杂点的视频播放器会滋生众多问题,后面再说,因此自这里提供任何一样种方案。

编码

乍浪微博手势调节音量bug.png

水平排列

开创一个名吧LineLayout.swift的公文(继承自UICollectionViewFlowLayout)。添加如下几履行代码

    var itemW: CGFloat = 100
    var itemH: CGFloat = 100

    override init() {
        super.init()

        //设置每一个元素的大小
        self.itemSize = CGSizeMake(itemW, itemH)
        //设置滚动方向
        self.scrollDirection = .Horizontal
        //设置间距
        self.minimumLineSpacing = 0.7 * itemW
    }

    //苹果推荐,对一些布局的准备操作放在这里
    override func prepareLayout() {
        //设置边距(让第一张图片与最后一张图片出现在最中央)ps:这里可以进行优化
        let inset = (self.collectionView?.bounds.width ?? 0)  * 0.5 - self.itemSize.width * 0.5
        self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset)
    }

功效就算改成了如此

思考

shouldInvalidateLayoutForBoundsChange方法以及layoutAttributesForElementsInRect方法关系

题目所描绘来的是特别关键的少方式,先看自己长的如下测试代码

    /**
    返回true只要显示的边界发生改变就重新布局:(默认是false)
    内部会重新调用prepareLayout和调用
    layoutAttributesForElementsInRect方法获得部分cell的布局属性
    */
    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        print(newBounds)
        return true
    }

    /**
    用来计算出rect这个范围内所有cell的UICollectionViewLayoutAttributes,
    并返回。
    */
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        print("layoutAttributesForElementsInRect==\(rect)")
        let ret = super.layoutAttributesForElementsInRect(rect)
//        print(ret?.count)
        return ret
    }

为讲,我加加了几个打印语句,在shouldInvalidateLayoutForBoundsChange返回值设置也true后,会发现layoutAttributesForElementsInRect计调用十分数,几乎是各国滑动一点即会调用一浅。观察打印信息可以发现许多秘密

  • 起步程序来如下打印

layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)

接近看无绝知道,没事,尝试滑动。

  • 滑动

(0.5, 0.0, 320.0, 200.0) //这个是shouldInvalidateLayoutForBoundsChange方法的打印的newBounds
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)//这个是layoutAttributesForElementsInRect打印的rect
(1.5, 0.0, 320.0, 200.0) 
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
(3.5, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
...

易察觉,shouldInvalidateLayoutForBoundsChange的参数newBounds的意思是UICollectionView的可见矩形。什么吃可见矩阵?,因为UICollectionView也是UIScrollView的子类,所以她确实的“内容”远远不止我们屏幕及看看底那么多(这里不再说话时持续说可见矩阵)。那类layoutAttributesForElementsInRect打印出的物没有底转是怎么回事?不急继续滑动。

  • 解密

继续滑动后发出这些消息,经过删除一些无用信息,显示如下。(注意看有注释的实践)

...
(248.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 568.0, 568.0)
(249.0, 0.0, 320.0, 200.0)  //这里是可见矩阵
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0)  //这里变化了1136.0是568.0的2倍(1136代表的是宽度的意思应该知道不需要解释吧)
(250.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0)
...
(567.5, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(0.0, 0.0, 1136.0, 568.0)
(568.5, 0.0, 320.0, 200.0)//这里是可见矩阵
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0)  // 这里又变化了,x变成了568,宽度变成了568
(571.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0)
...
(815.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 568.0, 568.0)
(817.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 1136.0, 568.0) //还有这里
...
(1135.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(568.0, 0.0, 1136.0, 568.0)
(1136.0, 0.0, 320.0, 200.0)
layoutAttributesForElementsInRect==(1136.0, 0.0, 568.0, 568.0)  //还有这里

面的的数码展示实在就足够解释一切了。读到此地,推荐你协调去探寻找规律,通过祥和发现的奥秘绝对比直接看自己形容有答案有义之大多!下面这张图例已经证明了整

关于为何会是568之倍数。。因为自身是故底5s模拟器。你换成4s纵成为480了。至于这样设计之理由,我怀疑是为着便于进行界定之确定。

夫效果于发生部分支经历的总人口吧并无为难,只要勤快点,别遇到点难题没怎么考虑就失去寻觅第三方库,都可凭自己打个八九勿离十。我这边想透过此效应于大家介绍自己平常解决部分题目的心路历程,希望会辅助到大家的不但是技巧自,还有平等栽缓解问题的力。对于喜好“废话少说,直接上代码”的同伴,这篇稿子或会见被你小不痛快,因为在我看来代码一轻柔不值,值钱的是我们的想想,别急,咱们慢慢来。

缩放效果

了解了上面shouldInvalidateLayoutForBoundsChange方法以及layoutAttributesForElementsInRect方法关系后,可以持续拓展编码了。因为要的内容已经教了,剩下的便光是一对动画的测算,所以不再继续教授,直接贴起代码。

class LineLayout: UICollectionViewFlowLayout {

    var itemW: CGFloat = 100
    var itemH: CGFloat = 100

    lazy var inset: CGFloat = {
        //这样设置,inset就只会被计算一次,减少了prepareLayout的计算步骤
        return  (self.collectionView?.bounds.width ?? 0)  * 0.5 - self.itemSize.width * 0.5
        }()

    override init() {
        super.init()

        //设置每一个元素的大小
        self.itemSize = CGSizeMake(itemW, itemH)
        //设置滚动方向
        self.scrollDirection = .Horizontal
        //设置间距
        self.minimumLineSpacing = 0.7 * itemW
    }

    //苹果推荐,对一些布局的准备操作放在这里
    override func prepareLayout() {

        //设置边距(让第一张图片与最后一张图片出现在最中央)
        self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    /**
    返回true只要显示的边界发生改变就重新布局:(默认是false)
    内部会重新调用prepareLayout和调用
    layoutAttributesForElementsInRect方法获得部分cell的布局属性
    */
    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        return true
    }

    /**
    用来计算出rect这个范围内所有cell的UICollectionViewLayoutAttributes,
    并返回。
    */
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        //取出rect范围内所有的UICollectionViewLayoutAttributes,然而
        //我们并不关心这个范围内所有的cell的布局,我们做动画是做给人看的,
        //所以我们只需要取出屏幕上可见的那些cell的rect即可
        let array = super.layoutAttributesForElementsInRect(rect)

        //可见矩阵
        let visiableRect = CGRectMake(self.collectionView!.contentOffset.x, self.collectionView!.contentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)

        //接下来的计算是为了动画效果
        let maxCenterMargin = self.collectionView!.bounds.width * 0.5 + itemW * 0.5;
        //获得collectionVIew中央的X值(即显示在屏幕中央的X)
        let centerX = self.collectionView!.contentOffset.x + self.collectionView!.frame.size.width * 0.5;
        for attributes in array! {
            //如果不在屏幕上,直接跳过
            if !CGRectIntersectsRect(visiableRect, attributes.frame) {continue}
            let scale = 1 + (0.8 - abs(centerX - attributes.center.x) / maxCenterMargin)
            attributes.transform = CGAffineTransformMakeScale(scale, scale)
        }

        return array
    }

    /**
    用来设置collectionView停止滚动那一刻的位置

    - parameter proposedContentOffset: 原本collectionView停止滚动那一刻的位置
    - parameter velocity:              滚动速度

    - returns: 最终停留的位置
    */
    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        //实现这个方法的目的是:当停止滑动,时刻有一张图片是位于屏幕最中央的。

        let lastRect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, self.collectionView!.frame.width, self.collectionView!.frame.height)
        //获得collectionVIew中央的X值(即显示在屏幕中央的X)
        let centerX = proposedContentOffset.x + self.collectionView!.frame.width * 0.5;
        //这个范围内所有的属性
        let array = self.layoutAttributesForElementsInRect(lastRect)

        //需要移动的距离
        var adjustOffsetX = CGFloat(MAXFLOAT);
        for attri in array! {
            if abs(attri.center.x - centerX) < abs(adjustOffsetX) {
                adjustOffsetX = attri.center.x - centerX;
            }
        }

        return CGPointMake(proposedContentOffset.x + adjustOffsetX, proposedContentOffset.y)
    }
}

万一当控制器中进入下面两单章程,在你点击控制器,或者点击某个cell会发老炫的卡通片产生,这还是苹果帮咱召开好的。

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

        self.imageArray.removeAtIndex(indexPath.item)

        collectionView.deleteItemsAtIndexPaths([indexPath])
    }

        override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

        if self.collectionView!.collectionViewLayout.isKindOfClass(LineLayout.self) {
            self.collectionView!.setCollectionViewLayout(UICollectionViewFlowLayout(), animated: true)
        }else {
            self.collectionView!.setCollectionViewLayout(LineLayout(), animated: true)
        }

    }
  • 浅析问题,抽离本质
    当我们将到这要求的时,首先不要想我之所以哪些类可以兑现,我若填补加在谁view上,我们率先使分析出此问题的本色,对于手势调节这个题目的真相很粗略,就是用户左右、上下滑动时根据手指运动的来头以及偏移量改变音量等设置。
  • 捋顺逻辑,列有方案
    浅析出问题之原形后,依然不要去想与代码有关的政工,接着我们如果思考处理问题之逻辑并被起一个当下看来可行之方案。我平常会见找一张白纸,画有草图帮助记忆和掌握,当然就再三想就此xmind等合计导图,但是发现尚是朴实的白纸适合自身,小伙伴们方可因我选择,只要能够帮捋顺思路就足以了。
    第一步我们要检测到手指在屏幕上的滑动,可以使用UIPanGestureRecognizer手势,前面说了这个会引起很多问题,比如一个视频播放器不仅仅有滑动手势还是单击、双击、左滑退出UINavigationController,各种手势会冲突,其次我们有时会在拖动前或者结束后处理一些事情在再执行拖动,虽然UIPanGestureRecognizer有UIGestureRecognizerStateBegan、UIGestureRecognizerStateEnded这些状态,可是手指点击屏幕没有滑动的时候无法触发,因此我最后弃用这个方案,改为使用- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;系列方法,具体实现看后面代码; 第二步要判断用户向哪个方向移动了,以便调用相应的设置,这可以根据手指在上下左右的偏移量来计算,我的方案是设置一个初始偏移量的数值,比如30,上下左右哪个方向偏移量先到达30,手势就设定为对应的方向; 第三步就是调用对应的方法去改变音量、亮度和进度了,具体实现看后面。

总结

本篇文章记录了自家于打定义UICollectionViewFlowLayout经过遭到相见的有题材和化解智(其实生有坑爹的问题我从未排有,怕误导大家)。上面的全部都是基于UICollectionViewFlowLayout开展的改观。而自以GitHub上面上传的也发生一样卖继承自UICollectionViewLayout的非流水布局。效果如下,因为原理性的事物还差不多,就不再进行剖析(代码也有注释)。感兴趣之好及时Github点下载。如果文章被来啊错或更好的措施、建议等等,感谢您的指出。我们一起学习!O(∩_∩)O!

行动

后记

自己不见面告诉您,介绍UICollectionView的自定义布局就篇文章,是我下一个试验的前传。不过最近被教师强迫帮她们去写文档,估计进度得慢性。

逻辑通了,方案来矣,现在初始走路吧,首先你而出个可播放视频demo,最好是点播视频,可参看上篇博文:iOS流媒体开发有:总结系统提供的接口,这里不赘述。

  • 于定义一个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) {
      //在这里处理速度设置成后的事务
      }];
      }
      }

真机运行效果使图

Demo.png

尾巴

至这里我们便水到渠成了指滑动视频控制音量、亮度和速度的急需,大家以团结之品种受到其实用时还用依据项目用添加适当的UI,处理其他有逻辑和业务流程。希望大家经过者小示例可以产生协调的化解问题之思绪与流程,力争拿一个就是好简单的功能就尽量到。Demo可以于此下载:示例<small>Demo</small>