Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
GeliBusinessPlatform
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
CI / CD Analytics
Repository Analytics
Value Stream Analytics
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ljy
GeliBusinessPlatform
Commits
5c1b463a
Commit
5c1b463a
authored
May 08, 2020
by
刘俊宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加JXPhotoBrowser(图片浏览器)
parent
31ddb37d
Changes
16
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1573 additions
and
0 deletions
+1573
-0
GeliBusinessPlatform.xcodeproj/project.pbxproj
GeliBusinessPlatform.xcodeproj/project.pbxproj
+64
-0
GeliBusinessPlatform.xcworkspace/xcuserdata/liujunhong.xcuserdatad/UserInterfaceState.xcuserstate
...ata/liujunhong.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowser.swift
...usinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowser.swift
+327
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserAnimatedTransitioning.swift
.../JXPhotoBrowser/JXPhotoBrowserAnimatedTransitioning.swift
+64
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserCell.swift
...essPlatform/Other/JXPhotoBrowser/JXPhotoBrowserCell.swift
+14
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserDefaultPageIndicator.swift
...r/JXPhotoBrowser/JXPhotoBrowserDefaultPageIndicator.swift
+41
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserFadeAnimator.swift
...orm/Other/JXPhotoBrowser/JXPhotoBrowserFadeAnimator.swift
+55
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserImageCell.swift
...atform/Other/JXPhotoBrowser/JXPhotoBrowserImageCell.swift
+321
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserLog.swift
...nessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserLog.swift
+41
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserNoneAnimator.swift
...orm/Other/JXPhotoBrowser/JXPhotoBrowserNoneAnimator.swift
+19
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserNumberPageIndicator.swift
...er/JXPhotoBrowser/JXPhotoBrowserNumberPageIndicator.swift
+67
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserPageIndicator.swift
...rm/Other/JXPhotoBrowser/JXPhotoBrowserPageIndicator.swift
+18
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserSmoothZoomAnimator.swift
...her/JXPhotoBrowser/JXPhotoBrowserSmoothZoomAnimator.swift
+121
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserView.swift
...essPlatform/Other/JXPhotoBrowser/JXPhotoBrowserView.swift
+261
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserZoomAnimator.swift
...orm/Other/JXPhotoBrowser/JXPhotoBrowserZoomAnimator.swift
+145
-0
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserZoomSupportedCell.swift
...ther/JXPhotoBrowser/JXPhotoBrowserZoomSupportedCell.swift
+15
-0
No files found.
GeliBusinessPlatform.xcodeproj/project.pbxproj
View file @
5c1b463a
This diff is collapsed.
Click to expand it.
GeliBusinessPlatform.xcworkspace/xcuserdata/liujunhong.xcuserdatad/UserInterfaceState.xcuserstate
View file @
5c1b463a
No preview for this file type
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowser.swift
0 → 100755
View file @
5c1b463a
This diff is collapsed.
Click to expand it.
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserAnimatedTransitioning.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserAnimatedTransitioning.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/25.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
public
protocol
JXPhotoBrowserAnimatedTransitioning
:
UIViewControllerAnimatedTransitioning
{
var
isForShow
:
Bool
{
get
set
}
var
photoBrowser
:
JXPhotoBrowser
?
{
get
set
}
var
isNavigationAnimation
:
Bool
{
get
set
}
}
private
var
isForShowKey
=
"isForShowKey"
private
var
photoBrowserKey
=
"photoBrowserKey"
extension
JXPhotoBrowserAnimatedTransitioning
{
public
var
isForShow
:
Bool
{
get
{
if
let
value
=
objc_getAssociatedObject
(
self
,
&
isForShowKey
)
as?
Bool
{
return
value
}
return
true
}
set
{
objc_setAssociatedObject
(
self
,
&
isForShowKey
,
newValue
,
.
OBJC_ASSOCIATION_ASSIGN
)
}
}
public
weak
var
photoBrowser
:
JXPhotoBrowser
?
{
get
{
return
objc_getAssociatedObject
(
self
,
&
photoBrowserKey
)
as?
JXPhotoBrowser
}
set
{
objc_setAssociatedObject
(
self
,
&
photoBrowserKey
,
newValue
,
.
OBJC_ASSOCIATION_ASSIGN
)
}
}
public
var
isNavigationAnimation
:
Bool
{
get
{
return
false
}
set
{
}
}
public
func
fastSnapshot
(
with
view
:
UIView
)
->
UIView
?
{
UIGraphicsBeginImageContextWithOptions
(
view
.
bounds
.
size
,
false
,
UIScreen
.
main
.
scale
)
view
.
drawHierarchy
(
in
:
view
.
bounds
,
afterScreenUpdates
:
false
)
let
image
=
UIGraphicsGetImageFromCurrentImageContext
()
UIGraphicsEndImageContext
()
return
UIImageView
(
image
:
image
)
}
public
func
snapshot
(
with
view
:
UIView
)
->
UIView
?
{
UIGraphicsBeginImageContextWithOptions
(
view
.
bounds
.
size
,
false
,
UIScreen
.
main
.
scale
)
guard
let
context
=
UIGraphicsGetCurrentContext
()
else
{
return
nil
}
view
.
layer
.
render
(
in
:
context
)
let
image
=
UIGraphicsGetImageFromCurrentImageContext
()
UIGraphicsEndImageContext
()
return
UIImageView
(
image
:
image
)
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserCell.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserCell.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/26.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
public
protocol
JXPhotoBrowserCell
:
UIView
{
static
func
generate
(
with
browser
:
JXPhotoBrowser
)
->
Self
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserDefaultPageIndicator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserDefaultPageIndicator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/25.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
open
class
JXPhotoBrowserDefaultPageIndicator
:
UIPageControl
,
JXPhotoBrowserPageIndicator
{
/// 页码与底部的距离
open
lazy
var
bottomPadding
:
CGFloat
=
{
if
#available(iOS 11.0, *)
,
let
window
=
UIApplication
.
shared
.
keyWindow
,
window
.
safeAreaInsets
.
bottom
>
0
{
return
20
}
return
15
}()
open
func
setup
(
with
browser
:
JXPhotoBrowser
)
{
isEnabled
=
false
}
open
func
reloadData
(
numberOfItems
:
Int
,
pageIndex
:
Int
)
{
numberOfPages
=
numberOfItems
currentPage
=
min
(
pageIndex
,
numberOfPages
-
1
)
sizeToFit
()
isHidden
=
numberOfPages
<=
1
if
let
view
=
superview
{
center
.
x
=
view
.
bounds
.
width
/
2
frame
.
origin
.
y
=
view
.
bounds
.
maxY
-
bottomPadding
-
bounds
.
height
}
}
open
func
didChanged
(
pageIndex
:
Int
)
{
currentPage
=
pageIndex
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserFadeAnimator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserFadeAnimator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/25.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
open
class
JXPhotoBrowserFadeAnimator
:
NSObject
,
JXPhotoBrowserAnimatedTransitioning
{
open
var
showDuration
:
TimeInterval
=
0.25
open
var
dismissDuration
:
TimeInterval
=
0.25
public
var
isNavigationAnimation
:
Bool
=
false
public
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
return
isForShow
?
showDuration
:
dismissDuration
}
public
func
animateTransition
(
using
transitionContext
:
UIViewControllerContextTransitioning
)
{
guard
let
browser
=
photoBrowser
else
{
transitionContext
.
completeTransition
(
!
transitionContext
.
transitionWasCancelled
)
return
}
if
isNavigationAnimation
,
isForShow
,
let
fromView
=
transitionContext
.
view
(
forKey
:
.
from
),
let
fromViewSnapshot
=
snapshot
(
with
:
fromView
),
let
toView
=
transitionContext
.
view
(
forKey
:
.
to
)
{
toView
.
insertSubview
(
fromViewSnapshot
,
at
:
0
)
}
if
isForShow
{
browser
.
maskView
.
alpha
=
0
browser
.
browserView
.
alpha
=
0
if
let
toView
=
transitionContext
.
view
(
forKey
:
.
to
)
{
transitionContext
.
containerView
.
addSubview
(
toView
)
}
}
else
{
if
isNavigationAnimation
,
let
fromView
=
transitionContext
.
view
(
forKey
:
.
from
),
let
toView
=
transitionContext
.
view
(
forKey
:
.
to
)
{
transitionContext
.
containerView
.
insertSubview
(
toView
,
belowSubview
:
fromView
)
}
}
browser
.
browserView
.
isHidden
=
true
UIView
.
animate
(
withDuration
:
transitionDuration
(
using
:
transitionContext
),
animations
:
{
browser
.
browserView
.
isHidden
=
false
browser
.
maskView
.
alpha
=
self
.
isForShow
?
1.0
:
0
browser
.
browserView
.
alpha
=
self
.
isForShow
?
1.0
:
0
})
{
_
in
transitionContext
.
completeTransition
(
!
transitionContext
.
transitionWasCancelled
)
}
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserImageCell.swift
0 → 100755
View file @
5c1b463a
This diff is collapsed.
Click to expand it.
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserLog.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserLog.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/12.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
Foundation
public
struct
JXPhotoBrowserLog
{
/// 日志重要程度等级
public
enum
Level
:
Int
{
case
low
=
0
case
middle
case
high
case
forbidden
}
/// 允许输出日志的最低等级。`forbidden`为禁止所有日志
public
static
var
level
:
Level
=
.
forbidden
public
static
func
low
(
_
item
:
@autoclosure
()
->
Any
)
{
if
level
.
rawValue
<=
Level
.
low
.
rawValue
{
print
(
"[JXPhotoBrowser] [low]"
,
item
())
}
}
public
static
func
middle
(
_
item
:
@autoclosure
()
->
Any
)
{
if
level
.
rawValue
<=
Level
.
middle
.
rawValue
{
print
(
"[JXPhotoBrowser] [middle]"
,
item
())
}
}
public
static
func
high
(
_
item
:
@autoclosure
()
->
Any
)
{
if
level
.
rawValue
<=
Level
.
high
.
rawValue
{
print
(
"[JXPhotoBrowser] [high]"
,
item
())
}
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserNoneAnimator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserNoneAnimator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/26.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
/// 使用本类以实现不出现转场动画的需求
open
class
JXPhotoBrowserNoneAnimator
:
JXPhotoBrowserFadeAnimator
{
public
override
init
()
{
super
.
init
()
showDuration
=
0
dismissDuration
=
0
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserNumberPageIndicator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserNumberPageIndicator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/25.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
open
class
JXPhotoBrowserNumberPageIndicator
:
UILabel
,
JXPhotoBrowserPageIndicator
{
/// 页码与顶部的距离
open
lazy
var
topPadding
:
CGFloat
=
{
if
#available(iOS 11.0, *)
,
let
window
=
UIApplication
.
shared
.
keyWindow
{
return
window
.
safeAreaInsets
.
top
}
return
20
}()
public
convenience
init
()
{
self
.
init
(
frame
:
.
zero
)
}
public
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
config
()
}
required
public
init
?(
coder
:
NSCoder
)
{
super
.
init
(
coder
:
coder
)
config
()
}
private
func
config
()
{
font
=
UIFont
.
systemFont
(
ofSize
:
17
)
textAlignment
=
.
center
textColor
=
UIColor
.
white
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
0.4
)
layer
.
masksToBounds
=
true
}
public
func
setup
(
with
browser
:
JXPhotoBrowser
)
{
}
private
var
total
:
Int
=
0
public
func
reloadData
(
numberOfItems
:
Int
,
pageIndex
:
Int
)
{
total
=
numberOfItems
text
=
"
\(
pageIndex
+
1
)
/
\(
total
)
"
sizeToFit
()
frame
.
size
.
width
+=
frame
.
height
layer
.
cornerRadius
=
frame
.
height
/
2
if
let
view
=
superview
{
center
.
x
=
view
.
bounds
.
width
/
2
frame
.
origin
.
y
=
topPadding
}
isHidden
=
numberOfItems
<=
1
}
public
func
didChanged
(
pageIndex
:
Int
)
{
text
=
"
\(
pageIndex
+
1
)
/
\(
total
)
"
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserPageIndicator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserPageIndicator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/25.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
public
protocol
JXPhotoBrowserPageIndicator
:
UIView
{
func
setup
(
with
browser
:
JXPhotoBrowser
)
func
reloadData
(
numberOfItems
:
Int
,
pageIndex
:
Int
)
func
didChanged
(
pageIndex
:
Int
)
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserSmoothZoomAnimator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserSmoothZoomAnimator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/26.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
/// 更丝滑的Zoom动画
open
class
JXPhotoBrowserSmoothZoomAnimator
:
NSObject
,
JXPhotoBrowserAnimatedTransitioning
{
open
var
showDuration
:
TimeInterval
=
0.25
open
var
dismissDuration
:
TimeInterval
=
0.25
open
var
isNavigationAnimation
=
false
public
typealias
TransitionViewAndFrame
=
(
transitionView
:
UIView
,
thumbnailFrame
:
CGRect
)
public
typealias
TransitionViewAndFrameProvider
=
(
_
index
:
Int
,
_
destinationView
:
UIView
)
->
TransitionViewAndFrame
?
/// 获取转场缩放的视图与前置Frame
open
var
transitionViewAndFrameProvider
:
TransitionViewAndFrameProvider
=
{
_
,
_
in
return
nil
}
/// 替补的动画方案
open
lazy
var
substituteAnimator
:
JXPhotoBrowserAnimatedTransitioning
=
JXPhotoBrowserFadeAnimator
()
public
init
(
transitionViewAndFrame
:
@escaping
TransitionViewAndFrameProvider
)
{
transitionViewAndFrameProvider
=
transitionViewAndFrame
}
public
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
return
isForShow
?
showDuration
:
dismissDuration
}
public
func
animateTransition
(
using
transitionContext
:
UIViewControllerContextTransitioning
)
{
if
isForShow
{
playShowAnimation
(
context
:
transitionContext
)
}
else
{
playDismissAnimation
(
context
:
transitionContext
)
}
}
private
func
playShowAnimation
(
context
:
UIViewControllerContextTransitioning
)
{
guard
let
browser
=
photoBrowser
else
{
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
return
}
if
isNavigationAnimation
,
let
fromView
=
context
.
view
(
forKey
:
.
from
),
let
fromViewSnapshot
=
snapshot
(
with
:
fromView
),
let
toView
=
context
.
view
(
forKey
:
.
to
)
{
toView
.
insertSubview
(
fromViewSnapshot
,
at
:
0
)
}
context
.
containerView
.
addSubview
(
browser
.
view
)
guard
let
(
transitionView
,
thumbnailFrame
,
destinationFrame
)
=
transitionViewAndFrames
(
with
:
browser
)
else
{
// 转为执行替补动画
substituteAnimator
.
isForShow
=
isForShow
substituteAnimator
.
photoBrowser
=
photoBrowser
substituteAnimator
.
isNavigationAnimation
=
isNavigationAnimation
substituteAnimator
.
animateTransition
(
using
:
context
)
return
}
browser
.
maskView
.
alpha
=
0
browser
.
browserView
.
isHidden
=
true
transitionView
.
frame
=
thumbnailFrame
context
.
containerView
.
addSubview
(
transitionView
)
UIView
.
animate
(
withDuration
:
showDuration
,
animations
:
{
browser
.
maskView
.
alpha
=
1.0
transitionView
.
frame
=
destinationFrame
})
{
_
in
browser
.
browserView
.
isHidden
=
false
browser
.
view
.
insertSubview
(
browser
.
maskView
,
belowSubview
:
browser
.
browserView
)
transitionView
.
removeFromSuperview
()
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
}
}
private
func
playDismissAnimation
(
context
:
UIViewControllerContextTransitioning
)
{
guard
let
browser
=
photoBrowser
else
{
return
}
guard
let
(
transitionView
,
thumbnailFrame
,
destinationFrame
)
=
transitionViewAndFrames
(
with
:
browser
)
else
{
// 转为执行替补动画
substituteAnimator
.
isForShow
=
isForShow
substituteAnimator
.
photoBrowser
=
photoBrowser
substituteAnimator
.
isNavigationAnimation
=
isNavigationAnimation
substituteAnimator
.
animateTransition
(
using
:
context
)
return
}
browser
.
browserView
.
isHidden
=
true
transitionView
.
frame
=
destinationFrame
context
.
containerView
.
addSubview
(
transitionView
)
UIView
.
animate
(
withDuration
:
showDuration
,
animations
:
{
browser
.
maskView
.
alpha
=
0
transitionView
.
frame
=
thumbnailFrame
})
{
_
in
if
let
toView
=
context
.
view
(
forKey
:
.
to
)
{
context
.
containerView
.
addSubview
(
toView
)
}
transitionView
.
removeFromSuperview
()
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
}
}
private
func
transitionViewAndFrames
(
with
browser
:
JXPhotoBrowser
)
->
(
UIView
,
CGRect
,
CGRect
)?
{
let
browserView
=
browser
.
browserView
let
destinationView
=
browser
.
view
!
guard
let
transitionContext
=
transitionViewAndFrameProvider
(
browser
.
pageIndex
,
destinationView
)
else
{
return
nil
}
guard
let
cell
=
browserView
.
visibleCells
[
browserView
.
pageIndex
]
as?
JXPhotoBrowserZoomSupportedCell
else
{
return
nil
}
let
showContentView
=
cell
.
showContentView
let
destinationFrame
=
showContentView
.
convert
(
showContentView
.
bounds
,
to
:
destinationView
)
return
(
transitionContext
.
transitionView
,
transitionContext
.
thumbnailFrame
,
destinationFrame
)
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserView.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserView.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/14.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
open
class
JXPhotoBrowserView
:
UIView
,
UIScrollViewDelegate
{
/// 弱引用PhotoBrowser
open
weak
var
photoBrowser
:
JXPhotoBrowser
?
/// 询问当前数据总量
open
lazy
var
numberOfItems
:
()
->
Int
=
{
0
}
/// 返回可复用的Cell类。用户可根据index返回不同的类。本闭包将在每次复用Cell时实时调用。
open
lazy
var
cellClassAtIndex
:
(
_
index
:
Int
)
->
JXPhotoBrowserCell
.
Type
=
{
_
in
JXPhotoBrowserImageCell
.
self
}
/// 刷新Cell数据。本闭包将在Cell完成位置布局后调用。
open
lazy
var
reloadCellAtIndex
:
(
JXPhotoBrowser
.
ReloadCellContext
)
->
Void
=
{
_
in
}
/// 自然滑动引起的页码改变时回调
open
lazy
var
didChangedPageIndex
:
(
_
index
:
Int
)
->
Void
=
{
_
in
}
/// Cell将显示
open
lazy
var
cellWillAppear
:
(
JXPhotoBrowserCell
,
Int
)
->
Void
=
{
_
,
_
in
}
/// Cell将不显示
open
lazy
var
cellWillDisappear
:
(
JXPhotoBrowserCell
,
Int
)
->
Void
=
{
_
,
_
in
}
/// Cell已显示
open
lazy
var
cellDidAppear
:
(
JXPhotoBrowserCell
,
Int
)
->
Void
=
{
_
,
_
in
}
/// 滑动方向
open
var
scrollDirection
:
JXPhotoBrowser
.
ScrollDirection
=
.
horizontal
/// 项间距
open
var
itemSpacing
:
CGFloat
=
30
/// 当前页码。给本属性赋值不会触发`didChangedPageIndex`闭包。
open
var
pageIndex
=
0
{
didSet
{
if
pageIndex
!=
oldValue
{
isPageIndexChanged
=
true
}
}
}
/// 页码是否已改变
public
var
isPageIndexChanged
=
true
/// 容器
open
lazy
var
scrollView
:
UIScrollView
=
{
let
sv
=
UIScrollView
()
sv
.
backgroundColor
=
.
clear
sv
.
showsVerticalScrollIndicator
=
false
sv
.
showsHorizontalScrollIndicator
=
false
sv
.
isPagingEnabled
=
true
sv
.
isScrollEnabled
=
true
sv
.
delegate
=
self
if
#available(iOS 11.0, *)
{
sv
.
contentInsetAdjustmentBehavior
=
.
never
}
return
sv
}()
var
isRotating
=
false
deinit
{
JXPhotoBrowserLog
.
low
(
"deinit -
\(
self
.
classForCoder
)
"
)
}
public
convenience
init
()
{
self
.
init
(
frame
:
.
zero
)
}
public
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
setup
()
}
public
required
init
?(
coder
:
NSCoder
)
{
super
.
init
(
coder
:
coder
)
setup
()
}
open
func
setup
()
{
backgroundColor
=
.
clear
addSubview
(
scrollView
)
}
open
override
func
layoutSubviews
()
{
super
.
layoutSubviews
()
if
scrollDirection
==
.
horizontal
{
scrollView
.
frame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
bounds
.
width
+
itemSpacing
,
height
:
bounds
.
height
)
}
else
{
scrollView
.
frame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
bounds
.
width
,
height
:
bounds
.
height
+
itemSpacing
)
}
reloadData
()
}
open
func
resetContentSize
()
{
let
maxIndex
=
CGFloat
(
numberOfItems
())
if
scrollDirection
==
.
horizontal
{
scrollView
.
contentSize
=
CGSize
(
width
:
scrollView
.
frame
.
width
*
maxIndex
,
height
:
scrollView
.
frame
.
height
)
}
else
{
scrollView
.
contentSize
=
CGSize
(
width
:
scrollView
.
frame
.
width
,
height
:
scrollView
.
frame
.
height
*
maxIndex
)
}
}
/// 刷新数据,同时刷新Cell布局
open
func
reloadData
()
{
// 修正pageIndex,同步数据源的变更
pageIndex
=
max
(
0
,
pageIndex
)
pageIndex
=
min
(
pageIndex
,
numberOfItems
())
resetContentSize
()
resetCells
()
layoutCells
()
reloadItems
()
refreshContentOffset
()
}
/// 根据页码更新滑动位置
open
func
refreshContentOffset
()
{
if
scrollDirection
==
.
horizontal
{
scrollView
.
contentOffset
=
CGPoint
(
x
:
CGFloat
(
pageIndex
)
*
scrollView
.
bounds
.
width
,
y
:
0
)
}
else
{
scrollView
.
contentOffset
=
CGPoint
(
x
:
0
,
y
:
CGFloat
(
pageIndex
)
*
scrollView
.
bounds
.
height
)
}
}
open
func
scrollViewDidScroll
(
_
scrollView
:
UIScrollView
)
{
// 屏幕旋转时会触发本方法。此时不可更改pageIndex
if
isRotating
{
isRotating
=
false
return
}
if
scrollDirection
==
.
horizontal
&&
scrollView
.
bounds
.
width
>
0
{
pageIndex
=
Int
(
round
(
scrollView
.
contentOffset
.
x
/
(
scrollView
.
bounds
.
width
)))
}
else
if
scrollDirection
==
.
vertical
&&
scrollView
.
bounds
.
height
>
0
{
pageIndex
=
Int
(
round
(
scrollView
.
contentOffset
.
y
/
(
scrollView
.
bounds
.
height
)))
}
if
isPageIndexChanged
{
isPageIndexChanged
=
false
resetCells
()
layoutCells
()
reloadItems
()
didChangedPageIndex
(
pageIndex
)
}
}
public
func
scrollViewDidEndDecelerating
(
_
scrollView
:
UIScrollView
)
{
if
let
cell
=
visibleCells
[
pageIndex
]
{
cellDidAppear
(
cell
,
pageIndex
)
}
}
//
// MARK: - 复用Cell
//
/// 显示中的Cell
open
var
visibleCells
=
[
Int
:
JXPhotoBrowserCell
]()
/// 缓存中的Cell
open
var
reusableCells
=
[
String
:
[
JXPhotoBrowserCell
]]()
/// 入队
private
func
enqueue
(
cell
:
JXPhotoBrowserCell
)
{
let
name
=
String
(
describing
:
cell
.
classForCoder
)
if
var
array
=
reusableCells
[
name
]
{
array
.
append
(
cell
)
reusableCells
[
name
]
=
array
}
else
{
reusableCells
[
name
]
=
[
cell
]
}
}
/// 出队,没缓存则新建
private
func
dequeue
(
cellType
:
JXPhotoBrowserCell
.
Type
,
browser
:
JXPhotoBrowser
)
->
JXPhotoBrowserCell
{
var
cell
:
JXPhotoBrowserCell
let
name
=
String
(
describing
:
cellType
.
classForCoder
())
if
var
array
=
reusableCells
[
name
],
array
.
count
>
0
{
JXPhotoBrowserLog
.
middle
(
"命中缓存!
\(
name
)
"
)
cell
=
array
.
removeFirst
()
reusableCells
[
name
]
=
array
}
else
{
JXPhotoBrowserLog
.
middle
(
"新建Cell!
\(
name
)
"
)
cell
=
cellType
.
generate
(
with
:
browser
)
}
return
cell
}
/// 重置所有Cell的位置。更新 visibleCells 和 reusableCells
open
func
resetCells
()
{
guard
let
browser
=
photoBrowser
else
{
return
}
var
removeFromVisibles
=
[
Int
]()
for
(
index
,
cell
)
in
visibleCells
{
if
index
==
pageIndex
{
continue
}
cellWillDisappear
(
cell
,
index
)
cell
.
removeFromSuperview
()
enqueue
(
cell
:
cell
)
removeFromVisibles
.
append
(
index
)
}
removeFromVisibles
.
forEach
{
visibleCells
.
removeValue
(
forKey
:
$0
)
}
// 添加要显示的cell
let
itemsTotalCount
=
numberOfItems
()
for
index
in
(
pageIndex
-
1
)
...
(
pageIndex
+
1
)
{
if
index
<
0
||
index
>
itemsTotalCount
-
1
{
continue
}
if
index
==
pageIndex
&&
visibleCells
[
index
]
!=
nil
{
continue
}
let
clazz
=
cellClassAtIndex
(
index
)
JXPhotoBrowserLog
.
middle
(
"Required class name:
\(
String
(
describing
:
clazz
)
)
"
)
JXPhotoBrowserLog
.
middle
(
"index:
\(
index
)
出队!"
)
let
cell
=
dequeue
(
cellType
:
clazz
,
browser
:
browser
)
visibleCells
[
index
]
=
cell
scrollView
.
addSubview
(
cell
)
}
}
/// 刷新所有显示中的Cell位置
open
func
layoutCells
()
{
let
cellWidth
=
bounds
.
width
let
cellHeight
=
bounds
.
height
for
(
index
,
cell
)
in
visibleCells
{
if
scrollDirection
==
.
horizontal
{
cell
.
frame
=
CGRect
(
x
:
CGFloat
(
index
)
*
(
cellWidth
+
itemSpacing
),
y
:
0
,
width
:
cellWidth
,
height
:
cellHeight
)
}
else
{
cell
.
frame
=
CGRect
(
x
:
0
,
y
:
CGFloat
(
index
)
*
(
cellHeight
+
itemSpacing
),
width
:
cellWidth
,
height
:
cellHeight
)
}
}
}
/// 刷新所有Cell的数据
open
func
reloadItems
()
{
visibleCells
.
forEach
{
[
weak
self
]
index
,
cell
in
guard
let
`
self
`
=
self
else
{
return
}
self
.
reloadCellAtIndex
((
cell
,
index
,
self
.
pageIndex
))
cell
.
setNeedsLayout
()
}
if
let
cell
=
visibleCells
[
pageIndex
]
{
cellWillAppear
(
cell
,
pageIndex
)
}
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserZoomAnimator.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserZoomAnimator.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/26.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
/// Zoom动画
open
class
JXPhotoBrowserZoomAnimator
:
NSObject
,
JXPhotoBrowserAnimatedTransitioning
{
open
var
showDuration
:
TimeInterval
=
0.25
open
var
dismissDuration
:
TimeInterval
=
0.25
open
var
isNavigationAnimation
=
false
public
typealias
PreviousViewAtIndexClosure
=
(
_
index
:
Int
)
->
UIView
?
/// 转场动画的前向视图
open
var
previousViewProvider
:
PreviousViewAtIndexClosure
=
{
_
in
return
nil
}
/// 替补的动画方案
open
lazy
var
substituteAnimator
:
JXPhotoBrowserAnimatedTransitioning
=
JXPhotoBrowserFadeAnimator
()
public
init
(
previousView
:
@escaping
PreviousViewAtIndexClosure
)
{
previousViewProvider
=
previousView
}
public
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
return
isForShow
?
showDuration
:
dismissDuration
}
public
func
animateTransition
(
using
transitionContext
:
UIViewControllerContextTransitioning
)
{
if
isForShow
{
playShowAnimation
(
context
:
transitionContext
)
}
else
{
playDismissAnimation
(
context
:
transitionContext
)
}
}
private
func
playShowAnimation
(
context
:
UIViewControllerContextTransitioning
)
{
guard
let
browser
=
photoBrowser
else
{
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
return
}
if
isNavigationAnimation
,
let
fromView
=
context
.
view
(
forKey
:
.
from
),
let
fromViewSnapshot
=
snapshot
(
with
:
fromView
),
let
toView
=
context
.
view
(
forKey
:
.
to
)
{
toView
.
insertSubview
(
fromViewSnapshot
,
at
:
0
)
}
context
.
containerView
.
addSubview
(
browser
.
view
)
guard
let
(
snap1
,
snap2
,
thumbnailFrame
,
destinationFrame
)
=
snapshotsAndFrames
(
browser
:
browser
)
else
{
// 转为执行替补动画
substituteAnimator
.
isForShow
=
isForShow
substituteAnimator
.
photoBrowser
=
photoBrowser
substituteAnimator
.
isNavigationAnimation
=
isNavigationAnimation
substituteAnimator
.
animateTransition
(
using
:
context
)
return
}
snap1
.
frame
=
thumbnailFrame
snap2
.
frame
=
thumbnailFrame
snap2
.
alpha
=
0
browser
.
maskView
.
alpha
=
0
browser
.
browserView
.
isHidden
=
true
context
.
containerView
.
addSubview
(
snap1
)
context
.
containerView
.
addSubview
(
snap2
)
UIView
.
animate
(
withDuration
:
showDuration
,
animations
:
{
browser
.
maskView
.
alpha
=
1.0
snap1
.
frame
=
destinationFrame
snap1
.
alpha
=
0
snap2
.
frame
=
destinationFrame
snap2
.
alpha
=
1.0
})
{
_
in
browser
.
browserView
.
isHidden
=
false
browser
.
view
.
insertSubview
(
browser
.
maskView
,
belowSubview
:
browser
.
browserView
)
snap1
.
removeFromSuperview
()
snap2
.
removeFromSuperview
()
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
}
}
private
func
playDismissAnimation
(
context
:
UIViewControllerContextTransitioning
)
{
guard
let
browser
=
photoBrowser
else
{
return
}
guard
let
(
snap1
,
snap2
,
thumbnailFrame
,
destinationFrame
)
=
snapshotsAndFrames
(
browser
:
browser
)
else
{
// 转为执行替补动画
substituteAnimator
.
isForShow
=
isForShow
substituteAnimator
.
photoBrowser
=
photoBrowser
substituteAnimator
.
isNavigationAnimation
=
isNavigationAnimation
substituteAnimator
.
animateTransition
(
using
:
context
)
return
}
snap1
.
frame
=
destinationFrame
snap1
.
alpha
=
0
snap2
.
frame
=
destinationFrame
context
.
containerView
.
addSubview
(
snap1
)
context
.
containerView
.
addSubview
(
snap2
)
browser
.
browserView
.
isHidden
=
true
UIView
.
animate
(
withDuration
:
showDuration
,
animations
:
{
browser
.
maskView
.
alpha
=
0
snap1
.
frame
=
thumbnailFrame
snap1
.
alpha
=
0
snap2
.
frame
=
thumbnailFrame
snap2
.
alpha
=
1.0
})
{
_
in
if
let
toView
=
context
.
view
(
forKey
:
.
to
)
{
context
.
containerView
.
addSubview
(
toView
)
}
snap1
.
removeFromSuperview
()
snap2
.
removeFromSuperview
()
context
.
completeTransition
(
!
context
.
transitionWasCancelled
)
}
}
private
func
snapshotsAndFrames
(
browser
:
JXPhotoBrowser
)
->
(
UIView
,
UIView
,
CGRect
,
CGRect
)?
{
let
browserView
=
browser
.
browserView
let
view
=
browser
.
view
let
closure
=
previousViewProvider
guard
let
previousView
=
closure
(
browserView
.
pageIndex
)
else
{
return
nil
}
guard
let
cell
=
browserView
.
visibleCells
[
browserView
.
pageIndex
]
as?
JXPhotoBrowserZoomSupportedCell
else
{
return
nil
}
let
thumbnailFrame
=
previousView
.
convert
(
previousView
.
bounds
,
to
:
view
)
let
showContentView
=
cell
.
showContentView
// 两Rect求交集,得出显示中的区域
let
destinationFrame
=
cell
.
convert
(
cell
.
bounds
.
intersection
(
showContentView
.
frame
),
to
:
view
)
guard
let
snap1
=
fastSnapshot
(
with
:
previousView
)
else
{
JXPhotoBrowserLog
.
high
(
"取不到前截图!"
)
return
nil
}
guard
let
snap2
=
snapshot
(
with
:
cell
.
showContentView
)
else
{
JXPhotoBrowserLog
.
high
(
"取不到后截图!"
)
return
nil
}
return
(
snap1
,
snap2
,
thumbnailFrame
,
destinationFrame
)
}
}
GeliBusinessPlatform/Other/JXPhotoBrowser/JXPhotoBrowserZoomSupportedCell.swift
0 → 100755
View file @
5c1b463a
//
// JXPhotoBrowserZoomSupportedCell.swift
// JXPhotoBrowser
//
// Created by JiongXing on 2019/11/22.
// Copyright © 2019 JiongXing. All rights reserved.
//
import
UIKit
/// 在Zoom转场时使用
protocol
JXPhotoBrowserZoomSupportedCell
:
UIView
{
/// 内容视图
var
showContentView
:
UIView
{
get
}
}
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