当前位置: 首页 > news >正文

网站设计的经费预算专业做网站的团队推荐

网站设计的经费预算,专业做网站的团队推荐,荣成建设局网站,电子商务网站规划、电子商务网站建设引言 视频截取在社交类 APP 中十分常见。有了上传视频的功能,就不可避免地需要提供截取和编辑的选项。如果我们过度依赖第三方库,项目的代码可能会变得异常臃肿,因为这些库往往包含许多我们用不到的功能,而且它们的 UI 样式和功能…

引言

视频截取在社交类 APP 中十分常见。有了上传视频的功能,就不可避免地需要提供截取和编辑的选项。如果我们过度依赖第三方库,项目的代码可能会变得异常臃肿,因为这些库往往包含许多我们用不到的功能,而且它们的 UI 样式和功能通常比较固定,不支持定制。因此,有条件的话,尽可能自行实现这些功能。

原本我打算直接介绍视频截取的实现方式,但发现相关的 UI 设计也非常有趣。如果不把 UI 和视频截取功能结合起来,即使掌握了截取技术,也可能难以打造出一个好用的视频编辑工具。因此,在本篇博客中,我们先来介绍视频截取中最常见的 UI 样式和小组件。

组件结构

我们创建一个继承自UIView的SVVideoEditBar类,整个编辑的操作小组件可以分为播放控制和截取控制两部分:

播放控制

第一部分是播放和暂停按钮,控制截取后视频的播放和暂停功能,这里比较简单只需要一个按钮就可以实现。

    /// 播放按钮private var playButton = UIButton()
    /// 添加播放按钮private func addPlayerButton() {playButton.setImage(UIImage(named: "icon_play_light_fill_24"), for: .normal)playButton.setImage(UIImage(named: "icon_pause_light_fill_24"), for: .selected)self.addSubview(playButton)playButton.snp.makeConstraints { make inmake.leading.equalToSuperview().offset(16.0)make.centerY.equalToSuperview()make.width.height.equalTo(24.0)}}

截取控制

第二部分为截取控制部分可以再详细划分为展示部分和操作部分。

展示

对于展示部分我们采用UICollectionView来显示视频获取到的缩略图。

    /// 列表private var collectionView:UICollectionView!
    /// 添加列表private func addCollectionView() {let layout = UICollectionViewFlowLayout()layout.minimumLineSpacing = 0.0layout.scrollDirection = .horizontalcollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)collectionView.contentInset = UIEdgeInsets(top: 0.0, left: 10.0, bottom: 0.0, right: 10.0)collectionView.backgroundColor = UIColor.clearcollectionView.showsHorizontalScrollIndicator = falsecollectionView.delegate = selfcollectionView.dataSource = selfcollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")self.addSubview(collectionView)collectionView.snp.makeConstraints { make inmake.leading.equalTo(lineView.snp.trailing).offset(20.0)make.trailing.equalToSuperview().offset(-20.0)make.top.equalToSuperview().offset(8.0)make.bottom.equalToSuperview().offset(-8.0)}collectionView.backgroundColor = .red}

关于列表中图片的尺寸会根据视频的尺寸来确定,所以我们将大小在代理方法中进行设置

extension SVVideoEditBar: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return 10}func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)return cell}func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {return CGSize(width: 40.0, height: collectionView.bounds.height)}
}
滑动遮罩

遮罩也分为两部分,一部分为黄色的边框,边框内的内容表示的是视频截取后保留的部分,而黄色边框以外的黑色半透明的遮罩则表示视频截取后舍弃的部分。

黄色的部分由我们自定义的视图SVEditorSliderView来实现。

    /// 可拖拽滑动视图private var sliderView = SVEditorSliderView()
    /// 添加滑动视图private func addSliderView() {self.addSubview(sliderView)sliderView.layer.cornerRadius = 8.0sliderView.backgroundColor = UIColor.yellowupdateLeftRightOffset()// 右侧拖拽回调sliderView.rightDragBlock = { [weak self] x in...}// 左侧拖拽回调sliderView.leftDragBlock = { [weak self] x in....}}
    /// 更新左右侧偏移private func updateLeftRightOffset() {sliderView.snp.remakeConstraints { make inmake.leading.equalTo(lineView.snp.trailing).offset(leftOffset)make.top.bottom.equalToSuperview()make.trailing.equalToSuperview().offset(rightOffset)}}

