Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
P
PhoneManager
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Yang
PhoneManager
Commits
3f3bdcb5
Commit
3f3bdcb5
authored
May 22, 2025
by
CZ1004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【优化】调整压缩动画以及细节
parent
87820404
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
297 additions
and
145 deletions
+297
-145
Contents.json
...xcassets/Compress/Group_1171275116.imageset/Contents.json
+23
-0
Group_1171275116.png
...s/Compress/Group_1171275116.imageset/Group_1171275116.png
+0
-0
Group_1171275116@2x.png
...ompress/Group_1171275116.imageset/Group_1171275116@2x.png
+0
-0
Group_1171275116@3x.png
...ompress/Group_1171275116.imageset/Group_1171275116@3x.png
+0
-0
CompressCompletedViewController.swift
...Compress/Controller/CompressCompletedViewController.swift
+36
-33
CompressController.swift
...r/Class/Page/Compress/Controller/CompressController.swift
+78
-1
CompressQualityController.swift
.../Page/Compress/Controller/CompressQualityController.swift
+1
-1
CompressingViewController.swift
.../Page/Compress/Controller/CompressingViewController.swift
+71
-54
CustomCompressProgressBar.swift
.../Class/Page/Compress/View/CustomCompressProgressBar.swift
+86
-54
CompressViewModel.swift
...ger/Class/Page/Compress/ViewModel/CompressViewModel.swift
+2
-2
No files found.
PhoneManager/Assets.xcassets/Compress/Group_1171275116.imageset/Contents.json
0 → 100644
View file @
3f3bdcb5
{
"images"
:
[
{
"filename"
:
"Group_1171275116.png"
,
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"Group_1171275116@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"Group_1171275116@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
PhoneManager/Assets.xcassets/Compress/Group_1171275116.imageset/Group_1171275116.png
0 → 100644
View file @
3f3bdcb5
1.03 KB
PhoneManager/Assets.xcassets/Compress/Group_1171275116.imageset/Group_1171275116@2x.png
0 → 100644
View file @
3f3bdcb5
2.63 KB
PhoneManager/Assets.xcassets/Compress/Group_1171275116.imageset/Group_1171275116@3x.png
0 → 100644
View file @
3f3bdcb5
3.85 KB
PhoneManager/Class/Page/Compress/Controller/CompressCompletedViewController.swift
View file @
3f3bdcb5
...
@@ -25,7 +25,7 @@ class CompressCompletedViewController : BaseViewController{
...
@@ -25,7 +25,7 @@ class CompressCompletedViewController : BaseViewController{
}
}
}
}
var
comVideoDataSource
:
[
URL
?
]
=
[]{
var
comVideoDataSource
:
[
URL
]
=
[]{
didSet
{
didSet
{
if
let
url
=
comVideoDataSource
.
first
{
if
let
url
=
comVideoDataSource
.
first
{
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
...
@@ -225,6 +225,8 @@ class CompressCompletedViewController : BaseViewController{
...
@@ -225,6 +225,8 @@ class CompressCompletedViewController : BaseViewController{
}
}
// MARK: 事件方法
// MARK: 事件方法
/// 保留两个
@objc
func
keepButtonAction
(){
@objc
func
keepButtonAction
(){
if
currentMediaType
==
.
compressPhoto
{
if
currentMediaType
==
.
compressPhoto
{
if
let
imageData
=
self
.
comDataSource
.
first
{
if
let
imageData
=
self
.
comDataSource
.
first
{
...
@@ -234,38 +236,34 @@ class CompressCompletedViewController : BaseViewController{
...
@@ -234,38 +236,34 @@ class CompressCompletedViewController : BaseViewController{
})
{
success
,
error
in
})
{
success
,
error
in
if
(
success
){
if
(
success
){
print
(
"保存照片成功"
)
print
(
"保存照片成功"
)
}
else
{
if
let
error
=
error
{
print
(
"保存相片时出错:
\(
error
.
localizedDescription
)
"
)
}
}
}
self
.
jumpToRootVC
(
)
self
.
showDeleteSuccess
(
fileCount
:
1
,
fileSize
:
Int64
(
self
.
completedSize
)
)
}
}
}
else
{
}
else
{
self
.
jumpToRootVC
(
)
self
.
showDeleteSuccess
(
fileCount
:
1
,
fileSize
:
Int64
(
self
.
completedSize
)
)
}
}
}
else
{
}
else
{
// 保存视频到相册
// 保存视频到相册
if
let
url
=
self
.
comVideoDataSource
.
first
{
PHPhotoLibrary
.
shared
()
.
performChanges
(
{
PHPhotoLibrary
.
shared
()
.
performChanges
(
{
if
let
url
=
self
.
comVideoDataSource
.
first
{
PHAssetChangeRequest
.
creationRequestForAssetFromVideo
(
atFileURL
:
url
!
)
PHAssetChangeRequest
.
creationRequestForAssetFromVideo
(
atFileURL
:
url
as
URL
)
}
)
{
(
success
,
saveError
)
in
}
if
success
{
})
{
(
success
,
saveError
)
in
print
(
"保存视频成功"
)
if
success
{
}
else
{
print
(
"保存视频成功"
)
if
let
error
=
saveError
{
}
else
{
print
(
"保存视频时出错:
\(
error
.
localizedDescription
)
"
)
if
let
error
=
saveError
{
}
print
(
"保存视频时出错:
\(
error
.
localizedDescription
)
"
)
}
}
self
.
jumpToRootVC
()
}
}
}
else
{
self
.
showDeleteSuccess
(
fileCount
:
1
,
fileSize
:
Int64
(
self
.
completedSize
))
self
.
jumpToRootVC
()
}
}
}
}
}
}
/// 删除原数据
@objc
func
deleteButtonAction
(){
@objc
func
deleteButtonAction
(){
if
let
model
=
self
.
model
{
if
let
model
=
self
.
model
{
let
fetchResult
=
PHAsset
.
fetchAssets
(
withLocalIdentifiers
:
[
model
.
localIdentifier
],
options
:
nil
)
let
fetchResult
=
PHAsset
.
fetchAssets
(
withLocalIdentifiers
:
[
model
.
localIdentifier
],
options
:
nil
)
...
@@ -275,15 +273,11 @@ class CompressCompletedViewController : BaseViewController{
...
@@ -275,15 +273,11 @@ class CompressCompletedViewController : BaseViewController{
if
(
success
){
if
(
success
){
PhotoManager
.
shared
.
removeDataWhenDeleteInPage
(
data
:
[
self
.
model
!
])
PhotoManager
.
shared
.
removeDataWhenDeleteInPage
(
data
:
[
self
.
model
!
])
print
(
"删除文件成功"
)
print
(
"删除文件成功"
)
}
else
{
if
let
error
=
error
{
print
(
"删除文件时出错:
\(
error
.
localizedDescription
)
"
)
}
}
}
self
.
jumpToRootVC
(
)
self
.
showDeleteSuccess
(
fileCount
:
1
,
fileSize
:
Int64
(
self
.
completedSize
)
)
}
}
}
else
{
}
else
{
self
.
jumpToRootVC
(
)
self
.
showDeleteSuccess
(
fileCount
:
1
,
fileSize
:
Int64
(
self
.
completedSize
)
)
}
}
}
}
...
@@ -291,16 +285,25 @@ class CompressCompletedViewController : BaseViewController{
...
@@ -291,16 +285,25 @@ class CompressCompletedViewController : BaseViewController{
// MARK: 辅助方法
// MARK: 辅助方法
// 删除成功页面
func
showDeleteSuccess
(
fileCount
:
Int
,
fileSize
:
Int64
){
DispatchQueue
.
main
.
async
{
self
.
jumpToRootVC
()
let
vc
=
DelSuccessViewController
()
vc
.
delType
=
fileCount
>
1
?
"photos"
:
"photo"
vc
.
fileSzie
=
fileSize
vc
.
fileCount
=
fileCount
vc
.
modalPresentationStyle
=
.
fullScreen
self
.
present
(
vc
,
animated
:
true
)
}
}
/// 返回压缩控制器
/// 返回压缩控制器
func
jumpToRootVC
(){
func
jumpToRootVC
(){
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
if
let
viewControllers
=
self
.
navigationController
?
.
viewControllers
{
if
let
targetVC
=
self
.
navigationController
?
.
viewControllers
.
first
(
where
:
{
$0
is
CompressController
})
{
for
controller
in
viewControllers
.
reversed
()
{
self
.
navigationController
?
.
popToViewController
(
targetVC
,
animated
:
true
)
if
controller
is
CompressController
{
self
.
navigationController
?
.
popToViewController
(
controller
,
animated
:
true
)
break
}
}
}
}
}
}
}
}
...
...
PhoneManager/Class/Page/Compress/Controller/CompressController.swift
View file @
3f3bdcb5
...
@@ -153,7 +153,36 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
...
@@ -153,7 +153,36 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
}
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
self
.
startCompress
(
model
:
self
.
resourceData
[
indexPath
.
row
])
if
self
.
currentResourceType
==
.
compressPhoto
{
// 判断资源是否存在
let
options
=
PHImageRequestOptions
()
options
.
isNetworkAccessAllowed
=
false
options
.
progressHandler
=
nil
let
fetchResult
=
PHAsset
.
fetchAssets
(
withLocalIdentifiers
:
[
self
.
resourceData
[
indexPath
.
row
]
.
localIdentifier
],
options
:
nil
)
guard
let
phAsset
=
fetchResult
.
firstObject
else
{
showAlert
()
return
}
PHImageManager
.
default
()
.
requestImageDataAndOrientation
(
for
:
phAsset
,
options
:
options
)
{
data
,
_
,
_
,
info
in
if
data
==
nil
{
self
.
showAlert
()
}
else
{
self
.
startCompress
(
model
:
self
.
resourceData
[
indexPath
.
row
])
}
}
}
else
{
self
.
getVideoURLFromLocalIdentifier
(
localIdentifier
:
self
.
resourceData
[
indexPath
.
row
]
.
localIdentifier
)
{
url
,
error
in
if
url
!=
nil
{
self
.
startCompress
(
model
:
self
.
resourceData
[
indexPath
.
row
])
}
else
{
self
.
showAlert
()
}
}
}
}
}
func
referenceSizeForHeader
(
collectionView
collection
:
UICollectionView
,
layout
:
WaterfallMutiSectionFlowLayout
,
section
:
Int
)
->
CGSize
{
func
referenceSizeForHeader
(
collectionView
collection
:
UICollectionView
,
layout
:
WaterfallMutiSectionFlowLayout
,
section
:
Int
)
->
CGSize
{
return
CGSize
(
width
:
self
.
collectionView
.
width
,
height
:
188
)
return
CGSize
(
width
:
self
.
collectionView
.
width
,
height
:
188
)
...
@@ -271,11 +300,59 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
...
@@ -271,11 +300,59 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
}
}
func
jumpToNextPage
(
model
:
AssetModel
){
func
jumpToNextPage
(
model
:
AssetModel
){
// 先将值传到下一个页面
// 先将值传到下一个页面
let
vc
:
CompressQualityController
=
CompressQualityController
()
let
vc
:
CompressQualityController
=
CompressQualityController
()
vc
.
currentMediaType
=
self
.
currentResourceType
vc
.
currentMediaType
=
self
.
currentResourceType
vc
.
model
=
model
vc
.
model
=
model
self
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
self
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
func
showAlert
(){
let
alert
=
UIAlertController
(
title
:
nil
,
message
:
"ICloud video cannot be viewed"
,
preferredStyle
:
.
alert
)
self
.
present
(
alert
,
animated
:
true
,
completion
:
nil
)
// 2 秒后关闭弹窗
DispatchQueue
.
main
.
asyncAfter
(
deadline
:
.
now
()
+
1
)
{
alert
.
dismiss
(
animated
:
true
,
completion
:
nil
)
}
}
// 注意私有方法(某些参数不一样) 这个只能在这个类中使用
private
func
getVideoURLFromLocalIdentifier
(
localIdentifier
:
String
,
completion
:
@escaping
(
URL
?,
Error
?)
->
Void
)
{
// 通过 localIdentifier 获取 PHAsset
let
fetchOptions
=
PHFetchOptions
()
let
assets
=
PHAsset
.
fetchAssets
(
withLocalIdentifiers
:
[
localIdentifier
],
options
:
fetchOptions
)
guard
let
asset
=
assets
.
firstObject
,
asset
.
mediaType
==
.
video
else
{
DispatchQueue
.
main
.
async
{
completion
(
nil
,
NSError
(
domain
:
"com.example.error"
,
code
:
1
,
userInfo
:
[
NSLocalizedDescriptionKey
:
"未找到对应视频资源"
]))
}
return
}
let
options
=
PHVideoRequestOptions
()
options
.
isNetworkAccessAllowed
=
false
// 允许从网络下载
options
.
deliveryMode
=
.
fastFormat
// 要求高质量格式
PHImageManager
.
default
()
.
requestAVAsset
(
forVideo
:
asset
,
options
:
options
)
{
(
avAsset
,
audioMix
,
info
)
in
if
let
error
=
info
?[
PHImageErrorKey
]
as?
Error
{
DispatchQueue
.
main
.
async
{
completion
(
nil
,
error
)
}
return
}
if
let
urlAsset
=
avAsset
as?
AVURLAsset
{
DispatchQueue
.
main
.
async
{
completion
(
urlAsset
.
url
,
nil
)
}
}
else
{
DispatchQueue
.
main
.
async
{
completion
(
nil
,
NSError
(
domain
:
"CustomErrorDomain"
,
code
:
-
1
,
userInfo
:
[
NSLocalizedDescriptionKey
:
"Failed to get video URL"
]))
}
}
}
}
}
...
...
PhoneManager/Class/Page/Compress/Controller/CompressQualityController.swift
View file @
3f3bdcb5
...
@@ -258,7 +258,7 @@ class CompressQualityController : BaseViewController{
...
@@ -258,7 +258,7 @@ class CompressQualityController : BaseViewController{
fileprivate
func
updateNextView
(
_
compressAllSize
:
Double
,
_
compressingView
:
CompressingView
,
_
comDataSource
:
[
Data
],
_
comVideoDataSource
:
[
URL
?
])
{
fileprivate
func
updateNextView
(
_
compressAllSize
:
Double
,
_
compressingView
:
CompressingView
,
_
comDataSource
:
[
Data
],
_
comVideoDataSource
:
[
URL
])
{
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
compressingView
.
removeFromSuperview
()
compressingView
.
removeFromSuperview
()
let
vc
=
CompressCompletedViewController
()
let
vc
=
CompressCompletedViewController
()
...
...
PhoneManager/Class/Page/Compress/Controller/CompressingViewController.swift
View file @
3f3bdcb5
...
@@ -22,13 +22,11 @@ class CompressingViewController: BaseViewController {
...
@@ -22,13 +22,11 @@ class CompressingViewController: BaseViewController {
}
}
}
}
var
qualityType
:
CompressQualityType
?
{
var
qualityType
:
CompressQualityType
=
.
low
{
didSet
{
didSet
{
if
let
model
=
model
{
if
let
model
=
model
{
if
let
qualityType
=
qualityType
{
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
self
.
targetSizeLabel
.
text
=
formatFileSize
(
model
.
assetSize
*
self
.
qualityType
.
rawValue
)
self
.
targetSizeLabel
.
text
=
formatFileSize
(
model
.
assetSize
*
qualityType
.
rawValue
)
}
}
}
}
}
}
}
...
@@ -85,7 +83,7 @@ class CompressingViewController: BaseViewController {
...
@@ -85,7 +83,7 @@ class CompressingViewController: BaseViewController {
lazy
var
progressBar
:
CustomCompressProgressBar
=
{
lazy
var
progressBar
:
CustomCompressProgressBar
=
{
let
bar
=
CustomCompressProgressBar
()
let
bar
=
CustomCompressProgressBar
()
bar
.
thumbImage
=
UIImage
(
systemName
:
"arrowtriangle.right.fill"
)?
.
withTintColor
(
.
red
)
bar
.
thumbImage
=
UIImage
(
named
:
"Group_1171275116"
)
bar
.
layer
.
cornerRadius
=
3.5
bar
.
layer
.
cornerRadius
=
3.5
bar
.
clipsToBounds
=
true
bar
.
clipsToBounds
=
true
return
bar
return
bar
...
@@ -104,66 +102,85 @@ class CompressingViewController: BaseViewController {
...
@@ -104,66 +102,85 @@ class CompressingViewController: BaseViewController {
// MARK:设置数据
// MARK: 压缩方法
/// 开始压缩
func
startCompress
(){
func
startCompress
(){
if
let
qualityType
=
qualityType
{
if
self
.
currentMediaType
==
.
compressPhoto
{
self
.
compressPhoto
(
model
:
self
.
model
)
}
else
{
self
.
compressVideo
(
model
:
self
.
model
)
}
}
/// 压缩单个图片
/// - Parameter model: 资源
private
func
compressPhoto
(
model
:
AssetModel
?){
if
let
model
=
model
{
var
comDataSource
:
[
Data
]
=
[]
let
manager
:
CompressViewModel
=
CompressViewModel
()
let
manager
:
CompressViewModel
=
CompressViewModel
()
if
self
.
currentMediaType
==
.
compressPhoto
{
manager
.
compress
(
assets
:
[
model
],
compressionQuality
:
qualityType
.
rawValue
)
{
progress
in
// 表示压缩图片
DispatchQueue
.
main
.
async
{
var
comDataSource
:
[
Data
]
=
[]
self
.
progressBar
.
updateProgress
(
to
:
CGFloat
(
progress
))
manager
.
compress
(
assets
:
[
self
.
model
!
],
compressionQuality
:
qualityType
.
rawValue
)
{
progress
in
}
Print
(
progress
)
}
completion
:
{
compressedDataArray
,
errorArray
in
DispatchQueue
.
main
.
async
{
var
compressAllSize
=
0.0
self
.
progressBar
.
updateProgress
(
to
:
CGFloat
(
progress
))
for
(
_
,
data
)
in
compressedDataArray
.
enumerated
()
{
}
if
let
data
=
data
{
}
completion
:
{
compressedDataArray
,
errorArray
in
compressAllSize
=
compressAllSize
+
Double
(
data
.
count
)
var
compressAllSize
=
0.0
comDataSource
.
append
(
data
)
for
(
index
,
data
)
in
compressedDataArray
.
enumerated
()
{
if
let
error
=
errorArray
[
index
]
{
print
(
"第
\(
index
+
1
)
个文件压缩出错:
\(
error
.
localizedDescription
)
"
)
}
else
if
let
data
=
data
{
print
(
"第
\(
index
+
1
)
个文件压缩完成,压缩后大小:
\(
data
.
count
)
字节"
)
compressAllSize
=
compressAllSize
+
Double
(
data
.
count
)
comDataSource
.
append
(
data
)
}
else
{
print
(
"第
\(
index
+
1
)
个文件压缩失败"
)
}
}
}
}
self
.
progressBar
.
animationCompletion
=
{
// 不管成功失败都跳转下一页
self
.
updateNextView
(
compressAllSize
,
comDataSource
,[])
self
.
updateNextView
(
compressAllSize
,
comDataSource
,[])
}
}
}
else
{
}
// 压缩视频
}
var
compressAllSize
:
Double
=
0.0
}
CompressViewModel
.
compressVideos
(
models
:
[
self
.
model
!
],
quality
:
Float
(
qualityType
.
rawValue
))
{
progress
in
DispatchQueue
.
main
.
async
{
/// 压缩单个视频
self
.
progressBar
.
updateProgress
(
to
:
CGFloat
(
progress
))
/// - Parameter model: 资源
}
private
func
compressVideo
(
model
:
AssetModel
?){
}
completion
:
{
(
outputURLs
,
errors
)
in
if
let
model
=
model
{
for
(
index
,
outputURL
)
in
outputURLs
.
enumerated
()
{
var
compressAllSize
:
Double
=
0.0
if
let
outputURL
=
outputURL
{
CompressViewModel
.
compressVideos
(
models
:
[
model
],
quality
:
Float
(
qualityType
.
rawValue
))
{
progress
in
do
{
DispatchQueue
.
main
.
async
{
let
attributes
=
try
FileManager
.
default
.
attributesOfItem
(
atPath
:
outputURL
.
path
)
self
.
progressBar
.
updateProgress
(
to
:
CGFloat
(
progress
))
if
let
fileSize
=
attributes
[
.
size
]
as?
Int64
{
}
compressAllSize
=
compressAllSize
+
Double
(
fileSize
)
}
completion
:
{
(
outputURLs
,
errors
)
in
}
var
finallyUrls
:
[
URL
]
=
[]
}
catch
{
for
(
_
,
outputURL
)
in
outputURLs
.
enumerated
()
{
Print
(
"获取视频文件大小失败"
)
if
let
outputURL
=
outputURL
{
do
{
let
attributes
=
try
FileManager
.
default
.
attributesOfItem
(
atPath
:
outputURL
.
path
)
if
let
fileSize
=
attributes
[
.
size
]
as?
Int64
{
compressAllSize
=
compressAllSize
+
Double
(
fileSize
)
}
}
}
else
if
let
error
=
errors
[
index
]
{
}
catch
{
print
(
"Error compressing video
\(
index
)
:
\(
error
.
localizedDescription
)
"
)
Print
(
"获取视频文件大小失败
"
)
}
}
finallyUrls
.
append
(
outputURL
)
}
}
Print
(
"---------压缩后的大小:
\(
compressAllSize
)
"
)
}
self
.
progressBar
.
animationCompletion
=
{
// 不管成功失败都跳转下一页
// 不管成功失败都跳转下一页
self
.
updateNextView
(
compressAllSize
,[],
outputURLs
)
self
.
updateNextView
(
compressAllSize
,[],
finallyUrls
)
}
}
}
}
}
}
}
}
fileprivate
func
updateNextView
(
_
compressAllSize
:
Double
,
_
comDataSource
:
[
Data
],
_
comVideoDataSource
:
[
URL
?])
{
/// 压缩结果处理
/// - Parameters:
/// - compressAllSize: 压缩后总大小
/// - comDataSource: 压缩后的图片数据数组
/// - comVideoDataSource: 压缩后的视频链接数组
fileprivate
func
updateNextView
(
_
compressAllSize
:
Double
,
_
comDataSource
:
[
Data
],
_
comVideoDataSource
:
[
URL
])
{
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
let
vc
=
CompressCompletedViewController
()
let
vc
=
CompressCompletedViewController
()
vc
.
currentMediaType
=
self
.
currentMediaType
vc
.
currentMediaType
=
self
.
currentMediaType
...
@@ -176,7 +193,7 @@ class CompressingViewController: BaseViewController {
...
@@ -176,7 +193,7 @@ class CompressingViewController: BaseViewController {
}
}
// MARK:设置UI
// MARK:
设置UI
func
setUI
(){
func
setUI
(){
self
.
view
.
addSubview
(
self
.
bacImageView
)
self
.
view
.
addSubview
(
self
.
bacImageView
)
self
.
bacImageView
.
snp
.
makeConstraints
{
make
in
self
.
bacImageView
.
snp
.
makeConstraints
{
make
in
...
@@ -222,8 +239,8 @@ class CompressingViewController: BaseViewController {
...
@@ -222,8 +239,8 @@ class CompressingViewController: BaseViewController {
self
.
progressBar
.
snp
.
makeConstraints
{
make
in
self
.
progressBar
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalTo
(
16
)
make
.
left
.
equalTo
(
16
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
height
.
equalTo
(
7
)
make
.
height
.
equalTo
(
24
)
make
.
bottom
.
equalTo
(
-
43
-
safeHeight
)
make
.
bottom
.
equalTo
(
-
34
-
safeHeight
)
}
}
self
.
animationView
.
play
(
fromProgress
:
0
,
toProgress
:
1
,
loopMode
:
.
loop
)
self
.
animationView
.
play
(
fromProgress
:
0
,
toProgress
:
1
,
loopMode
:
.
loop
)
...
...
PhoneManager/Class/Page/Compress/View/CustomCompressProgressBar.swift
View file @
3f3bdcb5
...
@@ -8,23 +8,47 @@
...
@@ -8,23 +8,47 @@
import
UIKit
import
UIKit
class
CustomCompressProgressBar
:
UIView
{
class
CustomCompressProgressBar
:
UIView
{
var
animationCompletion
:
(()
->
Void
)
=
{}
// 背景色(已完成进度颜色)
private
let
backgroundLayer
=
CALayer
()
// 前景色(已完成进度颜色)
// 前景色(已完成进度颜色)
private
let
foregroundLayer
=
CALayer
()
private
let
foregroundLayer
=
CALayer
()
// 进度指示图标
// 进度指示图标
private
let
thumbLayer
=
CALayer
()
private
let
thumbLayer
=
CALayer
()
// 当前进度值(0-1)
// 当前进度值(0-1)
private
var
progress
:
CGFloat
=
0.0
private
var
progress
:
CGFloat
=
0.0
// 最后一次更新时间
// 动画持续时间
private
var
lastUpdateTime
:
Date
?
private
let
animationDuration
:
CFTimeInterval
=
4.0
// 动画定时器
private
var
displayLink
:
CADisplayLink
?
private
var
animationStartTime
:
CFTimeInterval
=
0
private
var
startProgress
:
CGFloat
=
0
private
var
targetProgress
:
CGFloat
=
0
// 缩略图图片
var
thumbImage
:
UIImage
?
{
var
thumbImage
:
UIImage
?
{
didSet
{
didSet
{
thumbLayer
.
contents
=
thumbImage
?
.
cgImage
thumbLayer
.
contents
=
thumbImage
?
.
cgImage
thumbLayer
.
frame
=
CGRect
(
origin
:
.
zero
,
size
:
thumbImage
?
.
size
??
CGSize
(
width
:
20
,
height
:
20
))
// 调整缩略图锚点
thumbLayer
.
anchorPoint
=
CGPoint
(
x
:
0.5
,
y
:
0.5
)
// 设置正确尺寸并居中
thumbLayer
.
frame
=
CGRect
(
x
:
0
,
y
:
bounds
.
height
/
2
-
12
,
// 24/2=12
width
:
24
,
height
:
24
)
}
}
}
}
// 添加视图配置防止裁剪
override
func
didMoveToSuperview
()
{
super
.
didMoveToSuperview
()
self
.
clipsToBounds
=
false
layer
.
masksToBounds
=
false
}
override
init
(
frame
:
CGRect
)
{
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
super
.
init
(
frame
:
frame
)
setup
()
setup
()
...
@@ -36,82 +60,90 @@ class CustomCompressProgressBar: UIView {
...
@@ -36,82 +60,90 @@ class CustomCompressProgressBar: UIView {
}
}
private
func
setup
()
{
private
func
setup
()
{
backgroundColor
=
.
white
// 设置背景层
layer
.
cornerRadius
=
frame
.
height
/
2
backgroundLayer
.
backgroundColor
=
UIColor
(
red
:
1
,
green
:
1
,
blue
:
1
,
alpha
:
1
)
.
cgColor
layer
.
masksToBounds
=
true
backgroundLayer
.
frame
=
CGRect
(
x
:
0
,
y
:
self
.
bounds
.
height
/
2
-
3.5
,
width
:
self
.
bounds
.
width
,
height
:
7
)
backgroundLayer
.
cornerRadius
=
3.5
layer
.
addSublayer
(
backgroundLayer
)
// 设置前景层
// 设置前景层
foregroundLayer
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0.51
,
blue
:
1
,
alpha
:
1
)
.
cgColor
foregroundLayer
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0.51
,
blue
:
1
,
alpha
:
1
)
.
cgColor
foregroundLayer
.
cornerRadius
=
layer
.
cornerRadius
foregroundLayer
.
cornerRadius
=
3.5
layer
.
addSublayer
(
foregroundLayer
)
layer
.
addSublayer
(
foregroundLayer
)
// 设置缩略图层
// 设置缩略图层
thumbLayer
.
contentsGravity
=
.
resizeAspect
layer
.
addSublayer
(
thumbLayer
)
layer
.
addSublayer
(
thumbLayer
)
}
}
override
func
layoutSubviews
()
{
override
func
layoutSubviews
()
{
super
.
layoutSubviews
()
super
.
layoutSubviews
()
CATransaction
.
begin
()
CATransaction
.
setDisableActions
(
true
)
updateLayers
(
for
:
progress
)
updateLayers
(
for
:
progress
)
CATransaction
.
commit
()
}
}
func
updateProgress
(
to
newProgress
:
CGFloat
)
{
func
updateProgress
(
to
newProgress
:
CGFloat
)
{
let
currentTime
=
Date
()
let
clampedProgress
=
max
(
0
,
min
(
newProgress
,
1.0
))
let
clampedProgress
=
max
(
0
,
min
(
newProgress
,
1.0
))
var
duration
:
TimeInterval
=
0
startProgress
=
currentPresentationProgress
()
targetProgress
=
clampedProgress
if
let
lastTime
=
lastUpdateTime
{
startAnimation
()
let
timeSinceLast
=
currentTime
.
timeIntervalSince
(
lastTime
)
}
duration
=
timeSinceLast
<
1.0
?
1.0
:
timeSinceLast
private
func
currentPresentationProgress
()
->
CGFloat
{
if
let
presentation
=
foregroundLayer
.
presentation
()
{
return
presentation
.
bounds
.
width
/
bounds
.
width
}
}
return
progress
animateProgress
(
from
:
progress
,
to
:
clampedProgress
,
duration
:
duration
)
lastUpdateTime
=
currentTime
}
}
private
func
updateLayers
(
for
progress
:
CGFloat
)
{
private
func
startAnimation
()
{
let
foregroundWidth
=
bounds
.
width
*
progress
animationStartTime
=
CACurrentMediaTime
()
foregroundLayer
.
frame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
foregroundWidth
,
height
:
bounds
.
height
)
displayLink
?
.
invalidate
()
displayLink
=
CADisplayLink
(
target
:
self
,
selector
:
#selector(
updateAnimation
)
)
let
thumbSize
=
thumbLayer
.
bounds
.
size
displayLink
?
.
add
(
to
:
.
main
,
forMode
:
.
common
)
let
thumbX
=
progress
*
bounds
.
width
-
thumbSize
.
width
/
2
thumbLayer
.
frame
.
origin
=
CGPoint
(
x
:
max
(
0
,
min
(
thumbX
,
bounds
.
width
-
thumbSize
.
width
)),
y
:
(
bounds
.
height
-
thumbSize
.
height
)
/
2
)
}
}
private
func
animateProgress
(
from
oldProgress
:
CGFloat
,
to
newProgress
:
CGFloat
,
duration
:
TimeInterval
)
{
@objc
private
func
updateAnimation
()
{
foregroundLayer
.
removeAllAnimations
()
let
elapsed
=
CACurrentMediaTime
()
-
animationStartTime
thumbLayer
.
removeAllAnimations
()
let
percent
=
min
(
elapsed
/
animationDuration
,
1.0
)
guard
duration
>
0
else
{
progress
=
newProgress
updateLayers
(
for
:
newProgress
)
return
}
let
foregroundAnimation
=
CABasicAnimation
(
keyPath
:
"bounds.size.width"
)
foregroundAnimation
.
fromValue
=
oldProgress
*
bounds
.
width
foregroundAnimation
.
toValue
=
newProgress
*
bounds
.
width
foregroundAnimation
.
duration
=
duration
foregroundAnimation
.
timingFunction
=
CAMediaTimingFunction
(
name
:
.
linear
)
let
thumbAnimation
=
CABasicAnimation
(
keyPath
:
"position.x"
)
let
currentProgress
=
startProgress
+
(
targetProgress
-
startProgress
)
*
CGFloat
(
percent
)
thumbAnimation
.
fromValue
=
(
oldProgress
*
bounds
.
width
)
-
thumbLayer
.
bounds
.
width
/
2
progress
=
currentProgress
thumbAnimation
.
toValue
=
(
newProgress
*
bounds
.
width
)
-
thumbLayer
.
bounds
.
width
/
2
thumbAnimation
.
duration
=
duration
thumbAnimation
.
timingFunction
=
CAMediaTimingFunction
(
name
:
.
linear
)
progress
=
newProgress
CATransaction
.
begin
()
CATransaction
.
begin
()
CATransaction
.
setDisableActions
(
true
)
CATransaction
.
setDisableActions
(
true
)
foregroundLayer
.
bounds
.
size
.
width
=
newProgress
*
bounds
.
width
updateLayers
(
for
:
currentProgress
)
thumbLayer
.
position
.
x
=
(
newProgress
*
bounds
.
width
)
-
thumbLayer
.
bounds
.
width
/
2
CATransaction
.
commit
()
CATransaction
.
commit
()
foregroundLayer
.
add
(
foregroundAnimation
,
forKey
:
nil
)
if
percent
>=
1.0
{
thumbLayer
.
add
(
thumbAnimation
,
forKey
:
nil
)
displayLink
?
.
invalidate
()
displayLink
=
nil
// 触发完成回调
animationCompletion
()
}
}
private
func
updateLayers
(
for
progress
:
CGFloat
)
{
let
foregroundWidth
=
bounds
.
width
*
progress
foregroundLayer
.
frame
=
CGRect
(
x
:
0
,
y
:
bounds
.
height
/
2
-
3.5
,
width
:
foregroundWidth
,
height
:
7
)
// 修改缩略图位置计算
let
thumbSize
=
thumbLayer
.
bounds
.
size
// 计算中心点位置(确保始终显示完整缩略图)
let
thumbCenterX
=
foregroundWidth
-
thumbSize
.
width
/
2
// 限制缩略图显示范围(不超出进度条边界)
let
minX
=
-
thumbSize
.
width
/
2
// 允许左侧部分超出
let
maxX
=
bounds
.
width
-
thumbSize
.
width
/
2
thumbLayer
.
frame
.
origin
.
x
=
max
(
minX
,
min
(
thumbCenterX
,
maxX
))
// 设置垂直居中
thumbLayer
.
frame
.
origin
.
y
=
bounds
.
height
/
2
-
thumbSize
.
height
/
2
}
}
}
}
PhoneManager/Class/Page/Compress/ViewModel/CompressViewModel.swift
View file @
3f3bdcb5
...
@@ -136,8 +136,8 @@ class CompressViewModel{
...
@@ -136,8 +136,8 @@ class CompressViewModel{
private
func
compressSingleAsset
(
_
asset
:
PHAsset
,
_
compressionQuality
:
CGFloat
,
progress
:
@escaping
(
Float
)
->
Void
,
completion
:
@escaping
(
Data
?,
Error
?)
->
Void
)
{
private
func
compressSingleAsset
(
_
asset
:
PHAsset
,
_
compressionQuality
:
CGFloat
,
progress
:
@escaping
(
Float
)
->
Void
,
completion
:
@escaping
(
Data
?,
Error
?)
->
Void
)
{
let
options
=
PHImageRequestOptions
()
let
options
=
PHImageRequestOptions
()
options
.
isSynchronous
=
false
options
.
isSynchronous
=
false
options
.
deliveryMode
=
.
highQualityFormat
// 设置为原图片
options
.
version
=
.
original
PHImageManager
.
default
()
.
requestImageDataAndOrientation
(
for
:
asset
,
options
:
options
)
{
(
imageData
,
_
,
_
,
error
)
in
PHImageManager
.
default
()
.
requestImageDataAndOrientation
(
for
:
asset
,
options
:
options
)
{
(
imageData
,
_
,
_
,
error
)
in
guard
let
originalData
=
imageData
else
{
guard
let
originalData
=
imageData
else
{
completion
(
nil
,
nil
)
completion
(
nil
,
nil
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment