Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
pidan
/
FuSiLive
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
cebed0a8
authored
Mar 25, 2026
by
suolong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
用户进入限时表演窗口
parent
b6f574a1
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
784 additions
and
8 deletions
Modules/FUSShowRoomModule/FUSShowRoomModule.xcodeproj/project.pbxproj
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/FUSLiveShowTimeTicketActionPopView.m
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/ShowTimeAudienceEntry/FUSLiveShowTimeAudienceEntryMainView.h
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/ShowTimeAudienceEntry/FUSLiveShowTimeAudienceEntryMainView.m
Modules/FUSShowRoomModule/FUSShowRoomModule.xcodeproj/project.pbxproj
View file @
cebed0a8
...
...
@@ -1494,6 +1494,8 @@
BED659092C5B745E00668116
/* FUSLiveChatInputToolView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED656062C5B745D00668116
/* FUSLiveChatInputToolView.swift */
;
};
BED6590A2C5B745E00668116
/* FUSLiveChatInputView.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED656072C5B745D00668116
/* FUSLiveChatInputView.h */
;
};
BED6590B2C5B745E00668116
/* FUSLiveChatInputView.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED656082C5B745D00668116
/* FUSLiveChatInputView.m */
;
};
00F7AA012FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
00F7AA032FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.h */
;
};
00F7AA022FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
00F7AA042FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.m */
;
};
BED6590C2C5B745E00668116
/* FUSLiveChatToolGiftTipView.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED656092C5B745D00668116
/* FUSLiveChatToolGiftTipView.h */
;
};
BED6590D2C5B745E00668116
/* FUSLiveChatToolGiftTipView.m in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED6560A2C5B745D00668116
/* FUSLiveChatToolGiftTipView.m */
;
};
BED6590E2C5B745E00668116
/* FUSLiveShareView.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
BED6560B2C5B745D00668116
/* FUSLiveShareView.h */
;
};
...
...
@@ -3918,6 +3920,8 @@
BED656062C5B745D00668116
/* FUSLiveChatInputToolView.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
FUSLiveChatInputToolView.swift
;
sourceTree
=
"<group>"
;
};
BED656072C5B745D00668116
/* FUSLiveChatInputView.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
FUSLiveChatInputView.h
;
sourceTree
=
"<group>"
;
};
BED656082C5B745D00668116
/* FUSLiveChatInputView.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
FUSLiveChatInputView.m
;
sourceTree
=
"<group>"
;
};
00F7AA032FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
FUSLiveShowTimeAudienceEntryMainView.h
;
sourceTree
=
"<group>"
;
};
00F7AA042FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
FUSLiveShowTimeAudienceEntryMainView.m
;
sourceTree
=
"<group>"
;
};
BED656092C5B745D00668116
/* FUSLiveChatToolGiftTipView.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
FUSLiveChatToolGiftTipView.h
;
sourceTree
=
"<group>"
;
};
BED6560A2C5B745D00668116
/* FUSLiveChatToolGiftTipView.m */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.objc
;
path
=
FUSLiveChatToolGiftTipView.m
;
sourceTree
=
"<group>"
;
};
BED6560B2C5B745D00668116
/* FUSLiveShareView.h */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.c.h
;
path
=
FUSLiveShareView.h
;
sourceTree
=
"<group>"
;
};
...
...
@@ -6921,6 +6925,7 @@
00E6CB0A2F4D509F00B63797
/* FUSLiveChatInputToolCell.swift */
,
BED656072C5B745D00668116
/* FUSLiveChatInputView.h */
,
BED656082C5B745D00668116
/* FUSLiveChatInputView.m */
,
00F7AA052FA1234500AA0001
/* ShowTimeAudienceEntry */
,
BED656092C5B745D00668116
/* FUSLiveChatToolGiftTipView.h */
,
BED6560A2C5B745D00668116
/* FUSLiveChatToolGiftTipView.m */
,
BED6560B2C5B745D00668116
/* FUSLiveShareView.h */
,
...
...
@@ -6939,6 +6944,15 @@
path
=
ChatInputView
;
sourceTree
=
"<group>"
;
};
00F7AA052FA1234500AA0001
/* ShowTimeAudienceEntry */
=
{
isa
=
PBXGroup
;
children
=
(
00F7AA032FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.h */
,
00F7AA042FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.m */
,
);
path
=
ShowTimeAudienceEntry
;
sourceTree
=
"<group>"
;
};
00F7FF882FB1000100AAAA09
/* ShowTimePopups */
=
{
isa
=
PBXGroup
;
children
=
(
...
...
@@ -9167,6 +9181,7 @@
BE189E252C733B460008418B
/* FSRLinkmicdictActiveView.h in Headers */
,
BED658A92C5B745E00668116
/* FUSVideoEndedView.h in Headers */
,
BED6590A2C5B745E00668116
/* FUSLiveChatInputView.h in Headers */
,
00F7AA012FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.h in Headers */
,
);
runOnlyForDeploymentPostprocessing
=
0
;
};
...
...
@@ -10968,6 +10983,7 @@
BED6586E2C5B745E00668116
/* VELPictureInPictureController.m in Sources */
,
BED65A992C5B745F00668116
/* FUSLiveManagerCell.m in Sources */
,
BED6590B2C5B745E00668116
/* FUSLiveChatInputView.m in Sources */
,
00F7AA022FA1234500AA0001
/* FUSLiveShowTimeAudienceEntryMainView.m in Sources */
,
00E6CB272F4E9AB800B63797
/* FUSLiveReleasePunishmentView.m in Sources */
,
00E6CB282F4E9AB800B63797
/* FUSLiveGlobalSpecialEffectView.m in Sources */
,
00E6CB292F4E9AB800B63797
/* FUSLivePunishListCell.m in Sources */
,
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m
View file @
cebed0a8
...
...
@@ -32,6 +32,8 @@
#import "FUSPayRoomCompanionDataModel.h"
#import "FUSPayRoomCompanionPopView.h"
#import "FUSRechargeViewController.h"
#import "FUSLiveShowTimeAudienceEntryMainView.h"
#import "FUSTicketShowCollectTicketToggleResultModel.h"
#import <FirebaseAnalytics/FirebaseAnalytics.h>
...
...
@@ -999,6 +1001,28 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
errorDict
[
@"msg"
]
cancelButtonTitle
:
[
NSString
fus_localString
:
@"确定"
]
otherButtonTitles
:
nil
clickBlock
:^
(
NSInteger
buttonIndex
)
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}];
}
else
if
(
code
==
-
40013
)
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
FUSStreamPlayStatus
status
=
[
self
.
liveVC
.
playView
fus_statusForUID
:
currentRoomId
];
if
(
status
==
FUSStreamPlayStatusPlaying
||
status
==
FUSStreamPlayStatusLoading
||
status
==
FUSStreamPlayStatusPause
)
{
[
self
.
liveVC
.
playView
fus_stopWithUID
:
currentRoomId
];
[
self
.
liveVC
.
playView
fus_destroyAllPlayer
];
[
self
.
liveVC
fus_stopPlay
];
[
self
.
liveVC
destroyPlayPictureInPicture
];
}
UIView
*
rootView
=
self
.
liveVC
.
view
?:
[
UIViewController
fus_topViewController
].
view
;
FUSLiveShowTimeAudienceEntryMainView
*
entry
=
[
FUSLiveShowTimeAudienceEntryMainView
fus_showOnView
:
rootView
actionHandler
:
^
(
FUSLiveShowTimeAudienceEntryMainViewAction
action
,
NSInteger
selectedOptionIndex
)
{
if
(
action
==
FUSLiveShowTimeAudienceEntryMainViewActionDismiss
)
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}
}];
NSString
*
channelId
=
[[
errorDict
[
@"channelId"
]
description
]
?:
@""
copy
];
NSString
*
roundId
=
[[
errorDict
[
@"roundId"
]
description
]
?:
@""
copy
];
[
self
fus_requestTicketShowBuyGetDataAndFillEntry
:
entry
roomId
:
currentRoomId
channelId
:
channelId
roundId
:
roundId
];
});
return
;
}
else
{
// 其他情况
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
msg
cancelButtonTitle
:
nil
otherButtonTitles
:
@[[
NSString
fus_localString
:
@"确定"
],
[
NSString
fus_localString
:
@"退出"
]]
clickBlock
:^
(
NSInteger
buttonIndex
)
{
...
...
@@ -1016,6 +1040,28 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
}
}
/// 请求 /ticketshow/buy/getdata 并用返回模型刷新“限时表演”观众入场弹窗
-
(
void
)
fus_requestTicketShowBuyGetDataAndFillEntry
:
(
FUSLiveShowTimeAudienceEntryMainView
*
)
entry
roomId
:
(
NSString
*
)
roomId
channelId
:
(
NSString
*
)
channelId
roundId
:
(
NSString
*
)
roundId
{
__weak
typeof
(
self
)
weakSelf
=
self
;
[
FUSLiveHttpHelper
fus_ticketShowBuyGetDataWithRoomId
:(
roomId
?:
@""
)
channelId
:([
NSString
isNull
:
channelId
]
?
@""
:
channelId
)
roundId
:
([
NSString
isNull
:
roundId
]
?
@""
:
roundId
)
succeed
:^
(
FUSTicketShowCollectTicketToggleResultModel
*
model
)
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
NSString
*
anchorFace
=
[[
weakSelf
.
roomInfoModel
.
face
description
]
length
]
>
0
?
[
weakSelf
.
roomInfoModel
.
face
description
]
:
@""
;
[
entry
fus_updateWithBuyGetDataModel
:
model
anchorFacePath
:
anchorFace
];
});
}
failure
:^
(
NSString
*
msg
,
NSInteger
code
)
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
FUSDialogView
fus_showDialog
:(
msg
?:
@""
)];
});
}];
}
/**
付费房磨砂弹层(-20065)处理:拉取磨砂数据并展示付费入口视图
*/
...
...
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/FUSLiveShowTimeTicketActionPopView.m
View file @
cebed0a8
...
...
@@ -20,8 +20,8 @@
@property
(
nonatomic
,
strong
)
UIImageView
*
ticketImageView
;
/// 票数文本(示例:x1 / x10)
@property
(
nonatomic
,
strong
)
UILabel
*
countLabel
;
/// 价格前置小
圆点(视觉分隔
)
@property
(
nonatomic
,
strong
)
UIView
*
priceDotView
;
/// 价格前置小
图标(home_list_pay
)
@property
(
nonatomic
,
strong
)
UI
Image
View
*
priceDotView
;
/// 价格文本(示例:100)
@property
(
nonatomic
,
strong
)
UILabel
*
priceLabel
;
/// 价格区域容器(用于让小圆点与价格文本整体居中)
...
...
@@ -61,10 +61,9 @@
self
.
countLabel
.
text
=
@"x--"
;
[
self
.
cardView
addSubview
:
self
.
countLabel
];
self
.
priceDotView
=
[[
UIView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
priceDotView
.
backgroundColor
=
[
UIColor
colorWithHex
:
@"#52DDE2"
];
self
.
priceDotView
.
layer
.
cornerRadius
=
3
;
self
.
priceDotView
.
layer
.
masksToBounds
=
YES
;
self
.
priceDotView
=
[[
UIImageView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
priceDotView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
self
.
priceDotView
.
image
=
[
FUSShowRoomCenterBunble
imageNamed
:
@"home_list_pay"
];
[
self
.
cardView
addSubview
:
self
.
priceDotView
];
self
.
priceLabel
=
[[
UILabel
alloc
]
initWithFrame
:
CGRectZero
];
...
...
@@ -108,13 +107,13 @@
make
.
top
.
equalTo
(
self
.
countLabel
.
mas_bottom
).
offset
(
6
);
make
.
centerX
.
equalTo
(
self
.
cardView
);
make
.
height
.
mas_equalTo
(
16
);
make
.
width
.
equalTo
(
self
.
priceLabel
.
mas_width
).
offset
(
1
0
);
make
.
width
.
equalTo
(
self
.
priceLabel
.
mas_width
).
offset
(
1
6
);
}];
[
self
.
priceDotView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
left
.
equalTo
(
self
.
priceContainerView
);
make
.
centerY
.
equalTo
(
self
.
priceContainerView
);
make
.
width
.
height
.
mas_equalTo
(
6
);
make
.
width
.
height
.
mas_equalTo
(
12
);
}];
[
self
.
priceLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
...
...
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/ShowTimeAudienceEntry/FUSLiveShowTimeAudienceEntryMainView.h
0 → 100644
View file @
cebed0a8
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class
FUSTicketShowCollectTicketToggleResultModel
;
/// 观众进入“限时表演中”房间时的入口弹窗交互类型
typedef
NS_ENUM
(
NSInteger
,
FUSLiveShowTimeAudienceEntryMainViewAction
)
{
/// 关闭弹窗(点击背景或右上角关闭按钮)
FUSLiveShowTimeAudienceEntryMainViewActionDismiss
=
0
,
/// 点击“进入限时表演”主按钮
FUSLiveShowTimeAudienceEntryMainViewActionEnter
=
1
,
/// 点击“活动须知”入口
FUSLiveShowTimeAudienceEntryMainViewActionNotice
=
2
,
/// 点击票券档位(仅改变选择,不直接发起业务)
FUSLiveShowTimeAudienceEntryMainViewActionSelectTicketOption
=
3
,
};
/// 票券档位字典 Key:票数文案(示例:x1 / x10 / x5)
FOUNDATION_EXPORT
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey
;
/// 票券档位字典 Key:价格文案(示例:100;不可用时建议传“--”,避免误导为免费)
FOUNDATION_EXPORT
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey
;
/// 票券档位字典 Key:贴附标签文案(示例:直接开始/抢当MVP;为空则不展示)
FOUNDATION_EXPORT
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionTagTextKey
;
/// “限时表演中”观众入场弹窗(对齐 FUSPayRoomEntryMainView 的展示方式:全屏遮罩 + 居中白色卡片)
@interface
FUSLiveShowTimeAudienceEntryMainView
:
UIView
/// 交互事件回调(仅分发用户意图;接口请求与跳转由外部决定)
@property
(
nonatomic
,
copy
,
nullable
)
void
(
^
actionHandler
)(
FUSLiveShowTimeAudienceEntryMainViewAction
action
,
NSInteger
selectedOptionIndex
);
/// 点击背景是否触发关闭(部分强引导场景可置 NO 以避免误触关闭)
@property
(
nonatomic
,
assign
)
BOOL
dismissWhenTapBackground
;
/// 在指定父视图上展示(会复用已存在实例,避免遮罩叠加造成层级/触摸问题)
/// - Parameters:
/// - rootView: 承载弹窗的父视图
/// - actionHandler: 交互回调(回传 action 与当前 selectedOptionIndex)
+
(
instancetype
)
fus_showOnView
:(
UIView
*
)
rootView
actionHandler
:(
void
(
^
_Nullable
)(
FUSLiveShowTimeAudienceEntryMainViewAction
action
,
NSInteger
selectedOptionIndex
))
actionHandler
;
/// 基于 /ticketshow/buy/getdata 返回模型刷新整个弹窗展示(标题/倒计时/票档位等)
/// - Parameters:
/// - model: /ticketshow/buy/getdata 模型
/// - anchorFacePath: 主播头像地址(接口无头像,需外部传入)
-
(
void
)
fus_updateWithBuyGetDataModel
:(
FUSTicketShowCollectTicketToggleResultModel
*
)
model
anchorFacePath
:(
nullable
NSString
*
)
anchorFacePath
;
/// 关闭并移除弹窗(默认带渐隐缩放动画)
-
(
void
)
fus_dismissAnimated
:(
BOOL
)
animated
;
@end
NS_ASSUME_NONNULL_END
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/ChatInputView/ShowTimeAudienceEntry/FUSLiveShowTimeAudienceEntryMainView.m
0 → 100644
View file @
cebed0a8
#import "FUSLiveShowTimeAudienceEntryMainView.h"
#import <FUSCommon/FUSCommon.h>
#import <FUSFoundation/FUSFoundation.h>
#import <Masonry/Masonry.h>
#import "FUSShowRoomCenterBunble.h"
#import "FUSTicketShowCollectTicketToggleResultModel.h"
#import "CBAutoScrollLabel.h"
/// 复用同类弹窗实例,避免重复叠加遮罩导致触摸穿透/层级错乱
static
NSInteger
const
kFUSLiveShowTimeAudienceEntryMainViewTag
=
90917002
;
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey
=
@"countText"
;
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey
=
@"priceText"
;
NSString
*
const
FUSLiveShowTimeAudienceEntryTicketOptionTagTextKey
=
@"tagText"
;
@interface
FUSLiveShowTimeAudienceEntryTicketOptionCardView
:
UIControl
/// 选择框卡片容器(负责圆角/描边的选中态展示)
@property
(
nonatomic
,
strong
)
UIView
*
cardView
;
/// 票券图标(资源:live_room_ticket)
@property
(
nonatomic
,
strong
)
UIImageView
*
ticketImageView
;
/// 票数文案(示例:x1 / x10)
@property
(
nonatomic
,
strong
)
UILabel
*
countLabel
;
/// 价格前置小圆点(视觉分隔)
@property
(
nonatomic
,
strong
)
UIImageView
*
priceDotView
;
/// 价格文案(示例:100)
@property
(
nonatomic
,
strong
)
UILabel
*
priceLabel
;
/// 价格区域容器(用于让小圆点与价格文案整体居中)
@property
(
nonatomic
,
strong
)
UIView
*
priceContainerView
;
/// 贴附标签(示例:直接开始/抢当MVP;为空则隐藏)
@property
(
nonatomic
,
strong
)
UIButton
*
tagButton
;
/// 刷新档位展示(仅更新 UI,不涉及业务决策;option 内使用本文件定义的 Key)
-
(
void
)
fus_setupWithOption
:(
NSDictionary
<
NSString
*
,
NSString
*>
*
)
option
;
@end
@implementation
FUSLiveShowTimeAudienceEntryTicketOptionCardView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
!
self
)
{
return
nil
;
}
self
.
backgroundColor
=
UIColor
.
clearColor
;
self
.
cardView
=
[[
UIView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
cardView
.
backgroundColor
=
[
UIColor
colorWithHex
:
@"#D4D3D3"
];
self
.
cardView
.
layer
.
cornerRadius
=
10
;
self
.
cardView
.
layer
.
masksToBounds
=
YES
;
self
.
cardView
.
layer
.
borderWidth
=
1
;
self
.
cardView
.
layer
.
borderColor
=
[
UIColor
colorWithHex
:
@"#E6E8EB"
].
CGColor
;
self
.
cardView
.
userInteractionEnabled
=
NO
;
[
self
addSubview
:
self
.
cardView
];
self
.
ticketImageView
=
[[
UIImageView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
ticketImageView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
self
.
ticketImageView
.
image
=
[
FUSShowRoomCenterBunble
imageNamed
:
@"live_room_ticket"
];
[
self
.
cardView
addSubview
:
self
.
ticketImageView
];
self
.
countLabel
=
[[
UILabel
alloc
]
initWithFrame
:
CGRectZero
];
self
.
countLabel
.
font
=
[
UIFont
fus_themeFont
:
12
];
self
.
countLabel
.
textColor
=
[
UIColor
colorWithHex
:
@"#9AA0A6"
];
self
.
countLabel
.
textAlignment
=
NSTextAlignmentCenter
;
self
.
countLabel
.
text
=
@"x--"
;
[
self
.
cardView
addSubview
:
self
.
countLabel
];
self
.
priceDotView
=
[[
UIImageView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
priceDotView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
self
.
priceDotView
.
image
=
[
FUSShowRoomCenterBunble
imageNamed
:
@"home_list_pay"
];
[
self
.
cardView
addSubview
:
self
.
priceDotView
];
self
.
priceLabel
=
[[
UILabel
alloc
]
initWithFrame
:
CGRectZero
];
self
.
priceLabel
.
font
=
[
UIFont
fus_themeBoldFont
:
12
];
self
.
priceLabel
.
textColor
=
[
UIColor
colorWithHex
:
@"#1F1F1F"
];
self
.
priceLabel
.
text
=
@"--"
;
[
self
.
cardView
addSubview
:
self
.
priceLabel
];
self
.
priceContainerView
=
[[
UIView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
priceContainerView
.
backgroundColor
=
UIColor
.
clearColor
;
[
self
.
cardView
addSubview
:
self
.
priceContainerView
];
[
self
.
priceContainerView
addSubview
:
self
.
priceDotView
];
[
self
.
priceContainerView
addSubview
:
self
.
priceLabel
];
self
.
tagButton
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
self
.
tagButton
.
hidden
=
YES
;
self
.
tagButton
.
userInteractionEnabled
=
NO
;
[
self
.
tagButton
setBackgroundImage
:[
FUSShowRoomCenterBunble
imageNamed
:
@"live_room_runBK"
]
forState
:
UIControlStateNormal
];
[
self
.
tagButton
setTitleColor
:
UIColor
.
blackColor
forState
:
UIControlStateNormal
];
self
.
tagButton
.
titleLabel
.
font
=
[
UIFont
fus_themeBoldFont
:
11
];
[
self
addSubview
:
self
.
tagButton
];
[
self
.
cardView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
edges
.
equalTo
(
self
);
}];
[
self
.
ticketImageView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
cardView
).
offset
(
12
);
make
.
centerX
.
equalTo
(
self
.
cardView
);
make
.
width
.
mas_equalTo
(
40
);
make
.
height
.
mas_equalTo
(
21
);
}];
[
self
.
countLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
ticketImageView
.
mas_bottom
).
offset
(
4
);
make
.
left
.
right
.
equalTo
(
self
.
cardView
);
make
.
height
.
mas_equalTo
(
16
);
}];
[
self
.
priceContainerView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
countLabel
.
mas_bottom
).
offset
(
6
);
make
.
centerX
.
equalTo
(
self
.
cardView
);
make
.
height
.
mas_equalTo
(
16
);
make
.
width
.
equalTo
(
self
.
priceLabel
.
mas_width
).
offset
(
16
);
}];
[
self
.
priceDotView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
left
.
equalTo
(
self
.
priceContainerView
);
make
.
centerY
.
equalTo
(
self
.
priceContainerView
);
make
.
width
.
height
.
mas_equalTo
(
12
);
}];
[
self
.
priceLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
left
.
equalTo
(
self
.
priceDotView
.
mas_right
).
offset
(
4
);
make
.
right
.
equalTo
(
self
.
priceContainerView
);
make
.
centerY
.
equalTo
(
self
.
priceContainerView
);
make
.
height
.
mas_equalTo
(
16
);
}];
[
self
.
tagButton
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
centerX
.
equalTo
(
self
);
make
.
centerY
.
equalTo
(
self
.
cardView
.
mas_bottom
);
make
.
width
.
mas_equalTo
(
57
);
make
.
height
.
mas_equalTo
(
24
);
}];
return
self
;
}
-
(
void
)
setSelected
:(
BOOL
)
selected
{
[
super
setSelected
:
selected
];
self
.
cardView
.
layer
.
borderWidth
=
(
selected
?
1
.
5
:
1
);
self
.
cardView
.
layer
.
borderColor
=
(
selected
?
[
UIColor
colorWithHex
:
@"#52DDE2"
].
CGColor
:
[
UIColor
colorWithHex
:
@"#E6E8EB"
].
CGColor
);
}
-
(
void
)
fus_setupWithOption
:(
NSDictionary
<
NSString
*
,
NSString
*>
*
)
option
{
NSString
*
countText
=
[
NSString
stringWithObject
:
option
[
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey
]];
NSString
*
priceText
=
[
NSString
stringWithObject
:
option
[
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey
]];
NSString
*
tagText
=
[
NSString
stringWithObject
:
option
[
FUSLiveShowTimeAudienceEntryTicketOptionTagTextKey
]];
self
.
countLabel
.
text
=
([
NSString
isNull
:
countText
]
?
@"x--"
:
countText
);
self
.
priceLabel
.
text
=
([
NSString
isNull
:
priceText
]
?
@"--"
:
priceText
);
if
(
!
[
NSString
isNull
:
tagText
])
{
self
.
tagButton
.
hidden
=
NO
;
[
self
.
tagButton
setTitle
:
tagText
forState
:
UIControlStateNormal
];
}
else
{
self
.
tagButton
.
hidden
=
YES
;
[
self
.
tagButton
setTitle
:
@""
forState
:
UIControlStateNormal
];
}
[
self
setNeedsLayout
];
}
@end
@interface
FUSLiveShowTimeAudienceEntryTicketOptionGroupView
:
UIView
/// 档位卡片列表(根据传入 options 动态重建)
@property
(
nonatomic
,
strong
)
NSArray
<
FUSLiveShowTimeAudienceEntryTicketOptionCardView
*>
*
optionViews
;
/// 选择回调(外部负责记录选择并触发后续业务)
@property
(
nonatomic
,
copy
,
nullable
)
void
(
^
selectHandler
)(
NSInteger
index
);
/// 更新档位数据(为保证布局稳定,采用销毁重建方式,避免残留旧视图状态)
-
(
void
)
fus_updateWithOptions
:(
NSArray
<
NSDictionary
<
NSString
*
,
NSString
*>
*>
*
)
options
;
/// 设置选中态(仅改变 UI,便于外部统一管理状态)
-
(
void
)
fus_setSelectedIndex
:(
NSInteger
)
selectedIndex
;
@end
@implementation
FUSLiveShowTimeAudienceEntryTicketOptionGroupView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
!
self
)
{
return
nil
;
}
self
.
backgroundColor
=
UIColor
.
clearColor
;
self
.
optionViews
=
@[];
return
self
;
}
-
(
void
)
fus_updateWithOptions
:(
NSArray
<
NSDictionary
<
NSString
*
,
NSString
*>
*>
*
)
options
{
for
(
UIView
*
v
in
self
.
optionViews
)
{
[
v
removeFromSuperview
];
}
NSArray
<
NSDictionary
<
NSString
*
,
NSString
*>
*>
*
validOptions
=
(
options
?:
@[]);
NSMutableArray
<
FUSLiveShowTimeAudienceEntryTicketOptionCardView
*>
*
views
=
[[
NSMutableArray
alloc
]
initWithCapacity
:
validOptions
.
count
];
for
(
NSInteger
i
=
0
;
i
<
validOptions
.
count
;
i
++
)
{
FUSLiveShowTimeAudienceEntryTicketOptionCardView
*
card
=
[[
FUSLiveShowTimeAudienceEntryTicketOptionCardView
alloc
]
initWithFrame
:
CGRectZero
];
card
.
tag
=
i
;
[
card
addTarget
:
self
action
:
@selector
(
fus_onTapOption
:
)
forControlEvents
:
UIControlEventTouchUpInside
];
[
card
fus_setupWithOption
:
validOptions
[
i
]];
[
self
addSubview
:
card
];
[
views
addObject
:
card
];
}
self
.
optionViews
=
views
.
copy
;
if
(
self
.
optionViews
.
count
==
0
)
{
return
;
}
CGFloat
spacing
=
12
;
UIView
*
first
=
self
.
optionViews
.
firstObject
;
[
first
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
left
.
top
.
bottom
.
equalTo
(
self
);
if
(
self
.
optionViews
.
count
==
1
)
{
make
.
right
.
equalTo
(
self
);
}
}];
for
(
NSInteger
i
=
1
;
i
<
self
.
optionViews
.
count
;
i
++
)
{
UIView
*
prev
=
self
.
optionViews
[
i
-
1
];
UIView
*
cur
=
self
.
optionViews
[
i
];
[
cur
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
left
.
equalTo
(
prev
.
mas_right
).
offset
(
spacing
);
make
.
top
.
bottom
.
equalTo
(
self
);
make
.
width
.
equalTo
(
first
);
if
(
i
==
self
.
optionViews
.
count
-
1
)
{
make
.
right
.
equalTo
(
self
);
}
}];
}
}
-
(
void
)
fus_setSelectedIndex
:(
NSInteger
)
selectedIndex
{
for
(
NSInteger
i
=
0
;
i
<
self
.
optionViews
.
count
;
i
++
)
{
self
.
optionViews
[
i
].
selected
=
(
i
==
selectedIndex
);
}
}
-
(
void
)
fus_onTapOption
:(
UIControl
*
)
sender
{
NSInteger
index
=
sender
.
tag
;
if
(
self
.
selectHandler
)
{
self
.
selectHandler
(
index
);
}
}
@end
@interface
FUSLiveShowTimeAudienceEntryMainView
()
/// 背景遮罩按钮(用于拦截触摸并支持点击关闭)
@property
(
nonatomic
,
strong
)
UIButton
*
bgBtn
;
/// 右上角关闭按钮(对齐项目通用关闭样式)
@property
(
nonatomic
,
strong
)
UIButton
*
closeBtn
;
/// 白色内容卡片容器(承载所有展示内容)
@property
(
nonatomic
,
strong
)
UIView
*
cardView
;
/// 标题(示例:精彩限时表演中,使用跑马灯滚动展示长文案)
@property
(
nonatomic
,
strong
)
CBAutoScrollLabel
*
titleLabel
;
/// 主播头像
@property
(
nonatomic
,
strong
)
FUSRichIconView
*
anchorAvatarView
;
/// 主标题(表演主题,跑马灯)
@property
(
nonatomic
,
strong
)
CBAutoScrollLabel
*
mainTitleLabel
;
/// 表演结束倒计时文案(由外部驱动更新,UI 仅展示)
@property
(
nonatomic
,
strong
)
UILabel
*
countdownLabel
;
/// 票券档位选择区(支持 1~N 档位)
@property
(
nonatomic
,
strong
)
FUSLiveShowTimeAudienceEntryTicketOptionGroupView
*
optionGroupView
;
/// 主按钮(进入限时表演)
@property
(
nonatomic
,
strong
)
UIButton
*
enterButton
;
/// 活动须知入口(带下划线文本,点击由外部跳转规则页/弹窗)
@property
(
nonatomic
,
strong
)
UIButton
*
noticeButton
;
/// 当前选中的档位索引(用于对外回调,外部再决定对应的票数/价格)
@property
(
nonatomic
,
assign
)
NSInteger
selectedOptionIndex
;
/// 倒计时剩余秒数(单位:秒;由倒计时驱动逐步递减)
@property
(
nonatomic
,
assign
)
NSInteger
countdownRemainingSeconds
;
/// GCD 定时器:用于每秒刷新倒计时文本
/// 内存管理说明:
/// - 使用 dispatch_source_t,避免 RunLoop 依赖
/// - dealloc 与弹层关闭时均会取消,防止泄漏与回调野指针
@property
(
nonatomic
,
strong
,
nullable
)
dispatch_source_t
countdownTimer
;
@end
@implementation
FUSLiveShowTimeAudienceEntryMainView
+
(
instancetype
)
fus_showOnView
:(
UIView
*
)
rootView
actionHandler
:(
void
(
^
_Nullable
)(
FUSLiveShowTimeAudienceEntryMainViewAction
action
,
NSInteger
selectedOptionIndex
))
actionHandler
{
if
(
!
rootView
)
{
return
nil
;
}
FUSLiveShowTimeAudienceEntryMainView
*
existView
=
[
rootView
viewWithTag
:
kFUSLiveShowTimeAudienceEntryMainViewTag
];
if
([
existView
isKindOfClass
:
FUSLiveShowTimeAudienceEntryMainView
.
class
])
{
[
rootView
bringSubviewToFront
:
existView
];
existView
.
actionHandler
=
actionHandler
;
[
existView
fus_showAnimated
:
YES
];
return
existView
;
}
FUSLiveShowTimeAudienceEntryMainView
*
view
=
[[
FUSLiveShowTimeAudienceEntryMainView
alloc
]
initWithFrame
:
CGRectZero
];
view
.
tag
=
kFUSLiveShowTimeAudienceEntryMainViewTag
;
view
.
actionHandler
=
actionHandler
;
[
rootView
addSubview
:
view
];
[
view
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
edges
.
equalTo
(
rootView
);
}];
[
view
fus_showAnimated
:
YES
];
return
view
;
}
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
self
.
dismissWhenTapBackground
=
YES
;
self
.
selectedOptionIndex
=
0
;
[
self
fus_buildUI
];
[
self
fus_bindActions
];
[
self
fus_updateTitleText
:
nil
anchorName
:
nil
anchorFacePath
:
nil
countdownText
:
nil
enterButtonTitle
:
nil
noticeText
:
nil
];
[
self
fus_updateTicketOptions
:@[]
selectedIndex
:
0
];
}
return
self
;
}
-
(
void
)
fus_updateTitleText
:(
nullable
NSString
*
)
titleText
anchorName
:(
nullable
NSString
*
)
anchorName
anchorFacePath
:(
nullable
NSString
*
)
anchorFacePath
countdownText
:(
nullable
NSString
*
)
countdownText
enterButtonTitle
:(
nullable
NSString
*
)
enterButtonTitle
noticeText
:(
nullable
NSString
*
)
noticeText
{
self
.
titleLabel
.
text
=
([
NSString
isNull
:
titleText
]
?
[
NSString
fus_localString
:
@"精彩限时表演中"
]
:
titleText
);
[
self
.
mainTitleLabel
setText
:([
NSString
isNull
:
anchorName
]
?
@""
:
anchorName
)
refreshLabels
:
YES
];
self
.
countdownLabel
.
text
=
([
NSString
isNull
:
countdownText
]
?
[
NSString
fus_localString
:
@"表演结束倒计时:--:--"
]
:
countdownText
);
[
self
.
enterButton
setTitle
:([
NSString
isNull
:
enterButtonTitle
]
?
[
NSString
fus_localString
:
@"进入限时表演"
]
:
enterButtonTitle
)
forState
:
UIControlStateNormal
];
NSString
*
notice
=
([
NSString
isNull
:
noticeText
]
?
[
NSString
fus_localString
:
@"活动须知"
]
:
noticeText
);
NSDictionary
*
attrs
=
@{
NSFontAttributeName:
[
UIFont
fus_themeFont
:
11
],
NSForegroundColorAttributeName:
[
UIColor
colorWithHex
:
@"#9B9B9B"
],
NSUnderlineStyleAttributeName:
@
(
NSUnderlineStyleSingle
),
NSUnderlineColorAttributeName:
[
UIColor
colorWithHex
:
@"#9B9B9B"
]
};
[
self
.
noticeButton
setAttributedTitle
:[[
NSAttributedString
alloc
]
initWithString
:
notice
attributes
:
attrs
]
forState
:
UIControlStateNormal
];
[
self
.
anchorAvatarView
fus_setupLiveIconWithFacePath
:([
NSString
isNull
:
anchorFacePath
]
?
@""
:
anchorFacePath
)
level
:
0
animated
:
NO
];
}
-
(
void
)
fus_updateTicketOptions
:(
NSArray
<
NSDictionary
<
NSString
*
,
NSString
*>
*>
*
)
ticketOptions
selectedIndex
:(
NSInteger
)
selectedIndex
{
NSArray
<
NSDictionary
<
NSString
*
,
NSString
*>
*>
*
options
=
(
ticketOptions
?:
@[]);
[
self
.
optionGroupView
fus_updateWithOptions
:
options
];
NSInteger
selected
=
0
;
if
(
options
.
count
>
0
)
{
selected
=
MAX
(
0
,
MIN
((
NSInteger
)
options
.
count
-
1
,
selectedIndex
));
}
self
.
selectedOptionIndex
=
selected
;
[
self
.
optionGroupView
fus_setSelectedIndex
:
selected
];
}
-
(
void
)
fus_updateWithBuyGetDataModel
:(
FUSTicketShowCollectTicketToggleResultModel
*
)
model
anchorFacePath
:(
nullable
NSString
*
)
anchorFacePath
{
NSString
*
theme
=
[
model
.
showTheme
description
];
NSInteger
remainMs
=
(
model
.
stageData
?
model
.
stageData
.
showStatusTime
:
model
.
showStatusTime
);
NSInteger
remainSec
=
MAX
(
0
,
(
NSInteger
)
llround
(((
double
)
remainMs
/
1000
.
0
)));
[
self
fus_updateTitleText
:
nil
anchorName
:(
!
[
NSString
isNull
:
theme
]
?
theme
:
nil
)
anchorFacePath:
(
!
[
NSString
isNull
:
anchorFacePath
]
?
anchorFacePath
:
nil
)
countdownText:
nil
enterButtonTitle:
nil
noticeText:
nil
];
[
self
fus_startCountdownWithRemaining
:
remainSec
];
NSInteger
unitPrice
=
MAX
(
0
,
model
.
buyPrice
);
NSInteger
directNum
=
MAX
(
1
,
model
.
directBuyNum
);
NSInteger
strengthNum
=
MAX
(
1
,
model
.
showStrengthNum
);
NSInteger
mvpNum
=
MAX
(
1
,
model
.
mvpBuyNum
);
NSString
*
priceText
=
[
@
(
unitPrice
)
description
];
NSDictionary
*
opt1
=
@{
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey:
[
NSString
stringWithFormat
:
@"x%ld"
,
(
long
)
directNum
],
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey:
priceText
,
};
NSDictionary
*
opt2
=
@{
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey:
[
NSString
stringWithFormat
:
@"x%ld"
,
(
long
)
strengthNum
],
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey:
priceText
,
};
NSDictionary
*
opt3
=
@{
FUSLiveShowTimeAudienceEntryTicketOptionCountTextKey:
[
NSString
stringWithFormat
:
@"x%ld"
,
(
long
)
mvpNum
],
FUSLiveShowTimeAudienceEntryTicketOptionPriceTextKey:
priceText
,
};
[
self
fus_updateTicketOptions
:@[
opt1
,
opt2
,
opt3
]
selectedIndex
:
0
];
}
-
(
void
)
fus_dismissAnimated
:(
BOOL
)
animated
{
[
self
fus_stopCountdown
];
if
(
!
self
.
superview
)
{
return
;
}
if
(
!
animated
)
{
[
self
removeFromSuperview
];
return
;
}
__weak
typeof
(
self
)
weakSelf
=
self
;
[
UIView
animateWithDuration
:
0
.
25
animations
:
^
{
weakSelf
.
alpha
=
0
;
weakSelf
.
cardView
.
transform
=
CGAffineTransformMakeScale
(
0
.
98
,
0
.
98
);
}
completion
:^
(
BOOL
finished
)
{
[
weakSelf
removeFromSuperview
];
}];
}
/// 生命周期释放:保证定时器被取消,避免野回调
-
(
void
)
dealloc
{
[
self
fus_stopCountdown
];
}
/// 启动倒计时
/// 说明:
/// - 先停止已有定时器,确保单一计时来源
/// - 首次设置即刻刷新一次 UI,再进入每秒触发
/// - UI 更新在主线程执行,保证线程安全
/// - 使用 weak/strong self,避免定时器闭包循环引用
-
(
void
)
fus_startCountdownWithRemaining
:
(
NSInteger
)
sec
{
[
self
fus_stopCountdown
];
self
.
countdownRemainingSeconds
=
sec
;
if
(
sec
<=
0
)
{
self
.
countdownLabel
.
text
=
[
NSString
fus_localString
:
@"表演结束倒计时:--:--"
];
return
;
}
NSInteger
mm
=
(
self
.
countdownRemainingSeconds
/
60
);
NSInteger
ss
=
(
self
.
countdownRemainingSeconds
%
60
);
self
.
countdownLabel
.
text
=
[
NSString
stringWithFormat
:[
NSString
fus_localString
:
@"表演结束倒计时:%02ld:%02ld"
],
(
long
)
mm
,
(
long
)
ss
];
dispatch_queue_t
q
=
dispatch_get_global_queue
(
QOS_CLASS_USER_INITIATED
,
0
);
dispatch_source_t
t
=
dispatch_source_create
(
DISPATCH_SOURCE_TYPE_TIMER
,
0
,
0
,
q
);
self
.
countdownTimer
=
t
;
dispatch_source_set_timer
(
t
,
dispatch_time
(
DISPATCH_TIME_NOW
,
NSEC_PER_SEC
),
NSEC_PER_SEC
,
(
uint64_t
)(
0
.
1
*
NSEC_PER_SEC
));
__weak
typeof
(
self
)
weakSelf
=
self
;
dispatch_source_set_event_handler
(
t
,
^
{
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
if
(
!
strongSelf
)
return
;
if
(
strongSelf
.
countdownRemainingSeconds
<=
0
)
{
[
strongSelf
fus_stopCountdown
];
dispatch_async
(
dispatch_get_main_queue
(),
^
{
strongSelf
.
countdownLabel
.
text
=
[
NSString
fus_localString
:
@"表演结束倒计时:--:--"
];
});
return
;
}
NSInteger
cmm
=
(
strongSelf
.
countdownRemainingSeconds
/
60
);
NSInteger
css
=
(
strongSelf
.
countdownRemainingSeconds
%
60
);
dispatch_async
(
dispatch_get_main_queue
(),
^
{
strongSelf
.
countdownLabel
.
text
=
[
NSString
stringWithFormat
:[
NSString
fus_localString
:
@"表演结束倒计时:%02ld:%02ld"
],
(
long
)
cmm
,
(
long
)
css
];
});
strongSelf
.
countdownRemainingSeconds
=
MAX
(
0
,
strongSelf
.
countdownRemainingSeconds
-
1
);
});
dispatch_resume
(
t
);
}
/// 停止倒计时
/// 说明:
/// - 取消 GCD 定时器并置空
/// - 多次调用安全可重入
-
(
void
)
fus_stopCountdown
{
if
(
self
.
countdownTimer
)
{
dispatch_source_cancel
(
self
.
countdownTimer
);
self
.
countdownTimer
=
nil
;
}
}
-
(
void
)
fus_buildUI
{
self
.
alpha
=
0
;
self
.
backgroundColor
=
UIColor
.
clearColor
;
self
.
bgBtn
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
self
.
bgBtn
.
backgroundColor
=
[
UIColor
colorWithWhite
:
0
alpha
:
0
.
55
];
[
self
addSubview
:
self
.
bgBtn
];
self
.
closeBtn
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[
self
.
closeBtn
setImage
:[
FUSShowRoomCenterBunble
imageNamed
:
@"live_board_close"
]
forState
:
UIControlStateNormal
];
[
self
addSubview
:
self
.
closeBtn
];
self
.
cardView
=
[[
UIView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
cardView
.
backgroundColor
=
UIColor
.
whiteColor
;
self
.
cardView
.
layer
.
cornerRadius
=
16
;
self
.
cardView
.
layer
.
masksToBounds
=
YES
;
[
self
addSubview
:
self
.
cardView
];
self
.
titleLabel
=
[[
UILabel
alloc
]
initWithFrame
:
CGRectZero
];
self
.
titleLabel
.
font
=
[
UIFont
fus_themeMediumFont
:
16
];
self
.
titleLabel
.
textColor
=
[
UIColor
colorWithHex
:
@"#2A2A2A"
];
self
.
titleLabel
.
textAlignment
=
NSTextAlignmentCenter
;
[
self
.
cardView
addSubview
:
self
.
titleLabel
];
self
.
anchorAvatarView
=
[[
FUSRichIconView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
anchorAvatarView
.
showNoVipLevel
=
NO
;
self
.
anchorAvatarView
.
richWearImageView
.
hidden
=
YES
;
self
.
anchorAvatarView
.
faceImageView
.
layer
.
cornerRadius
=
27
;
self
.
anchorAvatarView
.
faceImageView
.
layer
.
masksToBounds
=
YES
;
self
.
anchorAvatarView
.
faceImageView
.
contentMode
=
UIViewContentModeScaleAspectFill
;
[
self
.
cardView
addSubview
:
self
.
anchorAvatarView
];
self
.
mainTitleLabel
=
[[
CBAutoScrollLabel
alloc
]
initWithFrame
:
CGRectZero
];
self
.
mainTitleLabel
.
font
=
[
UIFont
fus_themeMediumFont
:
16
];
self
.
mainTitleLabel
.
textColor
=
[
UIColor
colorWithHex
:
@"#2A2A2A"
];
self
.
mainTitleLabel
.
textAlignment
=
NSTextAlignmentCenter
;
self
.
mainTitleLabel
.
fadeLength
=
7
;
self
.
mainTitleLabel
.
scrollDirection
=
CBAutoScrollDirectionLeft
;
self
.
mainTitleLabel
.
scrollSpeed
=
30
;
self
.
mainTitleLabel
.
pauseInterval
=
1
.
5
;
[
self
.
mainTitleLabel
observeApplicationNotifications
];
[
self
.
cardView
addSubview
:
self
.
mainTitleLabel
];
self
.
countdownLabel
=
[[
UILabel
alloc
]
initWithFrame
:
CGRectZero
];
self
.
countdownLabel
.
font
=
[
UIFont
fus_themeFont
:
12
];
self
.
countdownLabel
.
textColor
=
[
UIColor
colorWithHex
:
@"#9B9B9B"
];
self
.
countdownLabel
.
textAlignment
=
NSTextAlignmentCenter
;
self
.
countdownLabel
.
numberOfLines
=
1
;
[
self
.
cardView
addSubview
:
self
.
countdownLabel
];
self
.
optionGroupView
=
[[
FUSLiveShowTimeAudienceEntryTicketOptionGroupView
alloc
]
initWithFrame
:
CGRectZero
];
[
self
.
cardView
addSubview
:
self
.
optionGroupView
];
self
.
enterButton
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
self
.
enterButton
.
titleLabel
.
font
=
[
UIFont
fus_themeMediumFont
:
15
];
[
self
.
enterButton
setTitleColor
:[
UIColor
colorWithHex
:
@"#003333"
]
forState
:
UIControlStateNormal
];
self
.
enterButton
.
backgroundColor
=
[
UIColor
colorWithRed
:(
45
.
0
/
255
.
0
)
green
:(
226
.
0
/
255
.
0
)
blue
:
(
224
.
0
/
255
.
0
)
alpha
:
1
.
0
];
self
.
enterButton
.
layer
.
cornerRadius
=
22
;
self
.
enterButton
.
layer
.
masksToBounds
=
YES
;
[
self
.
cardView
addSubview
:
self
.
enterButton
];
self
.
noticeButton
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[
self
.
cardView
addSubview
:
self
.
noticeButton
];
[
self
.
bgBtn
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
edges
.
equalTo
(
self
);
}];
[
self
.
closeBtn
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
mas_safeAreaLayoutGuideTop
).
offset
(
6
);
make
.
right
.
equalTo
(
self
).
offset
(
-
8
);
make
.
width
.
height
.
mas_equalTo
(
44
);
}];
[
self
.
cardView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
center
.
equalTo
(
self
);
make
.
size
.
mas_equalTo
(
CGSizeMake
(
285
,
360
));
}];
[
self
.
titleLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
cardView
).
offset
(
18
);
make
.
left
.
equalTo
(
self
.
cardView
).
offset
(
20
);
make
.
right
.
equalTo
(
self
.
cardView
).
offset
(
-
20
);
make
.
height
.
mas_equalTo
(
22
);
}];
[
self
.
anchorAvatarView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
titleLabel
.
mas_bottom
).
offset
(
14
);
make
.
centerX
.
equalTo
(
self
.
cardView
);
make
.
size
.
mas_equalTo
(
CGSizeMake
(
54
,
54
));
}];
[
self
.
mainTitleLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
anchorAvatarView
.
mas_bottom
).
offset
(
10
);
make
.
left
.
equalTo
(
self
.
cardView
).
offset
(
20
);
make
.
right
.
equalTo
(
self
.
cardView
).
offset
(
-
20
);
make
.
height
.
mas_equalTo
(
20
);
}];
[
self
.
countdownLabel
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
mainTitleLabel
.
mas_bottom
).
offset
(
6
);
make
.
left
.
equalTo
(
self
.
cardView
).
offset
(
20
);
make
.
right
.
equalTo
(
self
.
cardView
).
offset
(
-
20
);
make
.
height
.
mas_equalTo
(
16
);
}];
[
self
.
optionGroupView
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
countdownLabel
.
mas_bottom
).
offset
(
14
);
make
.
left
.
equalTo
(
self
.
cardView
).
offset
(
20
);
make
.
right
.
equalTo
(
self
.
cardView
).
offset
(
-
20
);
make
.
height
.
mas_equalTo
(
85
);
}];
[
self
.
enterButton
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
optionGroupView
.
mas_bottom
).
offset
(
16
);
make
.
left
.
equalTo
(
self
.
cardView
).
offset
(
20
);
make
.
right
.
equalTo
(
self
.
cardView
).
offset
(
-
20
);
make
.
height
.
mas_equalTo
(
44
);
}];
[
self
.
noticeButton
mas_makeConstraints
:
^
(
MASConstraintMaker
*
make
)
{
make
.
top
.
equalTo
(
self
.
enterButton
.
mas_bottom
).
offset
(
10
);
make
.
centerX
.
equalTo
(
self
.
cardView
);
make
.
height
.
mas_equalTo
(
16
);
make
.
bottom
.
lessThanOrEqualTo
(
self
.
cardView
).
offset
(
-
12
);
}];
}
-
(
void
)
fus_bindActions
{
__weak
typeof
(
self
)
weakSelf
=
self
;
[
self
.
bgBtn
addTarget
:
self
action
:
@selector
(
fus_onTapBackground
)
forControlEvents
:
UIControlEventTouchUpInside
];
[
self
.
closeBtn
addTarget
:
self
action
:
@selector
(
fus_onTapClose
)
forControlEvents
:
UIControlEventTouchUpInside
];
[
self
.
enterButton
addTarget
:
self
action
:
@selector
(
fus_onTapEnter
)
forControlEvents
:
UIControlEventTouchUpInside
];
[
self
.
noticeButton
addTarget
:
self
action
:
@selector
(
fus_onTapNotice
)
forControlEvents
:
UIControlEventTouchUpInside
];
self
.
optionGroupView
.
selectHandler
=
^
(
NSInteger
index
)
{
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
if
(
!
strongSelf
)
{
return
;
}
/// 仅记录选择并回调给外部,业务侧可以基于 index 决定票数/价格/跳转逻辑
strongSelf
.
selectedOptionIndex
=
index
;
[
strongSelf
.
optionGroupView
fus_setSelectedIndex
:
index
];
if
(
strongSelf
.
actionHandler
)
{
strongSelf
.
actionHandler
(
FUSLiveShowTimeAudienceEntryMainViewActionSelectTicketOption
,
index
);
}
};
}
-
(
void
)
fus_showAnimated
:
(
BOOL
)
animated
{
if
(
!
animated
)
{
self
.
alpha
=
1
;
self
.
cardView
.
transform
=
CGAffineTransformIdentity
;
return
;
}
self
.
alpha
=
0
;
self
.
cardView
.
transform
=
CGAffineTransformMakeScale
(
0
.
98
,
0
.
98
);
__weak
typeof
(
self
)
weakSelf
=
self
;
[
UIView
animateWithDuration
:
0
.
25
animations
:
^
{
weakSelf
.
alpha
=
1
;
weakSelf
.
cardView
.
transform
=
CGAffineTransformIdentity
;
}];
}
-
(
void
)
fus_onTapBackground
{
if
(
!
self
.
dismissWhenTapBackground
)
{
return
;
}
/// 点击背景属于“用户意图关闭”,是否真正关闭交由外部统一控制(便于做强引导/二次确认)
if
(
self
.
actionHandler
)
{
self
.
actionHandler
(
FUSLiveShowTimeAudienceEntryMainViewActionDismiss
,
self
.
selectedOptionIndex
);
}
}
-
(
void
)
fus_onTapClose
{
if
(
self
.
actionHandler
)
{
self
.
actionHandler
(
FUSLiveShowTimeAudienceEntryMainViewActionDismiss
,
self
.
selectedOptionIndex
);
}
}
-
(
void
)
fus_onTapEnter
{
if
(
self
.
actionHandler
)
{
self
.
actionHandler
(
FUSLiveShowTimeAudienceEntryMainViewActionEnter
,
self
.
selectedOptionIndex
);
}
}
-
(
void
)
fus_onTapNotice
{
if
(
self
.
actionHandler
)
{
self
.
actionHandler
(
FUSLiveShowTimeAudienceEntryMainViewActionNotice
,
self
.
selectedOptionIndex
);
}
}
@end
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