两侧的黑色半透明遮罩直接通过UIView设置背景颜色的方式来实现

    /// 左侧蒙层private var leftMaskView = UIView()/// 右侧蒙层private var rightMaskView = UIView()
    /// 添加左侧蒙层private func addLeftMaskView() {leftMaskView.backgroundColor = UIColor.black.withAlphaComponent(0.3)self.addSubview(leftMaskView)leftMaskView.snp.makeConstraints { make inmake.top.bottom.equalToSuperview()make.leading.equalTo(self.lineView.snp.trailing)make.trailing.equalTo(sliderView.snp.leading)}}/// 添加右侧蒙层private func addRightMaskView() {rightMaskView.backgroundColor = UIColor.black.withAlphaComponent(0.3)self.addSubview(rightMaskView)rightMaskView.snp.makeConstraints { make inmake.top.bottom.equalToSuperview()make.leading.equalTo(sliderView.snp.trailing)make.trailing.equalToSuperview()}}
进度条

另外还有一个在播放时会跟随播放进度而移动的进度条,直接使用UIView加阴影的方式来实现。

class SVProgressLineView: UIView {override init(frame: CGRect) {super.init(frame: frame)self.backgroundColor = .whiteself.layer.cornerRadius = 1.0// 阴影self.layer.shadowColor = UIColor.black.cgColorself.layer.shadowOffset = CGSize(width: -1, height: 0)self.layer.shadowOpacity = 0.5self.layer.shadowRadius = 2.0}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}}
    /// 进度线private var progressLineView = SVProgressLineView()
    /// 添加进度线private func addProgressLineView() {self.addSubview(progressLineView)progressLineView.snp.makeConstraints { make inmake.leading.equalTo(sliderView).offset(20.0 + 10.0)make.centerY.equalToSuperview()make.width.equalTo(2.0)make.height.equalTo(self.snp.height).inset(8.0)}}

实现操作视图 - SVEditorSliderView

接下来我们把重点集中到SVEditorSliderView上面,首先它需要一个镂空效果,来显示底部的缩图列表,另外它的两侧还需要可拖拽来修改视频的截取区域。

镂空效果

那我们先来实现它的镂空效果,采用图层的mask属性和贝塞尔曲线结合来实现镂空。

    /// maskLayerprivate let maskLayer = CAShapeLayer()/// pathprivate var path = UIBezierPath()/// fullPathprivate var fullPath = UIBezierPath()
    override init(frame: CGRect) {super.init(frame: frame)maskLayer.backgroundColor = UIColor.black.cgColorself.layer.mask = maskLayermaskLayer.fillRule = .evenOdd...}
    override func layoutSubviews() {let width = self.bounds.widthlet height = self.bounds.heightfullPath = UIBezierPath(rect: self.bounds)path = UIBezierPath(rect: CGRect(x: 20.0, y: 8.0, width: width - 40.0, height: height - 16.0))fullPath.append(path)fullPath.usesEvenOddFillRule = truemaskLayer.path = fullPath.cgPath....}

拖拽事件

在视图的最左侧和最右侧添加可拖拽的UIView视图,并处理拖拽事件,由于该视图的布局在父视图上,所以我们选择将退拽事件回调出去来处理。

