Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
galaxy-iOS
Project
Project
Details
Activity
Releases
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mobile-group
galaxy-iOS
Commits
8079abe0
Commit
8079abe0
authored
Nov 30, 2024
by
Alex朱枝文
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加直播点播入口
parent
ce194313
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
406 additions
and
152 deletions
+406
-152
YHLifeViewController.swift
...es/Modules/Home(首页)/Life(生活)/C/YHLifeViewController.swift
+5
-1
YHHomeBannerView.swift
.../galaxy/Classes/Modules/Home(首页)/V/YHHomeBannerView.swift
+75
-1
YHSelectLookView.swift
...lasses/Modules/Home(首页)/YHSelect/V/YHSelectLookView.swift
+5
-1
YHLivePlayerViewController+Api.swift
...estreamSales(直播销售)/C/YHLivePlayerViewController+Api.swift
+12
-0
YHLivePlayerViewController.swift
.../LivestreamSales(直播销售)/C/YHLivePlayerViewController.swift
+41
-0
YHLiveDetailModel.swift
...s/Modules/LivestreamSales(直播销售)/M/YHLiveDetailModel.swift
+20
-0
YHFloatingWindow.swift
...es/Modules/LivestreamSales(直播销售)/V/YHFloatingWindow.swift
+180
-149
YHLiveSalesViewModel.swift
...dules/LivestreamSales(直播销售)/VM/YHLiveSalesViewModel.swift
+42
-0
YHAllApiName.swift
galaxy/galaxy/Classes/Tools/NetWork/YHAllApiName.swift
+4
-0
Contents.json
....xcassets/YinHeLive/live_win_close.imageset/Contents.json
+22
-0
live_win_close@2x.png
...s/YinHeLive/live_win_close.imageset/live_win_close@2x.png
+0
-0
live_win_close@3x.png
...s/YinHeLive/live_win_close.imageset/live_win_close@3x.png
+0
-0
No files found.
galaxy/galaxy/Classes/Modules/Home(首页)/Life(生活)/C/YHLifeViewController.swift
View file @
8079abe0
...
...
@@ -273,7 +273,11 @@ extension YHLifeViewController: UICollectionViewDelegate, UICollectionViewDataSo
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
//跳转直播 文哥代办
YHShareAlertView
.
show
(
image
:
"http://gips3.baidu.com/it/u=3886271102,3123389489&fm=3028&app=3028&f=JPEG&fmt=auto?w=1280&h=960"
,
title
:
"12344"
,
subMessage
:
"12213243"
,
linkUrl
:
"https://www.baidu.com"
,
isLive
:
true
)
guard
self
.
viewModel
.
liveArr
.
count
>
indexPath
.
row
else
{
return
}
let
item
=
self
.
viewModel
.
liveArr
[
indexPath
.
row
]
YHPlayerManager
.
shared
.
enterLive
(
from
:
nil
,
id
:
item
.
id
,
url
:
item
.
pull_url
,
title
:
item
.
live_title
,
roomId
:
item
.
room_id
)
}
}
...
...
galaxy/galaxy/Classes/Modules/Home(首页)/V/YHHomeBannerView.swift
View file @
8079abe0
...
...
@@ -24,8 +24,14 @@ class YHHomeBannerView: UIView {
self
.
indicatorView
.
curIndicatorIndex
=
0
// 指定显示图片为第一个
bannerView
.
selectItem
(
at
:
0
,
animated
:
false
)
let
noNeedAutoScroll
=
dataArr
.
contains
(
where
:
{
$0
.
skip_type
==
100
||
$0
.
skip_type
==
102
})
// // TODO: - alex测试
// noNeedAutoScroll = true
// // TODO: - alex测试
// 开启定时器开始滚动
bannerView
.
automaticSlidingInterval
=
bannerSildingInterval
bannerView
.
automaticSlidingInterval
=
noNeedAutoScroll
?
0
:
bannerSildingInterval
bannerView
.
removesInfiniteLoopForSingleItem
=
true
bannerView
.
alwaysBounceHorizontal
=
true
}
...
...
@@ -132,6 +138,13 @@ extension YHHomeBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
if
model
.
isLocalItemFlag
{
return
}
// // TODO: - alex测试
// if index == 1 {
// let cell: YHHomeBannerCollectionViewCell? = pagerView.cellForItem(at: index) as? YHHomeBannerCollectionViewCell
// YHPlayerManager.shared.enterLive(from: cell?.bannerImagV, id: 23, url: "https://pull-flv-l6.douyincdn.com/stage/stream-116295918585905183.flv?k=e21f1ae1e7591521&t=1733551151&major_anchor_level=common&abr_pts=-800&_session_id=037-202411301359108030CAEAC1F742805E6D.1732946351732.18942&rsi=1", title: nil, roomId: nil, type: .secondary)
// return
// }
// // TODO: - alex测试
if
model
.
skip_url
.
isEmpty
==
false
{
switch
model
.
skip_type
{
case
1
:
//跳转H5
...
...
@@ -201,6 +214,7 @@ extension YHHomeBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
vc
.
url
=
model
.
skip_url
self
.
parentViewController
?
.
navigationController
?
.
pushViewController
(
vc
)
case
100
:
// 直播
//文哥
// media_type 投放类型:1 图片,2 直播
// live_id 直播ID
// live_status 直播状态 1:直播中 2:未直播 0:未知状态 3:结束直播
...
...
@@ -208,11 +222,17 @@ extension YHHomeBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
// live_pull_url 直播拉流链接
// video_url 视频链接
// recorded_cate_id 录播分类id
let
cell
:
YHHomeBannerCollectionViewCell
?
=
pagerView
.
cellForItem
(
at
:
index
)
as?
YHHomeBannerCollectionViewCell
YHPlayerManager
.
shared
.
enterLive
(
from
:
cell
?
.
bannerImagV
,
id
:
model
.
live_id
,
url
:
model
.
live_pull_url
,
title
:
nil
,
roomId
:
nil
,
type
:
.
secondary
)
printLog
(
"跳转直播"
)
case
101
:
//录播
printLog
(
"跳转录播"
)
let
cell
:
YHHomeBannerCollectionViewCell
?
=
pagerView
.
cellForItem
(
at
:
index
)
as?
YHHomeBannerCollectionViewCell
YHPlayerManager
.
shared
.
enterVOD
(
from
:
cell
?
.
bannerImagV
,
id
:
model
.
live_id
,
url
:
model
.
video_url
,
title
:
nil
,
type
:
.
secondary
)
case
102
:
//图片直播
printLog
(
"跳转录播"
)
let
cell
:
YHHomeBannerCollectionViewCell
?
=
pagerView
.
cellForItem
(
at
:
index
)
as?
YHHomeBannerCollectionViewCell
YHPlayerManager
.
shared
.
enterLive
(
from
:
cell
?
.
bannerImagV
,
id
:
model
.
live_id
,
url
:
model
.
live_pull_url
,
title
:
nil
,
roomId
:
nil
,
type
:
.
secondary
)
case
0
:
//0 不需要跳转
printLog
(
"0 不需要跳转"
)
default
:
...
...
@@ -233,4 +253,58 @@ extension YHHomeBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
func
pagerViewDidEndScrollAnimation
(
_
pagerView
:
FSPagerView
)
{
self
.
indicatorView
.
curIndicatorIndex
=
pagerView
.
currentIndex
}
func
pagerView
(
_
pagerView
:
FSPagerView
,
willDisplay
cell
:
FSPagerViewCell
,
forItemAt
index
:
Int
)
{
if
index
>=
dataArr
.
count
{
return
}
let
model
=
dataArr
[
index
]
if
model
.
isLocalItemFlag
{
return
}
// // TODO: - alex测试
// if let cell = cell as? YHHomeBannerCollectionViewCell {
// if index == 1 {
// YHPlayerManager.shared.play(url: "https://pull-flv-l11.douyincdn.com/thirdgame/stream-404525958790382412.flv?expire=1733554587&sign=d1e9f927e20f4a3fb4e2dd2a2712e256&major_anchor_level=common&abr_pts=-800&_session_id=037-20241130145626DBDEB00EB11CB388DD95.1732949787574.66743&rsi=1", inView: cell.bannerImagV, title: nil, type: .secondary)
// } else {
// let player = YHPlayerManager.shared.getPlayer(.secondary)
// player?.setPlayView(nil)
// }
// return
// }
// // TODO: - alex测试
if
model
.
skip_url
.
isEmpty
==
false
{
if
let
cell
=
cell
as?
YHHomeBannerCollectionViewCell
{
if
model
.
skip_type
==
100
{
YHPlayerManager
.
shared
.
play
(
url
:
model
.
live_pull_url
,
inView
:
cell
.
bannerImagV
,
title
:
nil
,
type
:
.
secondary
)
}
else
{
let
player
=
YHPlayerManager
.
shared
.
getPlayer
(
.
secondary
)
player
?
.
setPlayView
(
nil
)
}
}
}
}
func
pagerView
(
_
pagerView
:
FSPagerView
,
didEndDisplaying
cell
:
FSPagerViewCell
,
forItemAt
index
:
Int
)
{
if
index
>=
dataArr
.
count
{
return
}
let
model
=
dataArr
[
index
]
if
model
.
isLocalItemFlag
{
return
}
// // TODO: - alex测试
// if index == 1 {
// YHPlayerManager.shared.stop(type: .secondary)
// return
// }
// // TODO: - alex测试
if
model
.
skip_url
.
isEmpty
==
false
{
if
model
.
skip_type
==
100
{
YHPlayerManager
.
shared
.
stop
(
type
:
.
secondary
)
}
}
}
}
galaxy/galaxy/Classes/Modules/Home(首页)/YHSelect/V/YHSelectLookView.swift
View file @
8079abe0
...
...
@@ -90,7 +90,11 @@ extension YHSelectLookView: UICollectionViewDelegate, UICollectionViewDataSource
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
//跳转直播 文哥代办
guard
items
.
count
>
indexPath
.
row
else
{
return
}
let
item
=
items
[
indexPath
.
row
]
YHPlayerManager
.
shared
.
enterLive
(
from
:
nil
,
id
:
item
.
id
,
url
:
item
.
pull_url
,
title
:
item
.
live_title
,
roomId
:
item
.
room_id
)
}
}
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHLivePlayerViewController+Api.swift
View file @
8079abe0
...
...
@@ -15,4 +15,16 @@ extension YHLivePlayerViewController {
callback
(
liveDetail
,
error
)
}
}
func
joinLiveRoom
(
id
:
Int
,
callback
:
@escaping
(
_
success
:
Bool
,
_
error
:
YHErrorModel
?)
->
Void
)
{
viewModel
.
joinLiveRoom
(
id
:
id
)
{
success
,
error
in
callback
(
success
,
error
)
}
}
func
leaveLiveRoom
(
id
:
Int
,
callback
:
@escaping
(
_
success
:
Bool
,
_
error
:
YHErrorModel
?)
->
Void
)
{
viewModel
.
leaveLiveRoom
(
id
:
id
)
{
success
,
error
in
callback
(
success
,
error
)
}
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHLivePlayerViewController.swift
View file @
8079abe0
...
...
@@ -69,6 +69,9 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
setupLiveUI
()
setupLiveNotifications
()
setupData
()
if
YHLoginManager
.
shared
.
isLogin
()
{
joinLiveRoom
(
id
:
liveId
,
callback
:
{
_
,
_
in
})
}
}
deinit
{
...
...
@@ -95,6 +98,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
topBarView
.
closeButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
quitChatRoom
()
self
?
.
leaveLiveRoom
()
YHPlayerManager
.
shared
.
stop
(
type
:
.
main
)
if
let
navigationController
=
self
?
.
navigationController
{
navigationController
.
popViewController
(
animated
:
true
)
...
...
@@ -105,6 +109,10 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
topBarView
.
zoomButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
enterFloating
()
}
topBarView
.
shareButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
shareLive
()
}
}
private
func
setupData
()
{
...
...
@@ -169,6 +177,9 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
name
:
YHIMHelper
.
didLogOutEaseIM
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLoginYH
)
,
name
:
YhConstant
.
YhNotification
.
didLoginSuccessNotifiction
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLogOutYH
)
,
name
:
YhConstant
.
YhNotification
.
didLogoutSuccessNotifiction
,
object
:
nil
)
}
// MARK: - Public Methods
...
...
@@ -207,6 +218,19 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
private
func
leaveLiveRoom
()
{
guard
YHLoginManager
.
shared
.
isLogin
()
else
{
return
}
leaveLiveRoom
(
id
:
liveId
)
{
_
,
error
in
if
let
error
=
error
{
printLog
(
"leaveLiveRoom:
\(
error
)
"
)
}
else
{
printLog
(
"leaveLiveRoom: success"
)
}
}
}
private
func
quitChatRoom
()
{
guard
let
roomId
=
roomId
else
{
return
}
...
...
@@ -219,6 +243,13 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
private
func
shareLive
()
{
guard
let
liveModel
=
viewModel
.
liveDetailModel
else
{
return
}
YHShareAlertView
.
show
(
image
:
liveModel
.
live_image
,
title
:
"@"
+
liveModel
.
account
,
subMessage
:
liveModel
.
live_title
,
linkUrl
:
liveModel
.
live_h5_url
,
isLive
:
true
)
}
// MARK: - Message Handling
private
func
handleMessageInput
(
text
:
String
,
controller
:
YHMessageInputViewController
)
{
guard
checkLogin
(),
...
...
@@ -276,6 +307,16 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
appendHistoryMessages
(
messages
)
}
@objc
private
func
didLoginYH
()
{
if
YHLoginManager
.
shared
.
isLogin
()
{
joinLiveRoom
(
id
:
liveId
,
callback
:
{
_
,
_
in
})
}
}
@objc
private
func
didLogOutYH
()
{
//
}
@objc
private
func
didLoginEaseIMSuccess
()
{
if
let
roomId
=
roomId
{
joinChatRoom
(
roomId
:
roomId
)
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/M/YHLiveDetailModel.swift
View file @
8079abe0
...
...
@@ -16,10 +16,30 @@ class YHLiveDetailModel: SmartCodable {
var
hxUid
:
String
=
""
var
access_num
:
Int
=
0
var
tips
:
String
=
""
// 1:直播中 2:未直播 0:未知状态 3:结束直播
var
status
:
Int
=
0
var
roomId
:
String
=
""
var
pullUrl
:
String
=
""
var
goods
:
[
YHLiveGoodsItem
]
=
[]
// 直播封面
var
live_image
:
String
=
""
// 直播主题
var
live_title
:
String
=
""
// h5直播地址
var
live_h5_url
:
String
=
""
// 预计开始时间
var
start_time
:
String
=
""
// 拉流地址360p
var
pull_sd1_url
:
String
=
""
// 拉流地址720p
var
pull_hd_url
:
String
=
""
// 1:直播中 2:未直播 0:未知状态 3:结束直播
var
stream_status
:
Int
=
0
// 实际开始时间
var
actual_start_time
:
String
=
""
// 实际结束时间
var
actual_end_time
:
String
=
""
required
init
()
{
}
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/V/YHFloatingWindow.swift
View file @
8079abe0
...
...
@@ -19,16 +19,16 @@ protocol YHFloatingWindowDelegate: AnyObject {
class
YHFloatingWindow
:
NSObject
{
// MARK: - Properties
weak
var
player
:
YHPlayer
?
weak
var
delegate
:
YHFloatingWindowDelegate
?
var
playbackInfo
:
YHPlayerManager
.
PlaybackInfo
?
// 视频方向
enum
VideoOrientation
{
case
portrait
// 竖屏 9:16
case
landscape
// 横屏 16:9
var
aspectRatio
:
CGFloat
{
switch
self
{
case
.
portrait
:
return
9.0
/
16.0
...
...
@@ -36,215 +36,219 @@ class YHFloatingWindow: NSObject {
}
}
}
// 窗口尺寸
private
struct
Size
{
static
let
minWidth
:
CGFloat
=
120
static
let
maxWidth
:
CGFloat
=
UIScreen
.
main
.
bounds
.
width
static
let
minHeight
:
CGFloat
=
67.5
// 16:9
static
let
maxHeight
:
CGFloat
=
UIScreen
.
main
.
bounds
.
height
static
let
defaultWidth
:
CGFloat
=
150
static
let
defaultHeight
:
CGFloat
=
84.375
// 16:9
}
private(set)
var
contentView
:
UIView
private
var
containerView
:
UIView
private
var
videoOrientation
:
VideoOrientation
=
.
landscape
// 手势相关
private
var
initialFrame
:
CGRect
=
.
zero
private
var
lastScale
:
CGFloat
=
1.0
private
var
isResizing
:
Bool
=
false
private
var
initialCenter
:
CGPoint
=
.
zero
// 缩放相关
private
var
currentScale
:
CGFloat
=
1.0
private
var
initialDistance
:
CGFloat
=
0
private
let
scaleMultiplier
:
CGFloat
=
1.5
// UI组件
private
lazy
var
closeButton
:
UIButton
=
{
let
button
=
UIButton
(
type
:
.
custom
)
button
.
setImage
(
UIImage
(
named
:
"
ico
n_close"
),
for
:
.
normal
)
button
.
setImage
(
UIImage
(
named
:
"
live_wi
n_close"
),
for
:
.
normal
)
button
.
addTarget
(
self
,
action
:
#selector(
closeButtonTapped
)
,
for
:
.
touchUpInside
)
button
.
frame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
24
,
height
:
24
)
return
button
}()
private
lazy
var
closeButtonContainer
:
UIView
=
{
let
container
=
UIView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
30
,
height
:
30
))
container
.
backgroundColor
=
.
clear
container
.
addSubview
(
closeButton
)
closeButton
.
center
=
CGPoint
(
x
:
container
.
bounds
.
width
/
2
,
y
:
container
.
bounds
.
height
/
2
)
return
container
}()
// MARK: - Initialization
override
init
()
{
// 创建容器视图
containerView
=
UIView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
Size
.
defaultWidth
,
height
:
Size
.
defaultHeight
))
// 创建内容视图
width
:
Size
.
defaultWidth
,
height
:
Size
.
defaultHeight
))
contentView
=
UIView
(
frame
:
containerView
.
bounds
)
super
.
init
()
setupUI
()
setupGestures
()
}
// MARK: - Setup
private
func
setupUI
()
{
// 容器视图设置
containerView
.
backgroundColor
=
.
black
containerView
.
layer
.
cornerRadius
=
8
containerView
.
layer
.
cornerRadius
=
3
containerView
.
clipsToBounds
=
true
containerView
.
layer
.
masksToBounds
=
true
// 添加阴影
containerView
.
layer
.
shadowColor
=
UIColor
.
black
.
cgColor
containerView
.
layer
.
shadowOffset
=
CGSize
(
width
:
0
,
height
:
2
)
containerView
.
layer
.
shadowRadius
=
4
containerView
.
layer
.
shadowOpacity
=
0.3
// 添加内容视图
containerView
.
addSubview
(
contentView
)
contentView
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
// 添加关闭按钮
containerView
.
addSubview
(
closeButton
)
closeButton
.
snp
.
makeConstraints
{
make
in
make
.
top
.
right
.
equalToSuperview
()
.
inset
(
8
)
make
.
size
.
equalTo
(
CGSize
(
width
:
24
,
height
:
24
))
}
contentView
.
translatesAutoresizingMaskIntoConstraints
=
false
NSLayoutConstraint
.
activate
([
contentView
.
leadingAnchor
.
constraint
(
equalTo
:
containerView
.
leadingAnchor
),
contentView
.
trailingAnchor
.
constraint
(
equalTo
:
containerView
.
trailingAnchor
),
contentView
.
topAnchor
.
constraint
(
equalTo
:
containerView
.
topAnchor
),
contentView
.
bottomAnchor
.
constraint
(
equalTo
:
containerView
.
bottomAnchor
)
])
containerView
.
addSubview
(
closeButtonContainer
)
closeButtonContainer
.
translatesAutoresizingMaskIntoConstraints
=
false
NSLayoutConstraint
.
activate
([
closeButtonContainer
.
topAnchor
.
constraint
(
equalTo
:
containerView
.
topAnchor
),
closeButtonContainer
.
trailingAnchor
.
constraint
(
equalTo
:
containerView
.
trailingAnchor
),
closeButtonContainer
.
widthAnchor
.
constraint
(
equalToConstant
:
30
),
closeButtonContainer
.
heightAnchor
.
constraint
(
equalToConstant
:
30
)
])
}
private
func
setupGestures
()
{
// 平移手势
let
panGesture
=
UIPanGestureRecognizer
(
target
:
self
,
action
:
#selector(
handlePan(_:)
)
)
// 缩放手势
let
pinchGesture
=
UIPinchGestureRecognizer
(
target
:
self
,
action
:
#selector(
handlePinch(_:)
)
)
// 点击手势
let
tapGesture
=
UITapGestureRecognizer
(
target
:
self
,
action
:
#selector(
handleTap(_:)
)
)
tapGesture
.
delegate
=
self
containerView
.
addGestureRecognizer
(
panGesture
)
containerView
.
addGestureRecognizer
(
pinchGesture
)
containerView
.
addGestureRecognizer
(
tapGesture
)
}
// MARK: - Public Methods
func
calculateInitialFrame
()
->
CGRect
{
// 计算浮窗的初始位置和大小
let
width
:
CGFloat
=
150
// 或其他合适的宽度
let
height
:
CGFloat
=
width
*
9
/
16
// 保持16:9比例
let
width
:
CGFloat
=
Size
.
defaultWidth
let
height
:
CGFloat
=
width
/
videoOrientation
.
aspectRatio
let
x
=
UIScreen
.
main
.
bounds
.
width
-
width
-
16
let
y
=
UIScreen
.
main
.
bounds
.
height
-
height
-
100
// 距离底部适当距离
let
y
=
UIScreen
.
main
.
bounds
.
height
-
height
-
100
return
CGRect
(
x
:
x
,
y
:
y
,
width
:
width
,
height
:
height
)
}
func
show
(
in
window
:
UIWindow
)
{
containerView
.
frame
=
calculateInitialFrame
()
window
.
addSubview
(
containerView
)
}
func
show
(
in
window
:
UIWindow
,
at
point
:
CGPoint
?
=
nil
)
{
// 设置初始位置
if
let
point
=
point
{
containerView
.
center
=
point
}
else
{
// 默认位置:右下角
containerView
.
frame
.
origin
=
CGPoint
(
x
:
window
.
bounds
.
width
-
containerView
.
bounds
.
width
-
20
,
y
:
window
.
bounds
.
height
-
containerView
.
bounds
.
height
-
100
)
}
window
.
addSubview
(
containerView
)
// 显示动画
containerView
.
alpha
=
0
// containerView.transform = CGAffineTransform(scaleX: 0.3, y: 0.3)
UIView
.
animate
(
withDuration
:
0.3
)
{
self
.
containerView
.
alpha
=
1
self
.
containerView
.
transform
=
.
identity
}
}
func
dismiss
()
{
UIView
.
animate
(
withDuration
:
0.3
,
animations
:
{
self
.
containerView
.
alpha
=
0
//self.containerView.transform = CGAffineTransform(scaleX: 0.3, y: 0.3)
})
{
_
in
self
.
containerView
.
removeFromSuperview
()
}
}
func
setVideoSize
(
_
size
:
CGSize
)
{
// 更新视频方向
let
orientation
:
VideoOrientation
=
size
.
width
>
size
.
height
?
.
landscape
:
.
portrait
if
orientation
!=
videoOrientation
{
videoOrientation
=
orientation
updateLayoutForOrientation
()
}
}
// MARK: - Private Methods
private
func
updateLayoutForOrientation
()
{
let
currentWidth
=
containerView
.
bounds
.
width
let
newHeight
=
currentWidth
/
videoOrientation
.
aspectRatio
UIView
.
animate
(
withDuration
:
0.3
)
{
var
frame
=
self
.
containerView
.
frame
frame
.
size
.
height
=
newHeight
self
.
containerView
.
frame
=
frame
// 通知代理
self
.
delegate
?
.
floatingWindow
(
self
,
didChangeSize
:
frame
.
size
)
}
}
private
func
snapToNearestSize
()
{
let
currentWidth
=
containerView
.
bounds
.
width
// 定义三种尺寸状态
let
smallWidth
=
Size
.
minWidth
let
mediumWidth
=
Size
.
maxWidth
*
0.5
let
largeWidth
=
Size
.
maxWidth
// 确定目标尺寸
let
targetWidth
:
CGFloat
if
currentWidth
<
(
smallWidth
+
mediumWidth
)
/
2
{
targetWidth
=
smallWidth
}
else
if
currentWidth
<
(
mediumWidth
+
largeWidth
)
/
2
{
targetWidth
=
mediumWidth
}
else
{
targetWidth
=
largeWidth
let
sizeSteps
:
[
CGFloat
]
=
[
Size
.
minWidth
,
Size
.
maxWidth
*
0.33
,
Size
.
maxWidth
*
0.5
,
Size
.
maxWidth
*
0.75
,
Size
.
maxWidth
]
var
targetWidth
=
sizeSteps
[
0
]
var
minDifference
=
abs
(
currentWidth
-
targetWidth
)
for
size
in
sizeSteps
{
let
difference
=
abs
(
currentWidth
-
size
)
if
difference
<
minDifference
{
minDifference
=
difference
targetWidth
=
size
}
}
// 计算对应高度
let
targetHeight
=
targetWidth
/
videoOrientation
.
aspectRatio
// 执行动画
UIView
.
animate
(
withDuration
:
0.3
)
{
let
centerX
=
containerView
.
center
.
x
let
centerY
=
containerView
.
center
.
y
UIView
.
animate
(
withDuration
:
0.3
,
delay
:
0
,
options
:
[
.
curveEaseOut
],
animations
:
{
var
frame
=
self
.
containerView
.
frame
frame
.
size
=
CGSize
(
width
:
targetWidth
,
height
:
targetHeight
)
frame
.
origin
.
x
=
self
.
containerView
.
center
.
x
-
targetWidth
/
2
frame
.
origin
.
y
=
self
.
containerView
.
center
.
y
-
targetHeight
/
2
frame
.
origin
.
x
=
centerX
-
targetWidth
/
2
frame
.
origin
.
y
=
centerY
-
targetHeight
/
2
self
.
containerView
.
frame
=
frame
// 通知代理
self
.
delegate
?
.
floatingWindow
(
self
,
didChangeSize
:
frame
.
size
)
}
}
)
}
// MARK: - Gesture Handlers
@objc
private
func
handlePan
(
_
gesture
:
UIPanGestureRecognizer
)
{
guard
!
isResizing
else
{
return
}
let
translation
=
gesture
.
translation
(
in
:
containerView
.
superview
)
switch
gesture
.
state
{
case
.
began
:
initialCenter
=
containerView
.
center
case
.
changed
:
var
newCenter
=
CGPoint
(
x
:
initialCenter
.
x
+
translation
.
x
,
...
...
@@ -252,113 +256,140 @@ class YHFloatingWindow: NSObject {
)
newCenter
=
adjustedPosition
(
for
:
newCenter
)
containerView
.
center
=
newCenter
// 通知代理
delegate
?
.
floatingWindow
(
self
,
didChangePosition
:
newCenter
)
case
.
ended
:
let
velocity
=
gesture
.
velocity
(
in
:
containerView
.
superview
)
handlePanEndedWithVelocity
(
velocity
)
default
:
break
}
}
@objc
private
func
handlePinch
(
_
gesture
:
UIPinchGestureRecognizer
)
{
switch
gesture
.
state
{
case
.
began
:
isResizing
=
true
initialFrame
=
containerView
.
frame
lastScale
=
1.0
currentScale
=
1.0
let
touch1
=
gesture
.
location
(
ofTouch
:
0
,
in
:
containerView
)
let
touch2
=
gesture
.
location
(
ofTouch
:
1
,
in
:
containerView
)
initialDistance
=
hypot
(
touch2
.
x
-
touch1
.
x
,
touch2
.
y
-
touch1
.
y
)
case
.
changed
:
let
scale
=
gesture
.
scale
/
lastScale
let
newWidth
=
initialFrame
.
width
*
scale
let
touch1
=
gesture
.
location
(
ofTouch
:
0
,
in
:
containerView
)
let
touch2
=
gesture
.
location
(
ofTouch
:
1
,
in
:
containerView
)
let
currentDistance
=
hypot
(
touch2
.
x
-
touch1
.
x
,
touch2
.
y
-
touch1
.
y
)
let
scale
=
(
currentDistance
/
initialDistance
)
*
scaleMultiplier
let
scaleDelta
=
scale
/
currentScale
currentScale
=
scale
let
newWidth
=
initialFrame
.
width
*
scaleDelta
let
newHeight
=
newWidth
/
videoOrientation
.
aspectRatio
var
newFrame
=
initialFrame
newFrame
.
size
=
constrainSize
(
CGSize
(
width
:
newWidth
,
height
:
newHeight
))
newFrame
.
origin
.
x
=
containerView
.
center
.
x
-
newFrame
.
width
/
2
newFrame
.
origin
.
y
=
containerView
.
center
.
y
-
newFrame
.
height
/
2
let
centerX
=
containerView
.
center
.
x
let
centerY
=
containerView
.
center
.
y
newFrame
.
origin
.
x
=
centerX
-
newFrame
.
width
/
2
newFrame
.
origin
.
y
=
centerY
-
newFrame
.
height
/
2
CATransaction
.
begin
()
CATransaction
.
setDisableActions
(
true
)
containerView
.
frame
=
newFrame
// 通知代理
CATransaction
.
commit
()
delegate
?
.
floatingWindow
(
self
,
didChangeSize
:
newFrame
.
size
)
case
.
ended
:
case
.
ended
,
.
cancelled
:
isResizing
=
false
snapToNearestSize
()
default
:
break
}
}
@objc
private
func
handleTap
(
_
gesture
:
UITapGestureRecognizer
)
{
let
location
=
gesture
.
location
(
in
:
containerView
)
if
closeButtonContainer
.
frame
.
contains
(
location
)
{
return
}
delegate
?
.
floatingWindowDidTap
(
self
)
}
@objc
private
func
closeButtonTapped
()
{
delegate
?
.
floatingWindowDidClose
(
self
)
dismiss
()
}
// MARK: - Helper Methods
private
func
constrainSize
(
_
size
:
CGSize
)
->
CGSize
{
var
width
=
size
.
width
var
height
=
size
.
height
// 限制最小/最大尺寸
width
=
max
(
min
(
width
,
Size
.
maxWidth
),
Size
.
minWidth
)
if
width
<
Size
.
minWidth
{
width
=
Size
.
minWidth
}
else
if
width
>
Size
.
maxWidth
{
width
=
Size
.
maxWidth
}
height
=
width
/
videoOrientation
.
aspectRatio
if
height
>
Size
.
maxHeight
{
height
=
Size
.
maxHeight
width
=
height
*
videoOrientation
.
aspectRatio
}
return
CGSize
(
width
:
width
,
height
:
height
)
}
private
func
adjustedPosition
(
for
center
:
CGPoint
)
->
CGPoint
{
guard
let
superview
=
containerView
.
superview
else
{
return
center
}
var
adjustedCenter
=
center
let
halfWidth
=
containerView
.
bounds
.
width
/
2
let
halfHeight
=
containerView
.
bounds
.
height
/
2
// 限制不超出屏幕边界
adjustedCenter
.
x
=
min
(
max
(
halfWidth
,
adjustedCenter
.
x
),
superview
.
bounds
.
width
-
halfWidth
)
adjustedCenter
.
y
=
min
(
max
(
halfHeight
,
adjustedCenter
.
y
),
superview
.
bounds
.
height
-
halfHeight
)
// 计算实际可用区域
let
topLimit
=
superview
.
safeAreaInsets
.
top
+
halfHeight
let
bottomLimit
=
superview
.
bounds
.
height
-
superview
.
safeAreaInsets
.
bottom
-
halfHeight
// 限制不超出屏幕边界和安全区域
let
safeAreaInsets
:
UIEdgeInsets
if
#available(iOS 11.0, *)
{
safeAreaInsets
=
superview
.
safeAreaInsets
}
else
{
safeAreaInsets
=
.
zero
}
let
topLimit
=
safeAreaInsets
.
top
+
halfHeight
let
bottomLimit
=
superview
.
bounds
.
height
-
safeAreaInsets
.
bottom
-
halfHeight
adjustedCenter
.
x
=
min
(
max
(
halfWidth
,
adjustedCenter
.
x
),
superview
.
bounds
.
width
-
halfWidth
)
superview
.
bounds
.
width
-
halfWidth
)
adjustedCenter
.
y
=
min
(
max
(
topLimit
,
adjustedCenter
.
y
),
bottomLimit
)
bottomLimit
)
return
adjustedCenter
}
private
func
handlePanEndedWithVelocity
(
_
velocity
:
CGPoint
)
{
let
magnitude
=
sqrt
((
velocity
.
x
*
velocity
.
x
)
+
(
velocity
.
y
*
velocity
.
y
))
let
slideMultiplier
=
magnitude
/
200
let
slideFactor
=
0.1
*
slideMultiplier
var
finalCenter
=
CGPoint
(
x
:
containerView
.
center
.
x
+
(
velocity
.
x
*
slideFactor
),
y
:
containerView
.
center
.
y
+
(
velocity
.
y
*
slideFactor
)
)
finalCenter
=
adjustedPosition
(
for
:
finalCenter
)
UIView
.
animate
(
withDuration
:
0.3
)
{
self
.
containerView
.
center
=
finalCenter
// 通知代理
self
.
delegate
?
.
floatingWindow
(
self
,
didChangePosition
:
finalCenter
)
}
}
...
...
@@ -368,14 +399,14 @@ class YHFloatingWindow: NSObject {
extension
YHFloatingWindow
:
UIGestureRecognizerDelegate
{
func
gestureRecognizer
(
_
gestureRecognizer
:
UIGestureRecognizer
,
shouldRecognizeSimultaneouslyWith
otherGestureRecognizer
:
UIGestureRecognizer
)
->
Bool
{
shouldRecognizeSimultaneouslyWith
otherGestureRecognizer
:
UIGestureRecognizer
)
->
Bool
{
return
true
}
func
gestureRecognizer
(
_
gestureRecognizer
:
UIGestureRecognizer
,
shouldReceive
touch
:
UITouch
)
->
Bool
{
// 如果点击的是按钮,不触发点击手势
if
touch
.
view
is
UIButton
{
shouldReceive
touch
:
UITouch
)
->
Bool
{
let
location
=
touch
.
location
(
in
:
containerView
)
if
closeButtonContainer
.
frame
.
contains
(
location
)
{
return
false
}
return
true
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/VM/YHLiveSalesViewModel.swift
View file @
8079abe0
...
...
@@ -133,4 +133,46 @@ extension YHLiveSalesViewModel {
callback
(
nil
,
err
)
}
}
/*
离开直播间
*/
func
leaveLiveRoom
(
id
:
Int
,
callback
:
@escaping
(
_
success
:
Bool
,
_
error
:
YHErrorModel
?)
->
Void
)
{
let
strUrl
=
YHBaseUrlManager
.
shared
.
curURL
()
+
YHAllApiName
.
LiveSales
.
leaveLiveRoom
_
=
YHNetRequest
.
getRequest
(
url
:
strUrl
,
params
:
[
"live_id"
:
id
])
{
json
,
_
in
// 1. json字符串 转 对象
printLog
(
"model 是 ==>
\(
json
)
"
)
if
json
.
code
==
200
{
callback
(
true
,
nil
)
}
else
{
let
err
=
YHErrorModel
(
errorCode
:
Int32
(
json
.
code
),
errorMsg
:
json
.
msg
.
isEmpty
?
""
:
json
.
msg
)
callback
(
false
,
err
)
}
}
failBlock
:
{
err
in
callback
(
false
,
err
)
}
}
/*
进入直播间
*/
func
joinLiveRoom
(
id
:
Int
,
callback
:
@escaping
(
_
success
:
Bool
,
_
error
:
YHErrorModel
?)
->
Void
)
{
let
strUrl
=
YHBaseUrlManager
.
shared
.
curURL
()
+
YHAllApiName
.
LiveSales
.
joinLiveRoom
_
=
YHNetRequest
.
getRequest
(
url
:
strUrl
,
params
:
[
"live_id"
:
id
])
{
json
,
_
in
// 1. json字符串 转 对象
printLog
(
"model 是 ==>
\(
json
)
"
)
if
json
.
code
==
200
{
callback
(
true
,
nil
)
}
else
{
let
err
=
YHErrorModel
(
errorCode
:
Int32
(
json
.
code
),
errorMsg
:
json
.
msg
.
isEmpty
?
""
:
json
.
msg
)
callback
(
false
,
err
)
}
}
failBlock
:
{
err
in
callback
(
false
,
err
)
}
}
}
galaxy/galaxy/Classes/Tools/NetWork/YHAllApiName.swift
View file @
8079abe0
...
...
@@ -676,5 +676,9 @@ class YHAllApiName {
static
let
categoryList
=
"super-app/goods/category-list"
static
let
goodsList
=
"super-app/goods/list"
// 离开直播间
static
let
leaveLiveRoom
=
"super-app/live/app-live-exit"
// 进入直播间--需求登录
static
let
joinLiveRoom
=
"super-app/live/app-live-join"
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_win_close.imageset/Contents.json
0 → 100644
View file @
8079abe0
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_win_close@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_win_close@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_win_close.imageset/live_win_close@2x.png
0 → 100644
View file @
8079abe0
751 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_win_close.imageset/live_win_close@3x.png
0 → 100644
View file @
8079abe0
958 Bytes
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