Swift 技术 视频播放器滚动条(源码)

一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希望未来技术之巅上有你们也有我。

整个的原理在视频中已经说的很清楚了,不懂的话直接看视频是很明朗的.
在这里插入图片描述

在这里插入图片描述

前言

2023.09.03自定义封装一个视频拖拽的滚动条.需要满足一下的需求:
1.能拖拽快进
2.能点击快进
3.能预加载进度
4.显示当前播放进度
5.显示节点,点击跳到对应的节点

在这里插入图片描述

思路

该拖拽进度条底部是用来显示预加载进度的,使用系统自带的UIProgressView控件.最外面能拖拽播放进度的使用系统自带的UISlider控件.节点通过for循环创建按键出来的节点.这样有一个问题,当播放到节点的位置的时候,节点会挡住拖拽进度条的位置.所以拖拽进度条的原点,就用一张透明的图片(相当于不要了),然后创建一个按键在最前面,用一张圆形图片,挡住原来UISlider控件的原点,跟随滑动,播放的个过程

在这里插入图片描述
可以看到上面的图片就是用一个自定义的按键挡住了原来UISlider控件的原点.

重点

下面说一下整个封装的几个关键地方.

点击滚动条
在这里插入图片描述
算出point值的公式:
在这里插入图片描述

let point = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
全部代码

//
//  PlayProgressView.swift
//  SwiftDemol
//
//  Created by 冯汉栩 on 2023/8/21.
//import UIKitclass PlayProgressView: UIView {// 预加载进度lazy var progress: UIProgressView = {let progress = UIProgressView()progress.progressTintColor = UIColor(red: 169.0/255.0, green: 169.0/255.0, blue: 169.0/255.0, alpha: 1.0)//深灰色progress.trackTintColor = UIColor(red: 228.0/255.0, green: 228.0/255.0, blue: 228.0/255.0, alpha: 1.0)//浅灰色return progress}()// 进度条 clearn_point   slider_pointer_normallazy var slider: UISlider = { [weak self] inlet slider  = UISlider()slider.minimumTrackTintColor = UIColor(red: 74.0/255.0, green: 155.0/255.0, blue: 234.0/255.0, alpha: 1.0)//蓝色slider.maximumTrackTintColor = UIColor.clear // 透明颜色slider.setThumbImage(UIImage(named: "slider_pointer_normal"), for: .normal)//clearn_point(透明) slider_pointer_normal(白色)slider.setThumbImage(UIImage(named: "slider_pointer_normal"), for: .highlighted)slider.setThumbImage(UIImage(named: "slider_pointer_normal"), for: .selected)let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(sliderTapped(gestureRecognizer:)))slider.addGestureRecognizer(tapGestureRecognizer)return slider}()//自定义point点lazy private var draggableButton: UIButton = {let button = UIButton()button.frame = CGRect(x: 0, y: 0, width: 10, height: 20)//button.backgroundColor = .blue.withAlphaComponent(0.5)button.setImage(UIImage(named: "slider_pointer_normal"), for: .normal)button.tag = 111return button}()// 修改播放进度var changePointBlock:((_ point: Float) ->Void)?// point数组var pointList = [Float]()// 当前播放点的移动位置var pointX:Float = 0.0 {didSet {let newX = (self.frame.width - draggableButton.frame.width) * CGFloat(pointX)if newX.isNaN { return }draggableButton.frame = CGRect(x: newX, y: draggableButton.frame.origin.y, width: draggableButton.frame.width, height: draggableButton.frame.height)slider.value = pointX}}override init(frame: CGRect) {super.init(frame: frame)buildUI()}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func buildUI() {backgroundColor = .clear // .green.withAlphaComponent(0.5)addSubview(progress)progress.snp.makeConstraints { make inmake.centerY.equalToSuperview()make.left.equalToSuperview().offset(2+1)//2是跟随slider的2+偏移1make.right.equalToSuperview().offset(-2)make.height.equalTo(4)}addSubview(slider)slider.snp.makeConstraints { make inmake.centerY.equalToSuperview().offset(-1)make.left.equalToSuperview().offset(2)make.right.equalToSuperview().offset(-2)make.height.equalTo(20)}addSubview(draggableButton)let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))draggableButton.addGestureRecognizer(panGesture)}override func layoutSubviews() {super.layoutSubviews()//严重的bug是否创建过if pointList.isEmpty { return }//如果有节点就移除for subview in self.subviews {if subview is UISlider {for sliderSubView in subview.subviews {if sliderSubView is UIButton {sliderSubView.removeFromSuperview()}}}}//布局节点for i in 0..<pointList.count {let button = UIButton()slider.addSubview(button)button.tag = ibutton.setImage(UIImage(named: "point_none"), for: .normal)button.addTarget(self, action: #selector(pointNoneClick), for: .touchUpInside)button.snp.makeConstraints { make inmake.width.equalTo(16)make.height.equalTo(20)make.centerY.equalToSuperview().offset(1)make.left.equalToSuperview().offset(Float(progress.bounds.size.width)*pointList[i]-16*0.5)}}}// MARK: - slider -- 点击滚动条@objc private func sliderTapped(gestureRecognizer: UIGestureRecognizer) {let pointTapped: CGPoint = gestureRecognizer.location(in: self)let positionOfSlider: CGPoint = slider.frame.originlet widthOfSlider: CGFloat = slider.frame.size.widthlet point = ((pointTapped.x - positionOfSlider.x) * CGFloat(slider.maximumValue) / widthOfSlider)//UI--修改进度条的值slider.setValue(Float(point), animated: false)//换算x的值let newX = (self.frame.width - draggableButton.frame.width) * CGFloat(point)//修改自定义point按键的framedraggableButton.frame = CGRect(x: newX, y: draggableButton.frame.origin.y, width: draggableButton.frame.width, height: draggableButton.frame.height)//闭包出去修改AVPlayer的值 0 -- 100changePointBlock?(Float(point))}// MARK: - 按键 -- 节点按键@objc private func pointNoneClick(button:UIButton) {//换算x的值let newX = (self.frame.width - draggableButton.frame.width) * CGFloat(pointList[button.tag])//修改自定义point按键的framedraggableButton.frame = CGRect(x: newX, y: draggableButton.frame.origin.y, width: draggableButton.frame.width, height: draggableButton.frame.height)//UI--修改进度条的值slider.setValue(Float(pointList[button.tag]), animated: false)//闭包出去修改AVPlayer的值 0 -- 100changePointBlock?(pointList[button.tag])}// MARK: - 自定义按键 -- 拖拽@objc func handlePanGesture(_ gesture: UIPanGestureRecognizer) {let translation = gesture.translation(in: self)//translation.x 拖拽的值var newX = draggableButton.frame.origin.x + translation.xswitch gesture.state {case .changed://更新按钮的 x 坐标,限制在 view 的范围内newX = max(0, min(newX, self.frame.width - draggableButton.frame.width))//意思是:newX取值范围0 ~ self.frame.width - draggableButton.frame.width 之间//修改自定义point按键的framedraggableButton.frame = CGRect(x: newX, y: draggableButton.frame.origin.y, width: draggableButton.frame.width, height: draggableButton.frame.height)gesture.setTranslation(.zero, in: self)//修改进度//换算成进度0.0-1.0let progress = newX / (self.frame.width - draggableButton.frame.width)//UI--修改进度条的值slider.setValue(Float(progress), animated: false)//闭包出去修改AVPlayer的值 0 -- 100changePointBlock?(Float(progress))default:break}}}