    /// 右侧可拖拽视图private let rightDragView = UIView()/// 左侧可拖拽视图private let leftDragView = UIView()/// 右侧退拽回调var rightDragBlock:((CGFloat)->Void)?/// 左侧拖拽回调var leftDragBlock:((CGFloat)->Void)?
    /// 添加右侧可拖拽视图private func addRightDragView() {
//        rightDragView.backgroundColor = .whiteself.addSubview(rightDragView)let pan = UIPanGestureRecognizer(target: self, action: #selector(panAction(_:)))rightDragView.addGestureRecognizer(pan)rightDragView.isUserInteractionEnabled = true}/// 添加左侧可拖拽视图private func addLeftDragView() {
//        leftDragView.backgroundColor = .whiteself.addSubview(leftDragView)let pan = UIPanGestureRecognizer(target: self, action: #selector(panAction(_:)))leftDragView.addGestureRecognizer(pan)leftDragView.isUserInteractionEnabled = true}
    @objc private func panAction(_ pan:UIPanGestureRecognizer) {// 获取视图let view = pan.viewif view == rightDragView {let translation = pan.translation(in: self)let x = translation.xrightDragBlock?(x)} else if view == leftDragView {let translation = pan.translation(in: self)let x = translation.xleftDragBlock?(x)}pan.setTranslation(.zero, in: self)}
    override func layoutSubviews() {let width = self.bounds.widthlet height = self.bounds.height...rightDragView.frame = CGRect(x: width - 20.0, y: 0.0, width: 20.0, height: height)leftDragView.frame = CGRect(x: 0.0, y: 0.0, width: 20.0, height: height)}

拖拽处理

处理拖拽事件是个细活,在拖拽过程中我们需要更新sliderView的布局约束,我们把它分成两个部分来讨论。

右侧拖拽事件

在SVVideoEditBar类中我们还定义另外两个CGFloat类型属性

    /// 左侧偏移

    private var leftOffset:CGFloat = 0.0

    /// 右侧偏移

    private var rightOffset:CGFloat = 0.0

分别表示sliderView的左侧约束的偏移量和右侧约束的偏移量,默认都为0.0。

在进行右侧退拽时,我们首先需要注意的是,往右拖拽时不能超过SVVideoEditBar的最右端,而往左退拽时不能超过sliderView自己的最左端的拖拽视图。

        // 右侧拖拽回调sliderView.rightDragBlock = { [weak self] x inguard let self = self else { return }// 限制右侧往右的拖拽范围if self.sliderView.frame.maxX >= self.bounds.width && x > 0 {print("右侧往右拖拽到最大范围")self.rightOffset = 0.0self.updateLeftRightOffset()return}// 限制右侧往左的拖拽范围if self.sliderView.frame.maxX <= (self.sliderView.frame.minX+40.0) && x < 0 {print("右侧往左拖拽到最小范围")self.rightOffset = -(self.bounds.width - self.sliderView.frame.minX - 40.0)self.updateLeftRightOffset()return}self.rightOffset = self.rightOffset + xself.updateLeftRightOffset()}

左侧拖拽事件

当我们拖拽左侧是视图时,需要注意当往左侧拖拽时不能超过左侧的起始位置,也就是竖线的最最右侧。而往右拖拽时同样也不能超过右侧的拖拽视图。

        // 左侧拖拽回调sliderView.leftDragBlock = { [weak self] x inguard let self = self else { return }// 限制左侧往左的拖拽范围if self.sliderView.frame.minX <= self.lineView.frame.maxX && x < 0 {print("左侧往左拖拽到最小范围")self.leftOffset = 0.0self.updateLeftRightOffset()return}// 限制左侧往右的拖拽范围if self.sliderView.frame.minX >= (self.sliderView.frame.maxX-40.0) && x > 0 {print("左侧往右拖拽到最大范围")self.leftOffset = self.sliderView.frame.maxX - 40.0 - self.lineView.frame.maxXself.updateLeftRightOffset()return}self.leftOffset = self.leftOffset + xself.updateLeftRightOffset()}

这样像GIF图片一样的视频剪裁小组件的UI部分就实现了。

结语

本篇博客主要介绍了视频截取中的UI小组件,介绍了如何实现镂空效果,以及拖拽事件,尤其是拖拽时临界值的处理。

获取到了裁剪区域之后,我们就可以根据视频的长度来进行视频截取了,那么下一篇博客我们将开始进入视频截取的数据处理部分。

http://www.yayakq.cn/news/775732/

相关文章:

  • 做外贸最好的网站建设多人运动免费正能量网站链接
  • 温州网站关键词排名免费项目进度管理软件
  • 绵阳网站建设绵阳杭州做网站电话
  • 建设网站宣传郑州网站建设公司电话多少
  • 某个网站做拍卖预展的好处百度云链接
  • 肇庆网站建设公司哪个好优化网站做内链接
  • 中盛腾龙建设工程有限公司网站百度优化 几个网站内容一样
  • 英德住房和城乡建设部网站wordpress双栏主题
  • 产品包装设计素材网站软件开发流程书籍
  • 广告网站开发背景有什么网站可以做家教
  • 自己做的网站加载不出验证码青岛外贸网站设计
  • 网站排名突然消失google adwords关键词工具
  • 做外贸网站要注意什么app开发用什么软件
  • 网站如何paypal支付方式电子贺卡怎么制作
  • 建设银行网站查询网页字体网站
  • wordpress 建门户网站查手表的app哪个好用
  • 在网站怎么做代销页面排版
  • 怎么做文学动漫网站百度官方
  • 免费开源网站模板小型培训机构网站开发毕业设计
  • 济南企业网站推广方法找客户网
  • 代做网站公司免费xyz域名注册
  • 网站群维护方案上海网页制作报价
  • 中企高呈建设网站学校网站设计的作用
  • 网站国内空间价格微博推广价格表
  • 描述网站建设的基本流程php学建网站
  • 石大远程网页设计及网站建设答案iis 部署wordpress
  • 自助建站好吗网站建设技术合作合同
  • 正在建设的网站可以随时进入吗端州网站建设
  • 最好建站网站wordpress无法连接ftp服务器
  • 怎么申请自己的网站手机网站做seo