今年是短视频的一个风口,快手、秒拍等已经在短视频领域取得了先机,一些传统直播平台也纷纷推出短视频功能。短视频App 的可玩性很大程度上在于可以对自己拍摄的短视频进行自由的编辑,例如视频拼接、剪辑、倒序、分段循环等。前些日子,本公司的产品提出了一个产品需求,即仿照微信朋友圈上传编辑短视频的选帧方案。
1064B8CBF9EE4243840C0D6A9932747B.jpg苦思冥想许久,逐渐在心中有了腹案。微信的短视频编辑是直接在一个普通view上覆盖一个可左右滑动的选帧框,这个选帧框也是唯一的响应者,而不用对选帧框与帧图的响应序列进行编辑,而我们需求中的帧序列图是一个collectionView,即必须在不同的情况下分别响应选帧框与collectionView。
第一步,必须实现覆盖在短视频序列帧上的选帧框可以跟随手指滑动,这个也是最初级的需求。其重点在与如何使左右滑动条可以跟随手指滑动,这个似乎并不是很难,在重新系统的- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法即可。左右滑动块之前的上下两个选中线用drawRect即可实现。在实现了左右滑动的效果之后,就是将这两个滑动块的位置存储起来,在进行选中后操作的时候进行坐标系转换即可获得选中范围。
第二步,如果在合适的时机进行响应者的传递。这就涉及到一个神器方法:- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 这个方法可以随意在view 上截取、传递响应者。重写滑块父视图的hitTest方法,在这个方法中对响应事件进行传递,即:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (point.x > 0 && point.x < self.width && point.y > 0 && point.y < self.height) {
ZBVideoEditSelectView *selectView;
UICollectionView *frameView;
UIScrollView *scrollView;
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[ZBVideoEditSelectView class]]) {
selectView = (ZBVideoEditSelectView *)view;
} else if ([view isKindOfClass:[UICollectionView class]]) {
frameView = (UICollectionView *)view;
} else if ([view isKindOfClass:[UIScrollView class]]) {
scrollView = (UIScrollView *)view;
}
}
if (CGRectContainsPoint(selectView.leftFrame, point) || CGRectContainsPoint(selectView.rightFrame, point)) {
return [selectView hitTest:point withEvent:event];
}
if (scrollView) {
return scrollView;
}
return frameView;
}
return [super hitTest:point withEvent:event];
}
判断点击的point是否在左右滑动块之内,如果是,则左右滑动块为第一响应者,否则序列帧列表为第一响应者。这个时候,当你对滑动进行操作的时候,滑动块滑动,点击透明区域的时候,则序列帧列表滑动。
第三,在通过滑动框选中序列帧后,怎样获取选中帧的序号,也就是获得cell 的indexPath。从网上查了许多方法与多次尝试之后,使用convertRect与CGRectContainsRect和CGRectIntersectsRect配合即可精确定位cell的位置,代码如下
NSMutableArray <NSNumber *>*array = [NSMutableArray arrayWithCapacity:10];
for (ZBSequenceFrameViewCell *cell in _frameView.visibleCells) {
CGRect cellRect = [_frameView convertRect:cell.frame toView:_sliderView];
if (CGRectContainsRect(cellRect, self.sliderView.leftFrame)) {
[array addObject:@(cell.tag)];
} else if (CGRectIntersectsRect(self.sliderView.leftFrame, cellRect)) {
[array addObject:@(cell.tag)];
}
if (CGRectContainsRect(cellRect, self.sliderView.rightFrame)) {
[array addObject:@(cell.tag)];
} else if (CGRectIntersectsRect(self.sliderView.rightFrame, cellRect)) {
[array addObject:@(cell.tag)];
}
}
利用visibleCells获取当前视图之内的所以cell,将cell的frame与左右滑块的frame转换统一坐标系内,通过CGRectContainsRect和CGRectIntersectsRect比对即可获取选中的cell,我是用cell.tag来存储序列帧的序号。获取选中序列帧的左右边界之后,就可以对选中的序列帧进行编辑了。
最后,我这个方案只是我个人想出来实现业务需求的逻辑,也是为了给有相似需求的同行一个启示,当然,如果有更好的方案,也可以发出来我们共同进步。至于微信选中框中的时间播放线以及如果利用帧选框来获取精确到毫秒基本的视频片段,就需要自己思考了。
网友评论