使用

创建+返回值出来
在这里插入图片描述
约束
在这里插入图片描述
赋值给它
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/65946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何分析识别文章/内容中高频词和关键词?

theme: orange 要分析一篇文章的高频词和关键词&#xff0c;可以使用 Python 中的 nltk 库和 collections 库或者jieba库来实现&#xff0c;本篇文章介绍基于两种库分别实现分析内容中的高频词和关键词。 nltk 和 collections 库 首先&#xff0c;需要安装 nltk 库和 collectio…

云计算 - 百度AIStudio使用小结

云计算 - 百度AIStudio使用小结 前言 本文以ffmpeg处理视频为例&#xff0c;小结一下AI Studio的使用体验及一些避坑技巧。 算力获得 免费的算力获得方式为&#xff1a;每日登录后运行一个项目&#xff08;只需要点击运行&#xff0c;不需要真正运行&#xff09;即可获得8小…

深入理解 JVM 之——动手编译 JDK

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 本篇为深入理解 Java 虚拟机第一章的实战内容&#xff0c;推荐在学习前先掌握基础的 Linux 操作、编译原理基础以及扎实的 C/C 功底。 该系列的 GitHub 仓库&#xff1a;https://github.com/Doge2077/lear…

C++知名开源库 整理收集

日志 spdlog 使用 CMake 构建&#xff1a; https://github.com/gabime/spdlog​ github.com/gabime/spdlog json json 语法极其简单友好 https://github.com/nlohmann/json​ github.com/nlohmann/json

Python爬虫网络安全:优劣势和适用范围分析

目录 优势和劣势 优势&#xff1a; 劣势&#xff1a; 适用范围&#xff1a; 1. 网页数据收集和分析&#xff1a; 2. 漏洞扫描和安全评估&#xff1a; 3. 威胁情报收集&#xff1a; 4. 社交媒体监测和情感分析&#xff1a; 注意事项 1. 合规性和法律规定&#xff1a; …

HTTP协议详解:基本概念与工作流程

个人主页:insist--个人主页​​​​​​ 本文专栏:网络基础——带你走进网络世界 本专栏会持续更新网络基础知识,希望大家多多支持,让我们一起探索这个神奇而广阔的网络世界。 目录 一、HTTP协议的基本概念 二、HTTP协议的主要特点</

VB.NET 如何将某个Excel的工作表中复制到另一个的Excel中的工作表中https://bbs.csdn.net/topics/392861034

