2025-10-27 20:07:37 +08:00
|
|
|
|
//
|
|
|
|
|
|
// KBPermissionViewController.m
|
|
|
|
|
|
// CustomKeyboard
|
|
|
|
|
|
//
|
|
|
|
|
|
// Created by Mac on 2025/10/27.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#import "KBPermissionViewController.h"
|
2025-11-27 21:39:03 +08:00
|
|
|
|
#import <AVFoundation/AVFoundation.h>
|
2025-10-27 20:07:37 +08:00
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
static void *KBPermPlayerPresentationSizeContext = &KBPermPlayerPresentationSizeContext;
|
|
|
|
|
|
|
2025-10-27 20:07:37 +08:00
|
|
|
|
@interface KBPermissionViewController ()
|
2025-11-03 16:57:24 +08:00
|
|
|
|
@property (nonatomic, strong) UILabel *titleLabel; // 标题
|
|
|
|
|
|
@property (nonatomic, strong) UILabel *tipsLabel; // 步骤提示
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *openButton; // 去设置
|
2025-11-14 16:34:01 +08:00
|
|
|
|
@property (nonatomic, strong) UIButton *closeButton; // 去设置
|
|
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
@property (nonatomic, strong) UILabel *helpLabel; // 底部帮助
|
2025-11-14 16:34:01 +08:00
|
|
|
|
@property (nonatomic, strong) UIImageView *redImageView;
|
|
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, strong) UIImageView *bgImageView;
|
|
|
|
|
|
|
2025-11-27 21:39:03 +08:00
|
|
|
|
// 权限引导视频播放器(循环播放,不提供暂停交互)
|
|
|
|
|
|
@property (nonatomic, strong) AVPlayer *kb_permPlayer;
|
|
|
|
|
|
@property (nonatomic, strong) AVPlayerLayer *kb_permPlayerLayer;
|
|
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
// 承载视频的裁剪容器,高度固定为 KBFit(550),内部内容从顶部开始显示,超出的部分从底部裁剪
|
|
|
|
|
|
@property (nonatomic, strong) UIView *videoContainerView;
|
|
|
|
|
|
|
2025-10-27 20:07:37 +08:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation KBPermissionViewController
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
|
|
[super viewDidLoad];
|
2025-11-14 16:34:01 +08:00
|
|
|
|
[self.view addSubview:self.bgImageView];
|
|
|
|
|
|
[self.view addSubview:self.redImageView];
|
2025-10-27 20:07:37 +08:00
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
// 懒加载控件 + 添加到视图
|
2025-11-14 16:34:01 +08:00
|
|
|
|
[self.view addSubview:self.closeButton];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
[self.view addSubview:self.titleLabel];
|
|
|
|
|
|
[self.view addSubview:self.tipsLabel];
|
2025-11-28 13:07:35 +08:00
|
|
|
|
[self.view addSubview:self.videoContainerView];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
[self.view addSubview:self.openButton];
|
|
|
|
|
|
[self.view addSubview:self.helpLabel];
|
|
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
|
|
|
|
|
|
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.edges.equalTo(self.view);
|
|
|
|
|
|
}];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
// Masonry 约束
|
2025-11-14 16:34:01 +08:00
|
|
|
|
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
2025-11-03 16:57:24 +08:00
|
|
|
|
make.left.equalTo(self.view).offset(16);
|
2025-11-14 16:34:01 +08:00
|
|
|
|
make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop).offset(20);
|
|
|
|
|
|
make.width.mas_equalTo(26);
|
|
|
|
|
|
make.height.mas_equalTo(26);
|
|
|
|
|
|
}];
|
|
|
|
|
|
[self.redImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.top.equalTo(self.closeButton.mas_centerY);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(20);
|
|
|
|
|
|
make.width.mas_equalTo(143);
|
|
|
|
|
|
make.height.mas_equalTo(132);
|
2025-11-03 16:57:24 +08:00
|
|
|
|
}];
|
2025-11-14 16:34:01 +08:00
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
|
|
|
|
|
|
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
2025-11-14 16:34:01 +08:00
|
|
|
|
make.top.equalTo(self.closeButton.mas_bottom).offset(13);
|
|
|
|
|
|
make.left.equalTo(self.view).offset(22);
|
|
|
|
|
|
make.height.mas_equalTo(24);
|
2025-11-03 16:57:24 +08:00
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
[self.tipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.top.equalTo(self.titleLabel.mas_bottom).offset(8);
|
2025-11-14 16:34:01 +08:00
|
|
|
|
make.left.equalTo(self.titleLabel);
|
2025-11-03 16:57:24 +08:00
|
|
|
|
}];
|
|
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
// 视频容器:左右各 25,顶部距离 tipsLabel 32,高度固定为 KBFit(550)
|
|
|
|
|
|
[self.videoContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
2025-11-28 13:20:50 +08:00
|
|
|
|
make.top.equalTo(self.tipsLabel.mas_bottom).offset(KB_DEVICE_HAS_NOTCH ? 32 : 0);
|
2025-11-28 13:07:35 +08:00
|
|
|
|
make.left.equalTo(self.view).offset(25);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-25);
|
2025-11-28 13:20:50 +08:00
|
|
|
|
make.height.mas_equalTo(KB_DEVICE_HAS_NOTCH ? KBFit(550) : KBFit(500));
|
2025-11-28 13:07:35 +08:00
|
|
|
|
}];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
|
|
|
|
|
|
[self.openButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
2025-11-14 16:34:01 +08:00
|
|
|
|
make.bottom.equalTo(self.view).offset(-KB_SAFE_BOTTOM-20);
|
|
|
|
|
|
make.left.equalTo(self.view).offset(47);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-47);
|
|
|
|
|
|
make.height.mas_equalTo(60);
|
2025-11-03 16:57:24 +08:00
|
|
|
|
}];
|
|
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
// [self.helpLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
// make.top.equalTo(self.openButton.mas_bottom).offset(12);
|
|
|
|
|
|
// make.left.equalTo(self.view).offset(24);
|
|
|
|
|
|
// make.right.equalTo(self.view).offset(-24);
|
|
|
|
|
|
// }];
|
2025-10-27 20:07:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 21:39:03 +08:00
|
|
|
|
- (void)viewWillAppear:(BOOL)animated {
|
|
|
|
|
|
[super viewWillAppear:animated];
|
|
|
|
|
|
// 进入页面时自动开始播放
|
|
|
|
|
|
[self kb_setupPermissionVideoPlayer];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidDisappear:(BOOL)animated {
|
|
|
|
|
|
[super viewDidDisappear:animated];
|
|
|
|
|
|
// 页面离开时停止播放,避免声音继续在其他界面播放
|
|
|
|
|
|
[self.kb_permPlayer pause];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLayoutSubviews {
|
|
|
|
|
|
[super viewDidLayoutSubviews];
|
|
|
|
|
|
if (!self.kb_permPlayerLayer) { return; }
|
2025-11-28 13:07:35 +08:00
|
|
|
|
// 以「宽度」为基准等比缩放视频,高度按宽高比计算,从 videoContainerView 顶部对齐,
|
|
|
|
|
|
// 多出的部分由容器(固定高度 KBFit(550))从底部裁剪
|
|
|
|
|
|
CGSize videoSize = self.kb_permPlayer.currentItem.presentationSize;
|
|
|
|
|
|
if (videoSize.width <= 0) { return; } // 尚未拿到真实尺寸时先不布局
|
|
|
|
|
|
|
|
|
|
|
|
CGFloat aspect = videoSize.height / videoSize.width;
|
|
|
|
|
|
CGRect containerBounds = self.videoContainerView.bounds;
|
|
|
|
|
|
if (CGRectIsEmpty(containerBounds)) { return; }
|
|
|
|
|
|
|
|
|
|
|
|
CGFloat width = CGRectGetWidth(containerBounds); // 以容器宽度为基准
|
|
|
|
|
|
CGFloat height = width * aspect; // 按宽度等比算出真实视频高度
|
|
|
|
|
|
|
|
|
|
|
|
// 顶部对齐,y = 0;若 height > 容器高度,则底部会被裁剪
|
|
|
|
|
|
self.kb_permPlayerLayer.frame = CGRectMake(0, 0, width, height);
|
2025-11-27 21:39:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
|
|
// 移除通知监听
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
2025-11-28 13:07:35 +08:00
|
|
|
|
@try {
|
|
|
|
|
|
[self.kb_permPlayer.currentItem removeObserver:self
|
|
|
|
|
|
forKeyPath:@"presentationSize"
|
|
|
|
|
|
context:KBPermPlayerPresentationSizeContext];
|
|
|
|
|
|
} @catch (__unused NSException *e) {
|
|
|
|
|
|
// ignore if observer not set
|
|
|
|
|
|
}
|
2025-11-27 21:39:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
#pragma mark - Actions
|
|
|
|
|
|
|
|
|
|
|
|
- (void)onBack {
|
2025-11-03 18:45:06 +08:00
|
|
|
|
// 支持两种展示方式:
|
|
|
|
|
|
// 1) 作为子控制器嵌入(无 presentingViewController)→ 交由回调让父 VC 处理(通常 pop)
|
|
|
|
|
|
// 2) 作为模态弹出 → 按原策略先 pop 再 dismiss
|
|
|
|
|
|
UIViewController *presenter = self.presentingViewController;
|
|
|
|
|
|
if (!presenter) {
|
|
|
|
|
|
if (self.backHandler) self.backHandler();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINavigationController *nav = nil;
|
|
|
|
|
|
if ([presenter isKindOfClass:UINavigationController.class]) {
|
|
|
|
|
|
nav = (UINavigationController *)presenter;
|
|
|
|
|
|
} else if (presenter.navigationController) {
|
|
|
|
|
|
nav = presenter.navigationController;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (nav) {
|
|
|
|
|
|
[nav popViewControllerAnimated:NO];
|
|
|
|
|
|
[nav dismissViewControllerAnimated:YES completion:^{ if (self.backHandler) self.backHandler(); }];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
[self dismissViewControllerAnimated:YES completion:^{ if (self.backHandler) self.backHandler(); }];
|
|
|
|
|
|
}
|
2025-10-27 20:07:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)openSettings {
|
|
|
|
|
|
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
|
|
|
|
|
|
UIApplication *app = [UIApplication sharedApplication];
|
|
|
|
|
|
if ([app canOpenURL:url]) {
|
|
|
|
|
|
if (@available(iOS 10.0, *)) {
|
|
|
|
|
|
[app openURL:url options:@{} completionHandler:nil];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
[app openURL:url];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
- (void)closeButtonAction{
|
|
|
|
|
|
[self.navigationController popViewControllerAnimated:true];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 21:39:03 +08:00
|
|
|
|
#pragma mark - Video Player
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化并开始在 cardView 中循环播放视频
|
|
|
|
|
|
- (void)kb_setupPermissionVideoPlayer {
|
|
|
|
|
|
// 避免重复初始化
|
|
|
|
|
|
if (self.kb_permPlayer) {
|
|
|
|
|
|
[self.kb_permPlayer play];
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"permiss_video" withExtension:@"mp4"];
|
|
|
|
|
|
if (!videoURL) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:videoURL];
|
|
|
|
|
|
self.kb_permPlayer = [AVPlayer playerWithPlayerItem:item];
|
|
|
|
|
|
self.kb_permPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
|
|
|
|
|
|
|
|
|
|
|
self.kb_permPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.kb_permPlayer];
|
|
|
|
|
|
// 使用等比模式,按我们计算好的 frame 显示;多余部分由容器裁剪
|
2025-11-28 13:07:35 +08:00
|
|
|
|
self.kb_permPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
|
2025-11-27 21:39:03 +08:00
|
|
|
|
self.kb_permPlayerLayer.cornerRadius = 20;
|
|
|
|
|
|
self.kb_permPlayerLayer.masksToBounds = true;
|
|
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
// 将视频图层添加到裁剪容器内部,由容器控制圆角与裁剪
|
|
|
|
|
|
[self.videoContainerView.layer addSublayer:self.kb_permPlayerLayer];
|
|
|
|
|
|
|
|
|
|
|
|
// 监听 presentationSize 变化,尺寸从 {0,0} 变为真实值时触发布局
|
|
|
|
|
|
[item addObserver:self
|
|
|
|
|
|
forKeyPath:@"presentationSize"
|
|
|
|
|
|
options:NSKeyValueObservingOptionNew
|
|
|
|
|
|
context:KBPermPlayerPresentationSizeContext];
|
2025-11-27 21:39:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 播放结束后从头循环
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
|
|
selector:@selector(kb_playerItemDidReachEnd:)
|
|
|
|
|
|
name:AVPlayerItemDidPlayToEndTimeNotification
|
|
|
|
|
|
object:item];
|
|
|
|
|
|
|
|
|
|
|
|
[self.kb_permPlayer play];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)kb_playerItemDidReachEnd:(NSNotification *)note {
|
|
|
|
|
|
AVPlayerItem *item = (AVPlayerItem *)note.object;
|
|
|
|
|
|
if (!item) return;
|
|
|
|
|
|
|
|
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
|
|
[item seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
|
|
|
|
|
|
__strong typeof(weakSelf) strongSelf = weakSelf;
|
|
|
|
|
|
[strongSelf.kb_permPlayer play];
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
|
|
|
|
ofObject:(id)object
|
|
|
|
|
|
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
|
|
|
|
|
|
context:(void *)context {
|
|
|
|
|
|
if (context == KBPermPlayerPresentationSizeContext) {
|
|
|
|
|
|
// presentationSize 从 {0,0} 变为真实尺寸时,触发布局更新
|
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
|
[self.view setNeedsLayout];
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
#pragma mark - Lazy Subviews
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)backButton {
|
|
|
|
|
|
if (!_backButton) {
|
|
|
|
|
|
_backButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
|
|
|
|
[_backButton setTitle:KBLocalized(@"common_back") forState:UIControlStateNormal];
|
|
|
|
|
|
_backButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
|
|
|
|
|
[_backButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
|
|
|
|
|
|
[_backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _backButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UILabel *)titleLabel {
|
|
|
|
|
|
if (!_titleLabel) {
|
|
|
|
|
|
_titleLabel = [UILabel new];
|
2025-11-14 16:34:01 +08:00
|
|
|
|
_titleLabel.text = (@"key of love keyboard");
|
|
|
|
|
|
_titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
_titleLabel.textColor = [UIColor blackColor];
|
|
|
|
|
|
_titleLabel.textAlignment = NSTextAlignmentCenter;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _titleLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UILabel *)tipsLabel {
|
|
|
|
|
|
if (!_tipsLabel) {
|
|
|
|
|
|
_tipsLabel = [UILabel new];
|
2025-11-14 16:34:01 +08:00
|
|
|
|
_tipsLabel.text = (@"One-click to find a partner");
|
2025-11-03 16:57:24 +08:00
|
|
|
|
_tipsLabel.font = [UIFont systemFontOfSize:14];
|
|
|
|
|
|
_tipsLabel.textColor = [UIColor darkGrayColor];
|
|
|
|
|
|
_tipsLabel.textAlignment = NSTextAlignmentCenter;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _tipsLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)openButton {
|
|
|
|
|
|
if (!_openButton) {
|
2025-11-14 16:34:01 +08:00
|
|
|
|
_openButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
|
[_openButton setTitle:@"Turn on the keyboard" forState:UIControlStateNormal];
|
|
|
|
|
|
_openButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
2025-11-03 16:57:24 +08:00
|
|
|
|
[_openButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
2025-11-14 16:34:01 +08:00
|
|
|
|
_openButton.backgroundColor = [UIColor colorWithHex:KBBlackValue];
|
|
|
|
|
|
_openButton.layer.cornerRadius = 30;
|
2025-11-03 16:57:24 +08:00
|
|
|
|
[_openButton addTarget:self action:@selector(openSettings) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _openButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
- (UIButton *)closeButton {
|
|
|
|
|
|
if (!_closeButton) {
|
|
|
|
|
|
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
|
[_closeButton setImage:[UIImage imageNamed:@"close_icon"] forState:UIControlStateNormal];
|
|
|
|
|
|
[_closeButton addTarget:self action:@selector(closeButtonAction) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _closeButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 16:57:24 +08:00
|
|
|
|
- (UILabel *)helpLabel {
|
|
|
|
|
|
if (!_helpLabel) {
|
|
|
|
|
|
_helpLabel = [UILabel new];
|
|
|
|
|
|
_helpLabel.text = KBLocalized(@"perm_help");
|
|
|
|
|
|
_helpLabel.font = [UIFont systemFontOfSize:12];
|
|
|
|
|
|
_helpLabel.textColor = [UIColor grayColor];
|
|
|
|
|
|
_helpLabel.textAlignment = NSTextAlignmentCenter;
|
|
|
|
|
|
_helpLabel.numberOfLines = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
return _helpLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
|
|
|
|
|
|
- (UIImageView *)bgImageView{
|
|
|
|
|
|
if (!_bgImageView) {
|
|
|
|
|
|
_bgImageView = [[UIImageView alloc] init];
|
|
|
|
|
|
_bgImageView.image = [UIImage imageNamed:@"qx_bg_icon"];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _bgImageView;
|
|
|
|
|
|
}
|
2025-11-28 13:07:35 +08:00
|
|
|
|
|
2025-11-14 16:34:01 +08:00
|
|
|
|
- (UIImageView *)redImageView{
|
|
|
|
|
|
if (!_redImageView) {
|
|
|
|
|
|
_redImageView = [[UIImageView alloc] init];
|
|
|
|
|
|
_redImageView.image = [UIImage imageNamed:@"qx_ax_icon"];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _redImageView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-28 13:07:35 +08:00
|
|
|
|
- (UIView *)videoContainerView {
|
|
|
|
|
|
if (!_videoContainerView) {
|
|
|
|
|
|
_videoContainerView = [UIView new];
|
|
|
|
|
|
_videoContainerView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
|
_videoContainerView.layer.cornerRadius = 20.0;
|
|
|
|
|
|
_videoContainerView.clipsToBounds = YES; // 超出容器高度的部分直接裁剪
|
|
|
|
|
|
}
|
|
|
|
|
|
return _videoContainerView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 20:07:37 +08:00
|
|
|
|
@end
|