参考http://share.freesion.com/306372/可以实现直接拷贝指定表 Private Sub Excel复制工作簿()Dim myExcelApp As New Microsoft.Office.Interop.Excel.ApplicationmyExcelApp.Workbooks.Open(System.Environment.CurrentDirectory "\\测试用例.xlsx", Type.Missin…

深入浅出理解Allan方差分析方法

一、参考资料 深入浅出理解卡尔曼滤波 二、Allan方差分析方法 1. 引言 传统的误差指标往往是采用均值误差&#xff08;反映整个误差序列有无宏观偏置&#xff09;、标准差&#xff08;反映整个误差序列的波动情况&#xff09;&#xff0c;以及均方根&#xff08;RMS&#x…

QT里使用sqlite的问题,好多坑

1. 我使用sqlite&#xff0c;开发机上好好的&#xff0c;测试机上却不行。后来发现是缺少驱动&#xff08;Driver not loaded Driver not loaded&#xff09;&#xff0c;代码检查了又检查&#xff0c;发现应该是缺少dll文件&#xff08;系统不提示&#xff0c;是自己使用 QMes…

怎样来实现流量削峰方案

削峰从本质上来说就是更多地延缓用户请求&#xff0c;以及层层过滤用户的访问需求&#xff0c;遵从“最后落地到数据库的请求数要尽量少”的原则。 1.消息队列解决削峰 要对流量进行削峰&#xff0c;最容易想到的解决方案就是用消息队列来缓冲瞬时流量&#xff0c;把同步的直…

jar包和war包的区别

SpringBoot项目既可以打成war包发布&#xff0c;也可以找成jar包发布。 jar包 jar包&#xff1a;直接通过内置Tomcat运行&#xff0c;不需要额外安装Tomcat。如需修改内置Tomcat的配置&#xff0c;只需要在SpringBoot的配置文件中配置。内置Tomcat没有自己的日志输出&#xff0…

SpringCloudGateway集成SpringDoc CORS问题

SpringCloudGateway集成SpringDoc CORS问题 集成SpringDoc后&#xff0c;在gateway在线文档界面&#xff0c;请求具体的服务接口&#xff0c;报CORS问题 Failed to fetch. Possible Reasons: CORS Network Failure URL scheme must be “http” or “https” for CORS reques…

uview ui 1.x ActonSheet项太多,设置滚动(亲测有效)

问题&#xff1a;ActionSheet滚动不了。 使用uview ui &#xff1a;u-action-sheet, 但是item太多&#xff0c;超出屏幕了&#xff0c; 查了一下文档&#xff0c;并没有设置滚动的地方。 官方文档&#xff1a;ActionSheet 操作菜单 | uView - 多平台快速开发的UI框架 - uni-a…

HashMap源码阅读(一)

HashMap继承抽象类AbstractMap&#xff0c;AbstractMap抽象类实现了Map接口 一、HashMap中的静态常量 //默认初始容量 static final int DEFAULT_INITIAL_CAPACITY 1 << 4; // aka 16 //最大长度 static final int MAXIMUM_CAPACITY 1 << 30; //负载因子&#…

很多应用都是nginx+apache+tomcat

nginx 负责负载均衡&#xff0c;将大量的访问量平衡分配给多个服务器 apache 是用来处理静态html、图片等资源&#xff0c;在对HTML解析、响应等方面比tomcat效率更高。 tomcat 处理JSP等内容&#xff0c;进行后台业务操作。 upstream bbb.com.cn{ server 192.168.10.1:80 ;…

Spring Cloud--从零开始搭建微服务基础环境【三】

&#x1f600;前言 本篇博文是关于Spring Cloud–从零开始搭建微服务基础环境【三】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;…

使用Fiddler模拟网络

Fiddler已经预置提供了模拟Modem速度的选项&#xff0c;其位置位于&#xff1a; Rules->Performances->Simulate Modem Speeds 勾选该选项后&#xff0c;所有通过Fiddler代理的流量都会变得用56k modem上网一般。 要直观观察限速后的效果&#xff0c;最好使用运行在浏览…

Linux用一键安装包部署禅道(18.5版本)

一、安装 禅道软件下载地址&#xff1a;禅道官方下载地址 - 禅道开源项目管理软件 - 禅道开源项目管理软件 请根据自己的需要下载对应的版本。 官方教程地址: (推荐)Linux用一键安装包 - 禅道使用手册 - 禅道开源项目管理软件 注&#xff1a;Linux 一键安装包必须直接解压到 …

2023-9-3 分解质因数

题目链接&#xff1a;分解质因数 #include <iostream>using namespace std;void divide(int n) {for(int i 2; i < n / i; i ){if(n % i 0){int res 0;while(n % i 0){n / i;res ;}cout << i << << res << endl;}}if(n > 1) cout &l…

虚拟现实(VR)和增强现实(AR)

虚拟现实&#xff08;Virtual Reality&#xff0c;VR&#xff09;和增强现实&#xff08;Augmented Reality&#xff0c;AR&#xff09;是两种前沿的计算机技术&#xff0c;它们正在改变人们与数字世界的互动方式。虚拟现实创造了一个计算机生成的全新虚拟环境&#xff0c;而增…