UIButton 动态改变文本闪烁问题

本文详细介绍了在iOS开发中遇到按钮动态改变Title时出现闪烁的问题,并提供了有效的解决方法,通过在设置Title前先设置button.titleLabel.text来解决闪烁问题。

当动态改变(比如一秒改变一次)按钮的Title的时候发现按钮每次都要闪烁一下;解决方法如下:

    self.settleButton.titleLabel.text = title;

    [self.settleButton setTitle:title forState:UIControlStateNormal];

在用 setTtitle之前先设置button.titleLabel.text.

转载于:https://www.cnblogs.com/cnman/p/5181861.html

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // 保存当前播放状态和进度 NSIndexPath * indexPath = [self metalienKK_getCurrentIndexPath]; MetalienKKDynamicModel * currentModel = self.dataSource[indexPath.row]; CGFloat playTime = currentModel.currentPlaybackTime; BOOL wasPlaying = currentModel.isPlaying; BOOL willBeFullScreen = (size.width > size.height); currentModel.isFullScreen = willBeFullScreen; // 更新控件可见性 self.metalienKK_statusImageView.hidden = willBeFullScreen; self.backButton.hidden = willBeFullScreen; self.searchButton.hidden = willBeFullScreen; self.shareButton.hidden = willBeFullScreen; self.portraitButton.hidden = !willBeFullScreen; // 暂停当前播放但不重置 MetalienKKShortVideoItemCollectionViewCell * currentCell = [self.collectionView cellForItemAtIndexPath:indexPath]; [currentCell.metalienKK_playerView metalienKK_pauseShortVideoWithoutReset]; // 更新约束 [self metalienKK_updateContainerFrameForSize:size isFullScreen:willBeFullScreen atIndexPath:indexPath]; // 更新布局而不重载数据 [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) { // 立即刷新布局避免闪烁 [UIView performWithoutAnimation:^{ [self.collectionView.collectionViewLayout invalidateLayout]; [self.collectionView layoutIfNeeded]; [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO]; }]; // 更新旋转状态 [currentCell.metalienKK_playerView metalienKK_shortVideoPlayerViewRotate:willBeFullScreen]; } completion:^(id <UIViewControllerTransitionCoordinatorContext> context) { self.collectionView.scrollEnabled = !currentModel.isFullScreen; // 恢复播放状态 if (wasPlaying) { [currentCell.metalienKK_playerView metalienKK_startPlayShortVideo]; [currentCell.metalienKK_playerView metalienKK_seekToTime:playTime]; } else { [currentCell.metalienKK_playerView metalienKK_pauseShortVideo]; } // 执行等待中的动作 if (self.interfaceOrientationBlock) { self.interfaceOrientationBlock(); self.interfaceOrientationBlock = nil; } }]; } #import "MetalienKKShortVideoPlayerView.h" #define MetalienKK_kMiniPlayerViewHeight (265.0) #define MetalienKK_kBottomViewHeight (55.0 + MetalienKK_SafeAreaBottom) #define MetalienKK_kProgressViewSize CGSizeMake(MetalienKK_ScreenWidth - 15*2.0, 18.0) #define MetalienKK_kFullScreenDefaultSize CGSizeMake(110, 30) #define MetalienKK_FullScreenOpenButtonFont MetalienKK_RegularFont(12) @implementation MetalienKKShortVideoPlayerView /// 加载子视图 - (void)metalienKK_loadSubviews { // 新增视图 [self addSubview:self.metalienKK_playerView]; [self addSubview:self.metalienKK_maskView]; [self addSubview:self.metalienKK_bottomView]; [self addSubview:self.metalienKK_durationLabel]; [self addSubview:self.metalienKK_contentView]; [self addSubview:self.metalienKK_userView]; [self addSubview:self.metalienKK_progressView]; [self addSubview:self.metalienKK_popupView]; [self addSubview:self.metalienKK_loadingView]; [self addSubview:self.metalienKK_fullScreenButton]; [self addSubview:self.metalienKK_playImageView]; [self.metalienKK_playerView addSubview:self.metalienKK_videoEngine.playerView]; [self.metalienKK_bottomView addSubview:self.metalienKK_likeButton]; [self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_1]; [self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_2]; [self.metalienKK_bottomView addSubview:self.metalienKK_commentButton]; [self.metalienKK_bottomView addSubview:self.metalienKK_wowButton]; // 设置约束 [self.metalienKK_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.bottom.right.equalTo(self); make.height.mas_offset(MetalienKK_kBottomViewHeight); }]; [self.metalienKK_likeButton mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.metalienKK_bottomView); make.top.equalTo(self.metalienKK_bottomView); make.width.equalTo(self.metalienKK_bottomView.mas_width).multipliedBy(1/3.0); make.height.mas_offset(55.0); }]; [self.metalienKK_bottomLineView_1 mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.metalienKK_likeButton); make.right.equalTo(self.metalienKK_likeButton.mas_left); make.size.mas_offset(CGSizeMake(1, 20)); }]; [self.metalienKK_bottomLineView_2 mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.metalienKK_likeButton); make.left.equalTo(self.metalienKK_likeButton.mas_right); make.size.mas_equalTo(self.metalienKK_bottomLineView_1); }]; [self.metalienKK_commentButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.equalTo(self.metalienKK_bottomView); make.right.equalTo(self.metalienKK_bottomLineView_1.mas_left); make.height.mas_equalTo(self.metalienKK_likeButton); }]; [self.metalienKK_wowButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.right.equalTo(self.metalienKK_bottomView); make.left.equalTo(self.metalienKK_bottomLineView_2.mas_right); make.height.mas_equalTo(self.metalienKK_likeButton); }]; [self.metalienKK_playerView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight); }]; [self.metalienKK_videoEngine.playerView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; [self.metalienKK_popupView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.mas_bottom); // 初始位置在底部之外 make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; [self.metalienKK_maskView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; [self.metalienKK_playImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.size.mas_offset(CGSizeMake(40, 40)); }]; [self.metalienKK_progressView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.bottom.equalTo(self.metalienKK_bottomView.mas_top); make.size.mas_offset(MetalienKK_kProgressViewSize); }]; [self.metalienKK_durationLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(self.metalienKK_progressView); make.bottom.equalTo(self.metalienKK_progressView.mas_top); }]; [self.metalienKK_contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_progressView.mas_top); make.height.mas_offset(20.0); }]; [self.metalienKK_userView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12); make.height.mas_offset(36.0); }]; [self.metalienKK_fullScreenButton mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.size.mas_equalTo(MetalienKK_kFullScreenDefaultSize); }]; [self.metalienKK_loadingView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.metalienKK_playerView); make.left.right.equalTo(self).inset(15.0); make.height.mas_equalTo(60); }]; // 按钮布局 [self.metalienKK_commentButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; [self.metalienKK_likeButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; [self.metalienKK_wowButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0]; // 创建通知 [self metalienKK_setupNotifications]; } /// 创建通知 - (void)metalienKK_setupNotifications { // 应用进入后台时暂停 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActiveNotification) name:UIApplicationWillResignActiveNotification object:nil]; // 应用返回前台时恢复 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActiveNotification) name:UIApplicationDidBecomeActiveNotification object:nil]; } /// 显示&隐藏控件 - (void)metalienKK_showAndHiddenControls { self.metalienKK_fullScreenButton.hidden = self.responseData.isFullScreen ?:(!self.responseData.isHorizontalResolution); self.metalienKK_bottomView.hidden = self.responseData.isFullScreen; self.metalienKK_contentView.hidden = self.responseData.isFullScreen ?:!((self.responseData.isShowTitle || self.responseData.isShowContent)); self.metalienKK_durationLabel.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:YES; self.metalienKK_userView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO; self.metalienKK_progressView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO; } /// 重置约束 - (void)metalienKK_remarkConstraints { // 视频播放器 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self); make.left.right.equalTo(self).inset(self.responseData.isFullScreen ? 76.0:0.0); make.bottom.equalTo(self).offset(self.responseData.isFullScreen ? 0.0:(-MetalienKK_kBottomViewHeight)); }]; [self.metalienKK_videoEngine.playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.metalienKK_playerView); }]; // 用户信息视图 [self.metalienKK_userView mas_remakeConstraints:^(MASConstraintMaker *make) { if (self.responseData.isFullScreen) { make.top.equalTo(self).offset(20); make.left.right.equalTo(self).inset(94); } else { make.left.right.equalTo(self); if (!self.metalienKK_contentView.hidden) { make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12); } else { make.bottom.equalTo(self.metalienKK_progressView.mas_top); } } make.height.mas_offset(36.0); }]; // 进度条 [self.metalienKK_progressView mas_remakeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); if (self.responseData.isFullScreen) { make.left.right.equalTo(self).inset(50); make.bottom.equalTo(self).offset(-39); make.height.mas_equalTo(MetalienKK_kProgressViewSize.height); } else { make.bottom.equalTo(self.metalienKK_bottomView.mas_top); make.size.mas_offset(MetalienKK_kProgressViewSize); } }]; // 内容 if (!self.metalienKK_contentView.hidden) { [self.metalienKK_contentView mas_remakeConstraints:^(MASConstraintMaker *make) { CGFloat contentHeight = [self.metalienKK_contentView metalienKK_getContentViewHeight]; make.left.right.equalTo(self); make.bottom.equalTo(self.metalienKK_progressView.mas_top); make.height.mas_offset(contentHeight); }]; } // 全屏播放按钮 if (!self.metalienKK_fullScreenButton.hidden) { [self.metalienKK_fullScreenButton mas_remakeConstraints:^(MASConstraintMaker *make) { CGSize tempSize = [self.metalienKK_fullScreenButton.currentTitle metalienKK_calculateMultipleLinesTextSizeWithFont:MetalienKK_FullScreenOpenButtonFont andMaxSize:CGSizeMake(CGFLOAT_MAX, MetalienKK_kFullScreenDefaultSize.height)]; CGFloat tempWidth = 2*12.0 + 20.0 + 8.0 + tempSize.width; if (tempWidth < MetalienKK_kFullScreenDefaultSize.width) { tempWidth = MetalienKK_kFullScreenDefaultSize.width; } CGFloat tempVideoHeight = (self.responseData.videoHeight/(self.responseData.videoWidth*1.0)) * MetalienKK_ScreenWidth; make.centerX.equalTo(self.metalienKK_playerView); make.centerY.equalTo(self.metalienKK_playerView).offset(tempVideoHeight/2.0 + 12.0 + MetalienKK_kFullScreenDefaultSize.height/2.0); make.size.mas_equalTo(CGSizeMake(tempWidth, MetalienKK_kFullScreenDefaultSize.height)); }]; } // 立即刷新 [self layoutIfNeeded]; } # pragma mark - Public /// 视图复用 - (void)metalienKK_shortVideoPlayerViewReuse { // 暂停播放 [self metalienKK_pauseShortVideo]; // 重置播放器 [self.metalienKK_videoEngine resetPlayerVideoProcessor]; } /// 视图旋转 - (void)metalienKK_shortVideoPlayerViewRotate:(BOOL)isFullScreen { // 标记 self.responseData.isFullScreen = isFullScreen; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; // 重置约束 [self metalienKK_remarkConstraints]; } /// 刷新数据 - (void)metalienKK_reloadVideoPlayerViewWithData:(MetalienKKDynamicModel *)responseData { // 缓存 self.responseData = responseData; // 显示&隐藏控件 self.metalienKK_loadingView.hidden = responseData.isReadyDisplay; self.metalienKK_playImageView.hidden = YES; self.metalienKK_fullScreenButton.hidden = !responseData.isHorizontalResolution; // 刷新数据 [self.metalienKK_userView metalienKK_refreshShortVideoUser:responseData]; [self.metalienKK_popupView metalienKK_reloadShortVideoViewData:responseData]; // 判断是否显示文本 BOOL isShowContent = (responseData.isShowTitle || responseData.isShowContent); self.metalienKK_contentView.hidden = !isShowContent; if (isShowContent) { [self.metalienKK_contentView metalienKK_refreshShortVideoContent:responseData]; } // 视频进度 [self.metalienKK_progressView metalienKK_shortVideoSetProgress:responseData.currentPlaybackProgress]; // 设置视频资源 [self metalienKK_setupVideoEngineSource]; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; // 重置约束 [self metalienKK_remarkConstraints]; } /// 设置视频资源 - (void)metalienKK_setupVideoEngineSource { if (self.responseData.metalienKK_mediaID.length > 0 && self.responseData.metalienKK_mediaToken.length > 0) { // 设置视频资源(使用 Video ID) [self metalienKK_setShortVideoSourceWithVideoID:self.responseData.metalienKK_mediaID andToken:self.responseData.metalienKK_mediaToken]; } else if (self.responseData.metalienKK_href.length > 0) { // 设置视频资源(使用 HTTP URL) [self metalienKK_setShortVideoSourceWithURL:self.responseData.metalienKK_href]; } } /// 预加载方法 - (void)metalienKK_preloadVideo { // 设置视频资源 [self metalienKK_setupVideoEngineSource]; // 准备播放 [self.metalienKK_videoEngine prepareToPlay]; } /// 开始播放 - (void)metalienKK_startPlayShortVideo { // 标识 self.responseData.isPlaying = YES; // 隐藏播放按钮 self.metalienKK_playImageView.hidden = YES; // 弱引用 MetalienKK_WeakSelf(self); // 播放进度 [self.metalienKK_videoEngine addPeriodicTimeObserverForInterval:0.5 queue:dispatch_get_main_queue() usingBlock:^{ // 强引用 MetalienKK_StrongSelf(self); // 刷新视频播放进度 [self metalienKK_refreshShortVideoPlaybackProgress]; }]; // 指定视频播放开始时间 [self.metalienKK_videoEngine setOptionForKey:VEKKeyPlayerStartTime_CGFloat value:@(self.responseData.currentPlaybackTime)]; // 播放视频 [self.metalienKK_videoEngine play]; } /// 暂停播放 - (void)metalienKK_pauseShortVideo { // 显示播放按钮 self.metalienKK_playImageView.hidden = NO; // 手动标记 self.responseData.isPlaying = NO; // 暂停播放 [self.metalienKK_videoEngine pause:YES]; // 移除监听 [self.metalienKK_videoEngine removeTimeObserver]; } /// 重置播放器 - (void)metalienKK_resetPlayer { // 显示播放按钮 self.metalienKK_playImageView.hidden = NO; // 手动标记 self.responseData.isPlaying = NO; // // 视频进度 // [self.metalienKK_progressView metalienKK_shortVideoSetProgress:0]; // 移除监听 [self.metalienKK_videoEngine removeTimeObserver]; // 重置播放器 [self.metalienKK_videoEngine pause:YES]; // [self.metalienKK_videoEngine resetPlayerVideoProcessor]; } // 无重置的暂停 - (void)metalienKK_pauseShortVideoWithoutReset { [self.metalienKK_videoEngine pause]; self.responseData.isPlaying = NO; } // 跳转到指定时间 - (void)metalienKK_seekToTime:(CGFloat)time { MetalienKK_WeakSelf(self); [self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) { if (success) { [weak_self metalienKK_refreshShortVideoPlaybackProgress]; } }]; } # pragma mark - Notification Event /// App 进入后台 - (void)appWillResignActiveNotification { if (self.responseData.isPlaying) { [self metalienKK_pauseShortVideo]; } } /// App 即将进入前台 - (void)appDidBecomeActiveNotification { if (self.responseData.isPlaying) { [self metalienKK_startPlayShortVideo]; } } # pragma mark - Event /// 设置视频资源(使用 Video ID) - (void)metalienKK_setShortVideoSourceWithVideoID:(NSString *)videoID andToken:(NSString *)token { TTVideoEngineVidSource * videoSource = [[TTVideoEngineVidSource alloc] initWithVid:videoID playAuthToken:token resolution:TTVideoEngineResolutionTypeAuto]; [self.metalienKK_videoEngine setVideoEngineVideoSource:videoSource]; } /// 设置视频资源(使用 HTTP URL) - (void)metalienKK_setShortVideoSourceWithURL:(NSString *)videoURL { NSString * cacheKey = [videoURL metalienKK_coverToMD5String]; TTVideoEngineUrlSource * urlSource = [[TTVideoEngineUrlSource alloc] initWithUrl:videoURL cacheKey:cacheKey]; [self.metalienKK_videoEngine setVideoEngineVideoSource:urlSource]; } /// 刷新视频播放进度 - (void)metalienKK_refreshShortVideoPlaybackProgress { CGFloat playTime = self.metalienKK_videoEngine.currentPlaybackTime; CGFloat duration = self.metalienKK_videoEngine.duration; CGFloat progress = (playTime/duration); [self.metalienKK_progressView metalienKK_shortVideoSetProgress:progress]; // 视频播放进度 NSString * playTimeString = [NSString metalienKK_secondConvertToFormat:playTime]; NSString * durationString = [NSString metalienKK_secondConvertToFormat:duration]; NSString * content = [NSString stringWithFormat:@"%@ / %@", playTimeString, durationString]; NSRange playTimeRange = [content rangeOfString:playTimeString]; NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:content]; [attributedString addAttribute:NSForegroundColorAttributeName value:MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7) range:attributedString.yy_rangeOfAll]; [attributedString addAttribute:NSForegroundColorAttributeName value:UIColor.whiteColor range:playTimeRange]; self.metalienKK_durationLabel.attributedText = attributedString; // 缓存 self.responseData.currentPlaybackProgress = progress; self.responseData.currentPlaybackTime = playTime; } /// 弹出视图 - (void)metalienKK_showPopupViewAtIndex:(int)index { // 选中处理 if (index >= 0) { [self.metalienKK_popupView metalienKK_popupViewDidSelectIndex:index]; } // 控件显示&隐藏 self.metalienKK_fullScreenButton.hidden = YES; self.metalienKK_popupView.hidden = NO; // 标记是否弹出视图 [self metalienKK_markPopupViewIsShow:YES]; // 重置约束 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_kMiniPlayerViewHeight); }]; [self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.metalienKK_playerView.mas_bottom); make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; // 创建弹簧动画器 UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.75 initialVelocity:CGVectorMake(0.5, 0.5)]; UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.4 timingParameters:springParams]; [animator addAnimations:^{ // 强制立即刷新布局 [self layoutIfNeeded]; }]; [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { [self metalienKK_disableCollectionViewScroll:YES]; }]; [animator startAnimation]; } /// 关闭视图 - (void)metalienKK_closePopupView { // 标记是否弹出视图 [self metalienKK_markPopupViewIsShow:NO]; // 重置约束 [self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self); make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight); }]; [self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.mas_bottom); make.left.right.equalTo(self); make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight); }]; // 使用相同的动画参数 UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.8 initialVelocity:CGVectorMake(0, 0)]; UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.35 timingParameters:springParams]; [animator addAnimations:^{ // 强制立即刷新布局 [self layoutIfNeeded]; }]; [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution; self.metalienKK_popupView.hidden = YES; [self metalienKK_disableCollectionViewScroll:NO]; }]; [animator startAnimation]; } /// 标记是否弹出视图 - (void)metalienKK_markPopupViewIsShow:(BOOL)isShow { // 缓存 self.responseData.isShowingPopupView = isShow; // 弹出&收起视图 if ([self.delegate respondsToSelector:@selector(metalienKK_collectionViewCellDidShowPopupView:)]) { [self.delegate metalienKK_collectionViewCellDidShowPopupView:isShow]; } } /// 禁止滚动 - (void)metalienKK_disableCollectionViewScroll:(BOOL)isDisable { // 移除手势 [self.metalienKK_maskView removeGestureRecognizer:self.metalienKK_maskViewBlockPanGesture]; // 判断是否禁止 if (isDisable) { [self.metalienKK_maskView addGestureRecognizer:self.metalienKK_maskViewBlockPanGesture]; } } # pragma mark - Gesture /// 点击视频 - (void)metalienKK_maskViewTapGesture:(UITapGestureRecognizer *)gesture { // 判断是否正在弹出视图 if (self.responseData.isShowingPopupView) { [self metalienKK_closePopupView]; } else { if (self.metalienKK_videoEngine.playbackState == TTVideoEnginePlaybackStatePlaying) { [self metalienKK_pauseShortVideo]; } else { [self metalienKK_startPlayShortVideo]; } } } /// 点击内容视图 - (void)metalienKK_contentViewTapGesture:(UITapGestureRecognizer *)gesture { [self metalienKK_showPopupViewAtIndex:0]; } /// 视频窗口滑动手势 - (void)metalienKK_maskViewPanGesture:(UIPanGestureRecognizer *)gesture { // Nothing ... } /// 预览视图滑动手势 - (void)metalienKK_popupViewPanGesture:(UIPanGestureRecognizer *)gesture { static CGPoint originalCenter; static CGRect originalFrame; static CGFloat initialTranslationY; CGPoint translation = [gesture translationInView:self]; CGPoint velocity = [gesture velocityInView:self]; switch (gesture.state) { case UIGestureRecognizerStateBegan: // 记录初始位置 originalCenter = self.metalienKK_popupView.center; originalFrame = self.metalienKK_popupView.frame; initialTranslationY = translation.y; break; case UIGestureRecognizerStateChanged: { // 计算新的Y位置(限制在屏幕范围内) CGFloat newY = originalFrame.origin.y + translation.y; CGFloat minY = MetalienKK_kMiniPlayerViewHeight; CGFloat maxY = MetalienKK_ScreenHeight; // 限制拖拽范围(不能超过屏幕顶部/底部) newY = MIN(MAX(newY, minY), maxY); // 应用新位置 CGRect newFrame = originalFrame; newFrame.origin.y = newY; self.metalienKK_popupView.frame = newFrame; // 计算背景视图的高度变化(跟随拖拽) CGFloat backgroundHeight = MetalienKK_kMiniPlayerViewHeight + (newY - minY); [self.metalienKK_playerView mas_updateConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(backgroundHeight); }]; [self layoutIfNeeded]; break; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: { CGFloat currentY = self.metalienKK_popupView.frame.origin.y; CGFloat threshold = MetalienKK_ScreenHeight * 0.5; // 阈值设为屏幕高度的50% BOOL shouldClose = NO; // 根据速度或位置决定操作 if (velocity.y > 800) { // 快速下滑则关闭 shouldClose = YES; } else if (velocity.y < -800) { // 快速上滑则展开 shouldClose = NO; } else { // 根据位置决定 shouldClose = (currentY > threshold); } if (shouldClose) { [self metalienKK_closePopupView]; } else { [self metalienKK_showPopupViewAtIndex:-999]; } break; } default: break; } } #pragma mark - Action /// 全屏播放 - (void)metalienKK_fullScreenButtonAction:(UIButton *)sender { // 确保使用主线程执行旋转 dispatch_async(dispatch_get_main_queue(), ^{ if ([self.delegate respondsToSelector:@selector(metalienKK_fullScreenOpenButtonDidClick:)]) { [self.delegate metalienKK_fullScreenOpenButtonDidClick:sender]; } }); } /// 评论 - (void)metalienKK_commentButtonAction:(UIButton *)sender { [self metalienKK_showPopupViewAtIndex:1]; } /// 赞 & 取消赞 - (void)metalienKK_likeButtonAction:(UIButton *)sender { } /// 棒 & 取消棒 - (void)metalienKK_wowButtonAction:(UIButton *)sender { } # pragma mark - TTVideoEngineDelegate /// 播放停止回调 - (void)videoEngineUserStopped:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineUserStopped:"); } /// 播放结束回调 - (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine error:(nullable NSError *)error { MetalienKK_Log(@"videoEngineDidFinish:error:"); } /// 异常播放结束回调 - (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine videoStatusException:(NSInteger)status { MetalienKK_Log(@"videoEngineDidFinish:videoStatusException:"); } /// 播放器实例销毁回调 - (void)videoEngineCloseAysncFinish:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineCloseAysncFinish:"); } /// 播放状态改变回调 - (void)videoEngine:(TTVideoEngine *)videoEngine playbackStateDidChanged:(TTVideoEnginePlaybackState)playbackState { MetalienKK_Log(@"videoEngine:playbackStateDidChanged:"); self.responseData.isPlaying = (playbackState == TTVideoEnginePlaybackStatePlaying); self.metalienKK_progressView.isPlaying = self.responseData.isPlaying; // 显示&隐藏控件 [self metalienKK_showAndHiddenControls]; } /// 加载状态改变回调 - (void)videoEngine:(TTVideoEngine *)videoEngine loadStateDidChanged:(TTVideoEngineLoadState)loadState { MetalienKK_Log(@"videoEngine:loadStateDidChanged:"); if (loadState == TTVideoEngineLoadStatePlayable) { self.responseData.isLoading = NO; [self.metalienKK_progressView metalienKK_shortVideoStopLoadingAnimation]; } else { self.responseData.isLoading = YES; [self.metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation]; } } /// 播放器各模块准备完成、可以播放回调 - (void)videoEnginePrepared:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEnginePrepared:"); self.metalienKK_progressView.duration = videoEngine.duration; } /// 视频加载完成、开始播放回调 - (void)videoEngineReadyToPlay:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineReadyToPlay:"); } /// 显示视频首帧回调 - (void)videoEngineReadyToDisPlay:(TTVideoEngine *)videoEngine { MetalienKK_Log(@"videoEngineReadyToDisPlay:(width:%ld, height:%ld)", self.responseData.videoWidth, self.responseData.videoHeight); self.responseData.isReadyDisplay = YES; self.metalienKK_loadingView.hidden = YES; } # pragma mark - TTVideoEngineResolutionDelegate /// 视频分辨率发生变化回调 - (void)videoSizeDidChange:(TTVideoEngine *)videoEngine videoWidth:(NSInteger)videoWidth videoHeight:(NSInteger)videoHeight { MetalienKK_Log(@"videoSizeDidChange:videoWidth:%ld videoHeight:%ld", (long)videoWidth, (long)videoHeight); // 缓存信息 self.responseData.videoWidth = videoWidth; self.responseData.videoHeight = videoHeight; // 按钮显示状态 self.responseData.isHorizontalResolution = (self.responseData.videoWidth > self.responseData.videoHeight); self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution; // 重置约束 [self metalienKK_remarkConstraints]; } # pragma mark - Override - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (self.responseData.isShowingPopupView) { CGPoint commentPoint = [self.metalienKK_popupView convertPoint:point fromView:self]; if ([self.metalienKK_popupView pointInside:commentPoint withEvent:event]) { return [self.metalienKK_popupView hitTest:commentPoint withEvent:event]; } CGPoint maskPoint = [self.metalienKK_maskView convertPoint:point fromView:self]; if ([self.metalienKK_maskView pointInside:maskPoint withEvent:event]) { return self.metalienKK_maskView; } return self; } return [super hitTest:point withEvent:event]; } //# pragma mark - Helper // ///// 判断视图是否存在 //- (BOOL)metalienKK_isVideoEnginePlayerViewExist { // return [self.metalienKK_videoEngine.playerView isDescendantOfView:self.metalienKK_playerView]; //} # pragma mark - Getter - (TTVideoEngine *)metalienKK_videoEngine { if (!_metalienKK_videoEngine) { _metalienKK_videoEngine = [[TTVideoEngine alloc] initWithOwnPlayer:YES]; _metalienKK_videoEngine.delegate = self; _metalienKK_videoEngine.resolutionDelegate = self; _metalienKK_videoEngine.looping = YES; [_metalienKK_videoEngine setOptionForKey:VEKKeyViewScaleMode_ENUM value:@(TTVideoEngineScalingModeAspectFit)]; [_metalienKK_videoEngine setOptionForKey:VEKKeyAudioChannelEffect_ENUM value:@(TTVideoEngineAudioChannelNormal)]; // 播放 DASH 视频 [_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerBashEnabled_BOOL value:@(YES)]; [_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerDashEnabled_BOOL value:@(YES)]; } return _metalienKK_videoEngine; } - (MetalienKKShortVideoProgressView *)metalienKK_progressView { if (!_metalienKK_progressView) { // 弱引用 MetalienKK_WeakSelf(self); // 初始化 _metalienKK_progressView = [[MetalienKKShortVideoProgressView alloc] initWithFrame:CGRectMake(0, 0, MetalienKK_kProgressViewSize.width, MetalienKK_kProgressViewSize.height)]; [_metalienKK_progressView setOnSeek:^(NSInteger time) { // 强引用 MetalienKK_StrongSelf(self); // 跳转到指定的时间位置 [self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) { // Nothing ... }]; }]; [_metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation]; } return _metalienKK_progressView; } - (MetalienKKShortVideoContentPreviewView *)metalienKK_contentView { if (!_metalienKK_contentView) { _metalienKK_contentView = [[MetalienKKShortVideoContentPreviewView alloc] init]; _metalienKK_contentView.userInteractionEnabled = YES; // 添加手势 UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_contentViewTapGesture:)]; [_metalienKK_contentView addGestureRecognizer:tap]; } return _metalienKK_contentView; } - (MetalienKKShortVideoUserView *)metalienKK_userView { if (!_metalienKK_userView) { _metalienKK_userView = [[MetalienKKShortVideoUserView alloc] init]; } return _metalienKK_userView; } - (UIView *)metalienKK_playerView { if (!_metalienKK_playerView) { _metalienKK_playerView = [[UIView alloc] init]; _metalienKK_playerView.userInteractionEnabled = YES; } return _metalienKK_playerView; } - (UIView *)metalienKK_bottomView { if (!_metalienKK_bottomView) { _metalienKK_bottomView = [[UIView alloc] init]; _metalienKK_bottomView.backgroundColor = MetalienKK_ColorHex(@"#11111D"); } return _metalienKK_bottomView; } - (UIButton *)metalienKK_commentButton { if (!_metalienKK_commentButton) { _metalienKK_commentButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_commentButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_commentButton setTitle:MetalienKK_LocalizedString(@"评论") forState:UIControlStateNormal]; [_metalienKK_commentButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_commentButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_comment"] forState:UIControlStateNormal]; [_metalienKK_commentButton addTarget:self action:@selector(metalienKK_commentButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_commentButton; } - (UIButton *)metalienKK_likeButton { if (!_metalienKK_likeButton) { _metalienKK_likeButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_likeButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_likeButton setTitle:MetalienKK_LocalizedString(@"赞") forState:UIControlStateNormal]; [_metalienKK_likeButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_likeButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_like"] forState:UIControlStateNormal]; [_metalienKK_likeButton addTarget:self action:@selector(metalienKK_likeButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_likeButton; } - (UIButton *)metalienKK_wowButton { if (!_metalienKK_wowButton) { _metalienKK_wowButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_wowButton.titleLabel setFont:MetalienKK_BoldFont(14)]; [_metalienKK_wowButton setTitle:MetalienKK_LocalizedString(@"棒") forState:UIControlStateNormal]; [_metalienKK_wowButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal]; [_metalienKK_wowButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_WOW"] forState:UIControlStateNormal]; [_metalienKK_wowButton addTarget:self action:@selector(metalienKK_wowButtonAction:) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_wowButton; } - (UIView *)metalienKK_bottomLineView_1 { if (!_metalienKK_bottomLineView_1) { _metalienKK_bottomLineView_1 = [[UIView alloc] init]; _metalienKK_bottomLineView_1.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1); } return _metalienKK_bottomLineView_1; } - (UIView *)metalienKK_bottomLineView_2 { if (!_metalienKK_bottomLineView_2) { _metalienKK_bottomLineView_2 = [[UIView alloc] init]; _metalienKK_bottomLineView_2.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1); } return _metalienKK_bottomLineView_2; } - (UIImageView *)metalienKK_playImageView { if (!_metalienKK_playImageView) { _metalienKK_playImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_shortVideoPlay"]]; _metalienKK_playImageView.hidden = YES; } return _metalienKK_playImageView; } - (UIView *)metalienKK_maskView { if (!_metalienKK_maskView) { _metalienKK_maskView = [[UIView alloc] init]; _metalienKK_maskView.backgroundColor = UIColor.clearColor; _metalienKK_maskView.userInteractionEnabled = YES; // 添加手势 UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewTapGesture:)]; [_metalienKK_maskView addGestureRecognizer:tap]; } return _metalienKK_maskView; } - (UIPanGestureRecognizer *)metalienKK_maskViewBlockPanGesture { if (!_metalienKK_maskViewBlockPanGesture) { _metalienKK_maskViewBlockPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewPanGesture:)]; } return _metalienKK_maskViewBlockPanGesture; } - (UIPanGestureRecognizer *)metalienKK_popupViewPanGesture { if (!_metalienKK_popupViewPanGesture) { _metalienKK_popupViewPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_popupViewPanGesture:)]; } return _metalienKK_popupViewPanGesture; } - (MetalienKKShortVideoPopupView *)metalienKK_popupView { if (!_metalienKK_popupView) { // 初始化视图 _metalienKK_popupView = [[MetalienKKShortVideoPopupView alloc] init]; _metalienKK_popupView.backgroundColor = [UIColor whiteColor]; _metalienKK_popupView.clipsToBounds = YES; _metalienKK_popupView.layer.cornerRadius = 12.0; _metalienKK_popupView.hidden = YES; _metalienKK_popupView.parentViewPanGestureRecognizer = self.metalienKK_popupViewPanGesture; // 添加拖拽手势 [_metalienKK_popupView addGestureRecognizer:self.metalienKK_popupViewPanGesture]; // 添加按钮事件 [_metalienKK_popupView.metalienKK_commentView.metalienKK_closeButton addTarget:self action:@selector(metalienKK_closePopupView) forControlEvents:UIControlEventTouchUpInside]; } return _metalienKK_popupView; } - (UIButton *)metalienKK_fullScreenButton { if (!_metalienKK_fullScreenButton) { _metalienKK_fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_metalienKK_fullScreenButton setFrame:CGRectMake(0, 0, MetalienKK_kFullScreenDefaultSize.width, MetalienKK_kFullScreenDefaultSize.height)]; [_metalienKK_fullScreenButton.titleLabel setFont:MetalienKK_FullScreenOpenButtonFont]; [_metalienKK_fullScreenButton setTitle:MetalienKK_LocalizedString(@"全屏播放") forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_fullScreen_open"] forState:UIControlStateNormal]; [_metalienKK_fullScreenButton setClipsToBounds:YES]; [_metalienKK_fullScreenButton.layer setCornerRadius:MetalienKK_kFullScreenDefaultSize.height/2.0]; [_metalienKK_fullScreenButton.layer setBorderColor:MetalienKK_ColorHexAlpha(@"#FFFFFF", 0.15).CGColor]; [_metalienKK_fullScreenButton.layer setBorderWidth:1.0]; [_metalienKK_fullScreenButton addTarget:self action:@selector(metalienKK_fullScreenButtonAction:) forControlEvents:UIControlEventTouchUpInside]; [_metalienKK_fullScreenButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:8.0]; [_metalienKK_fullScreenButton setHidden:YES]; } return _metalienKK_fullScreenButton; } - (UILabel *)metalienKK_durationLabel { if (!_metalienKK_durationLabel) { _metalienKK_durationLabel = [[UILabel alloc] init]; _metalienKK_durationLabel.font = MetalienKK_RegularFont(14); _metalienKK_durationLabel.text = @"00:00 / 00:00"; _metalienKK_durationLabel.textColor = MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7); _metalienKK_durationLabel.hidden = YES; } return _metalienKK_durationLabel; } - (UIView *)metalienKK_loadingView { if (!_metalienKK_loadingView) { _metalienKK_loadingView = [[UIView alloc] init]; _metalienKK_loadingView.hidden = YES; // 添加图标 UIImageView * iconImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_metalienIconBig"]]; iconImageView.contentMode = UIViewContentModeScaleAspectFit; [_metalienKK_loadingView addSubview:iconImageView]; [iconImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.centerX.equalTo(_metalienKK_loadingView); make.size.mas_equalTo(CGSizeMake(40, 40)); }]; // 添加说明 UILabel * tipLabel = [[UILabel alloc] init]; tipLabel.font = MetalienKK_RegularFont(12); tipLabel.text = MetalienKK_LocalizedString(@"加载中..."); tipLabel.textColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.6); [_metalienKK_loadingView addSubview:tipLabel]; [tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(_metalienKK_loadingView); make.bottom.equalTo(_metalienKK_loadingView); }]; } return _metalienKK_loadingView; } # pragma mark - Dealloc - (void)dealloc { // 移除通知 [[NSNotificationCenter defaultCenter] removeObserver:self]; // 销毁播放器 [self.metalienKK_videoEngine stop]; [self.metalienKK_videoEngine removeTimeObserver]; [self.metalienKK_videoEngine.playerView removeFromSuperview]; [self.metalienKK_videoEngine closeAysnc]; self.metalienKK_videoEngine = nil; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end 旋转视图时,为什么播放器的视频会黑一下,再显示出来的?
07-17
优化下面的代码,使显示的图框更美观,图框布局更美观,显示的结果显示完全详细,增加和删除信号有显示:classdef TDMApp222 < matlab.apps.AppBase % Properties corresponding to app components properties (Access = public) UIFigure matlab.ui.Figure SignalConfigPanel matlab.ui.container.Panel NumSignalsEditField matlab.ui.control.NumericEditField NumSignalsLabel matlab.ui.control.Label SignalTypeDropDown matlab.ui.control.DropDown SignalTypeLabel matlab.ui.control.Label FrequencyEditField matlab.ui.control.NumericEditField FrequencyLabel matlab.ui.control.Label AddSignalButton matlab.ui.control.Button RemoveSignalButton matlab.ui.control.Button SignalsListBox matlab.ui.control.ListBox SignalsListLabel matlab.ui.control.Label StrategyPanel matlab.ui.container.Panel FixedRadioButton matlab.ui.control.RadioButton PriorityRadioButton matlab.ui.control.RadioButton StrategyButtonGroup matlab.ui.container.ButtonGroup TotalSlotsEditField matlab.ui.control.NumericEditField TotalSlotsLabel matlab.ui.control.Label SimulationPanel matlab.ui.container.Panel RunSimulationButton matlab.ui.control.Button RunFeedbackButton matlab.ui.control.Button RunAnalysisButton matlab.ui.control.Button ResultsTabGroup matlab.ui.container.TabGroup SignalsTab matlab.ui.container.Tab OriginalAxes matlab.ui.control.UIAxes TDMAxes matlab.ui.control.UIAxes DemuxAxes matlab.ui.control.UIAxes SyncedAxes matlab.ui.control.UIAxes PerformanceTab matlab.ui.container.Tab BERAxes matlab.ui.control.UIAxes ParametersTab matlab.ui.container.Tab ParametersTextArea matlab.ui.control.TextArea StatusLabel matlab.ui.control.Label ProgressBar matlab.ui.control.Lamp SNREditField matlab.ui.control.NumericEditField SNRLabel matlab.ui.control.Label IterationsEditField matlab.ui.control.NumericEditField IterationsLabel matlab.ui.control.Label DurationEditField matlab.ui.control.NumericEditField DurationLabel matlab.ui.control.Label SamplingRateEditField matlab.ui.control.NumericEditField SamplingRateLabel matlab.ui.control.Label PriorityWeightsLabel matlab.ui.control.Label PriorityWeightsEditField matlab.ui.control.EditField end properties (Access = private) signals % 存储信号配置的cell数组 params % 系统参数结构体 tdmSystem % TDMSystem实例 controller % TDMFeedbackController实例 analyzer % TDMPerformanceAnalyzer实例 end methods (Access = private) function updateParams(app) % 更新系统参数 - 修复时钟漂移初始化问题 app.params = struct(); app.params.fs = app.SamplingRateEditField.Value; app.params.duration = app.DurationEditField.Value; app.params.numSignals = numel(app.signals); app.params.snrDb = app.SNREditField.Value; app.params.iterations = app.IterationsEditField.Value; app.params.totalSlots = app.TotalSlotsEditField.Value; % 设置时隙分配策略 if app.FixedRadioButton.Value app.params.strategy = 'fixed'; else app.params.strategy = 'priority'; end % 动态设置时钟漂移(支持任意数量的信号) app.params.clockDrift = zeros(1, app.params.numSignals); if app.params.numSignals >= 1 app.params.clockDrift(1) = 0.001; end if app.params.numSignals >= 2 app.params.clockDrift(2) = 0.002; end if app.params.numSignals >= 3 app.params.clockDrift(3:end) = -0.001; end % 解析优先级权重 if ~isempty(app.PriorityWeightsEditField.Value) try weights = str2num(app.PriorityWeightsEditField.Value); if numel(weights) ~= app.params.numSignals error('权重数量必须等于信号数量'); end app.params.priorities = weights / sum(weights); catch % 使用默认权重 app.params.priorities = ones(1, app.params.numSignals) / app.params.numSignals; end else % 默认权重 app.params.priorities = ones(1, app.params.numSignals) / app.params.numSignals; end end function generateSignals(app) % 生成信号数据 - 支持任意数量的信号 t = 0:1/app.params.fs:app.params.duration-1/app.params.fs; numSamples = length(t); app.tdmSystem.signals = zeros(app.params.numSignals, numSamples); app.tdmSystem.signalInfo = cell(app.params.numSignals, 1); for i = 1:app.params.numSignals sigConfig = app.signals{i}; switch sigConfig.type case '正弦波' freq = sigConfig.frequency; amp = sigConfig.amplitude; app.tdmSystem.signals(i, :) = amp * sin(2*pi*freq*t); app.tdmSystem.signalInfo{i} = sprintf('正弦波 (%dHz, %.1fV)', freq, amp); case '方波' freq = sigConfig.frequency; amp = sigConfig.amplitude; duty = sigConfig.dutyCycle; app.tdmSystem.signals(i, :) = amp * square(2*pi*freq*t, duty); app.tdmSystem.signalInfo{i} = sprintf('方波 (%dHz, %.1fV, %.0f%%)', freq, amp, duty); case '随机噪声' amp = sigConfig.amplitude; app.tdmSystem.signals(i, :) = amp * randn(1, numSamples); app.tdmSystem.signalInfo{i} = sprintf('随机噪声 (σ=%.1fV)', amp); case '锯齿波' freq = sigConfig.frequency; amp = sigConfig.amplitude; app.tdmSystem.signals(i, :) = amp * sawtooth(2*pi*freq*t); app.tdmSystem.signalInfo{i} = sprintf('锯齿波 (%dHz, %.1fV)', freq, amp); case '脉冲信号' freq = sigConfig.frequency; amp = sigConfig.amplitude; duty = 0.3; % 占空比 app.tdmSystem.signals(i, :) = amp * pulstran(t, 0:1/freq:app.params.duration, ... 'rectpuls', duty/freq); app.tdmSystem.signalInfo{i} = sprintf('脉冲信号 (%dHz, %.1fV)', freq, amp); end end end function updateParametersDisplay(app) % 更新参数显示 - 添加优先级权重信息 paramText = sprintf('系统参数:\n'); paramText = [paramText sprintf('采样频率: %d Hz\n', app.params.fs)]; paramText = [paramText sprintf('信号持续时间: %.2f 秒\n', app.params.duration)]; paramText = [paramText sprintf('信号源数量: %d\n', app.params.numSignals)]; paramText = [paramText sprintf('信噪比: %d dB\n', app.params.snrDb)]; paramText = [paramText sprintf('时隙分配策略: %s\n', app.params.strategy)]; paramText = [paramText sprintf('总时隙数量: %d\n', app.params.totalSlots)]; paramText = [paramText sprintf('仿真迭代次数: %d\n', app.params.iterations)]; % 添加信号信息 paramText = [paramText sprintf('\n信号配置:\n')]; for i = 1:app.params.numSignals sig = app.signals{i}; switch sig.type case {'正弦波', '方波', '锯齿波', '脉冲信号'} paramText = [paramText sprintf('信号 %d: %s (频率: %d Hz, 振幅: %.1fV)', ... i, sig.type, sig.frequency, sig.amplitude)]; if strcmp(sig.type, '方波') paramText = [paramText sprintf(', 占空比: %.0f%%', sig.dutyCycle)]; end paramText = [paramText newline]; case '随机噪声' paramText = [paramText sprintf('信号 %d: %s (振幅: %.1fV)', ... i, sig.type, sig.amplitude) newline]; end end % 添加优先级权重 paramText = [paramText sprintf('\n优先级权重:\n')]; for i = 1:app.params.numSignals paramText = [paramText sprintf('信号 %d: %.2f\n', i, app.params.priorities(i))]; end app.ParametersTextArea.Value = paramText; end function plotSignals(app) % 绘制原始信号 - 优化布局 t = 0:1/app.params.fs:app.params.duration-1/app.params.fs; colors = lines(app.params.numSignals); % 原始信号 cla(app.OriginalAxes); if app.params.numSignals > 0 hold(app.OriginalAxes, 'on'); for i = 1:app.params.numSignals plot(app.OriginalAxes, t, app.tdmSystem.signals(i, :), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end hold(app.OriginalAxes, 'off'); legend(app.OriginalAxes, 'Location', 'best', 'Interpreter', 'none'); title(app.OriginalAxes, '原始信号'); xlabel(app.OriginalAxes, '时间 (s)'); ylabel(app.OriginalAxes, '幅度'); grid(app.OriginalAxes, 'on'); end % TDM信号 cla(app.TDMAxes); if ~isempty(app.tdmSystem.tdmSignal) plot(app.TDMAxes, t, app.tdmSystem.tdmSignal); title(app.TDMAxes, ['TDM复用信号 (' app.params.strategy '策略)']); xlabel(app.TDMAxes, '时间 (s)'); ylabel(app.TDMAxes, '幅度'); grid(app.TDMAxes, 'on'); end % 解复用信号 cla(app.DemuxAxes); if ~isempty(app.tdmSystem.demuxSignals) && app.params.numSignals > 0 hold(app.DemuxAxes, 'on'); for i = 1:app.params.numSignals plot(app.DemuxAxes, t, app.tdmSystem.demuxSignals(i, :), ... 'Color', colors(i, :), 'DisplayName', ['信号 ' num2str(i)]); end hold(app.DemuxAxes, 'off'); legend(app.DemuxAxes, 'Location', 'best'); title(app.DemuxAxes, '解复用信号'); xlabel(app.DemuxAxes, '时间 (s)'); ylabel(app.DemuxAxes, '幅度'); grid(app.DemuxAxes, 'on'); end % 同步后信号 cla(app.SyncedAxes); if ~isempty(app.tdmSystem.syncedSignals) && app.params.numSignals > 0 hold(app.SyncedAxes, 'on'); for i = 1:app.params.numSignals plot(app.SyncedAxes, t, app.tdmSystem.syncedSignals(i, :), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end hold(app.SyncedAxes, 'off'); legend(app.SyncedAxes, 'Location', 'best', 'Interpreter', 'none'); title(app.SyncedAxes, '同步后信号'); xlabel(app.SyncedAxes, '时间 (s)'); ylabel(app.SyncedAxes, '幅度'); grid(app.SyncedAxes, 'on'); end % 误码率 cla(app.BERAxes); if ~isempty(app.tdmSystem.ber) && app.params.numSignals > 0 bar(app.BERAxes, 1:app.params.numSignals, app.tdmSystem.ber, 0.6, 'FaceColor', [0.2 0.4 0.8]); title(app.BERAxes, '各信号的均方误差'); xlabel(app.BERAxes, '信号编号'); ylabel(app.BERAxes, '均方误差 (MSE)'); grid(app.BERAxes, 'on'); xticks(app.BERAxes, 1:app.params.numSignals); % 添加数据标签 hold(app.BERAxes, 'on'); for i = 1:app.params.numSignals text(app.BERAxes, i, app.tdmSystem.ber(i), ... sprintf('%.4f', app.tdmSystem.ber(i)), ... 'HorizontalAlignment', 'center', ... 'VerticalAlignment', 'bottom'); end hold(app.BERAxes, 'off'); end end end % Callbacks that handle component events methods (Access = private) % Code that executes after component creation function startupFcn(app) % 初始化参数 app.signals = {}; app.params = struct(); app.StatusLabel.Text = '准备就绪'; app.ProgressBar.Color = 'green'; % 设置默认参数 app.SamplingRateEditField.Value = 1000; app.DurationEditField.Value = 1; app.SNREditField.Value = 20; app.IterationsEditField.Value = 5; app.TotalSlotsEditField.Value = 50; app.NumSignalsEditField.Value = 0; app.PriorityRadioButton.Value = true; app.PriorityWeightsEditField.Value = ''; % 更新参数显示 updateParams(app); updateParametersDisplay(app); end % Button pushed function: AddSignalButton function AddSignalButtonPushed(app, ~) % 添加新信号 - 支持振幅参数 signalType = app.SignalTypeDropDown.Value; frequency = app.FrequencyEditField.Value; amplitude = 1.0; % 默认振幅 dutyCycle = 50; % 默认占空比 if frequency <= 0 uialert(app.UIFigure, '频率必须大于0', '无效参数'); return; end % 为方波添加占空比配置 if strcmp(signalType, '方波') dutyCycle = inputdlg('请输入占空比 (0-100):', '方波参数', [1 40], {'50'}); if isempty(dutyCycle) return; end dutyCycle = str2double(dutyCycle{1}); if isnan(dutyCycle) || dutyCycle < 0 || dutyCycle > 100 uialert(app.UIFigure, '占空比必须在0-100之间', '无效参数'); return; end end % 为所有信号添加振幅配置 amplitude = inputdlg('请输入信号振幅:', '振幅参数', [1 40], {'1.0'}); if isempty(amplitude) return; end amplitude = str2double(amplitude{1}); if isnan(amplitude) || amplitude <= 0 uialert(app.UIFigure, '振幅必须大于0', '无效参数'); return; end newSignal = struct(... 'type', signalType, ... 'frequency', frequency, ... 'amplitude', amplitude, ... 'dutyCycle', dutyCycle); app.signals{end+1} = newSignal; app.NumSignalsEditField.Value = numel(app.signals); % 更新信号列表 signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; switch sig.type case {'正弦极波', '方波', '锯齿波', '脉冲信号'} signalList{i} = sprintf('信号 %d: %s (%d Hz, %.1fV)', i, sig.type, sig.frequency, sig.amplitude); case '随机噪声' signalList{i} = sprintf('信号 %极d: %s (σ=%.1fV)', i, sig.type, sig.amplitude); end end app.SignalsListBox.Items = signalList; % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已添加信号: %s (%d Hz, %.1fV)', signalType, frequency, amplitude); end % Button pushed function: RemoveSignalButton function RemoveSignalButtonPushed(app, ~) % 移除选中的信号 selectedIdx = app.SignalsListBox.Value; if isempty(selectedIdx) || selectedIdx > numel(app.signals) uialert(app.UIFigure, '请选择要删除的信号', '无选择'); return; end % 移除信号 removedSig = app.signals{selectedIdx}; app.signals(selectedIdx) = []; % 更新信号列表 app.NumSignalsEditField.Value = numel(app.signals); signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; switch sig.type case {'正弦波', '方波', '锯齿波', '脉冲信号'} signalList{i} = sprintf('信号 %d: %s (%d Hz, %.1fV)', i, sig.type, sig.frequency, sig.amplitude); case '随机噪声' signalList{i} = sprintf('信号 %d: %s (σ=%.1fV)', i, sig.type, sig.amplitude); end end app.SignalsListBox.Items = signalList; % 如果没有信号,清除选择 if isempty(app.signals) app.SignalsListBox.Value = []; else app.SignalsListBox.Value = min(selectedIdx, numel(app.signals)); end % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已移除信号: %s (%d Hz, %.1fV)', removedSig.type, removedSig.frequency, removedSig.amplitude); end % Value changed function: NumSignalsEditField function NumSignalsEditFieldValueChanged(app, ~) % 信号数量变化时更新 updateParams(app); updateParametersDisplay(app); end % Value changed function: SamplingRateEditField function SamplingRateEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: DurationEditField function DurationEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: SNREditField function SNREditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: IterationsEditField function IterationsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: TotalSlotsEditField function TotalSlotsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Selection changed function: StrategyButtonGroup function StrategyButtonGroupSelectionChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Button pushed function: RunSimulationButton function RunSimulationButtonPushed(app, ~) % 运行基础仿真 app.StatusLabel.Text = '运行基础仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 检查总时隙数 if app.params.totalSlots < app.params.numSignals uialert(app.UIFigure, '总时隙数必须大于等于信号数量', '无效参数'); app.ProgressBar.Color = 'red'; return; end % 创建TDM系统 app.tdmSystem = TDMSystem(app.params); % 生成信号 generateSignals(app); % 运行仿真 app.tdmSystem = app.tdmSystem.runSimulation(); % 显示结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '基础仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunFeedbackButton function RunFeedbackButtonPushed(app, ~) % 运行反馈控制仿真 app.StatusLabel.Text = '运行反馈控制仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 检查总时隙数 if app.params.totalSlots < app.params.numSignals uialert(app.UIFigure, '总时隙数必须大于等于信号数量', '无效参数'); app.ProgressBar.Color = 'red'; return; end % 创建反馈控制器 app.controller = TDMFeedbackController(app.params); % 生成信号 generateSignals(app); % 运行反馈仿真 app.controller.runFeedbackSimulation(); % 显示结果 app.tdmSystem = app.controller; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '反馈控制仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunAnalysisButton function RunAnalysisButtonPushed(app, ~) % 运行性能分析 app.StatusLabel.Text = '运行性能分析...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 检查总时隙数 if app.params.totalSlots < app.params.numSignals uialert(app.UIFigure, '总时隙数必须大于等于信号数量', '无效参数'); app.ProgressBar.Color = 'red'; return; end % 创建性能分析器 - 使用优化后的类 app.analyzer = TDMPerformanceAnalyzer(app.params); % 生成信号 generateSignals(app); % 运行性能分析 - 调用正确的方法 app.analyzer.runPerformanceAnalysis(); % 显示结果 app.tdmSystem = app.analyzer; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '性能分析完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Value changed function: PriorityWeightsEditField function PriorityWeightsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end end % App initialization and construction methods (Access = private) % Create UIFigure and components function createComponents(app) % Create UIFigure app.UIFigure = uifigure; app.UIFigure.Position = [100 100 1200 850]; app.UIFigure.Name = 'TDM通信系统仿真'; app.UIFigure.Scrollable = 'on'; % Create SignalConfigPanel app.SignalConfigPanel = uipanel(app.UIFigure); app.SignalConfigPanel.Title = '信号配置'; app.SignalConfigPanel.Position = [20 620 360 200]; % Create NumSignalsLabel app.NumSignalsLabel = uilabel(app.SignalConfigPanel); app.NumSignalsLabel.Position = [20 160 80 22]; app.NumSignalsLabel.Text = '信号数量:'; % Create NumSignalsEditField app.NumSignalsEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.NumSignalsEditField.Position = [110 160 60 22]; app.NumSignalsEditField.Value = 0; app.NumSignalsEditField.Editable = 'off'; % 设置为只读 app.NumSignalsEditField.ValueChangedFcn = createCallbackFcn(app, @NumSignalsEditFieldValueChanged, true); % Create SignalTypeLabel app.SignalTypeLabel = uilabel(app.SignalConfigPanel); app.SignalTypeLabel.Position = [20 130 80 22]; app.SignalTypeLabel.Text = '信号类型:'; % Create SignalTypeDropDown app.SignalTypeDropDown = uidropdown(app.SignalConfigPanel); app.SignalTypeDropDown.Position = [110 130 100 22]; app.SignalTypeDropDown.Items = {'正弦波', '方波', '随机噪声', '锯齿波', '脉冲信号'}; % Create FrequencyLabel app.FrequencyLabel = uilabel(app.SignalConfigPanel); app.FrequencyLabel.Position = [20 100 80 22]; app.FrequencyLabel.Text = '频率 (Hz):'; % Create FrequencyEditField app.FrequencyEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.FrequencyEditField.Position = [110 100 60 22]; app.FrequencyEditField.Value = 50; % Create AddSignalButton app.AddSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.AddSignalButton.ButtonPushedFcn = createCallbackFcn(app, @AddSignalButtonPushed, true); app.AddSignalButton.Position = [220 130 100 22]; app.AddSignalButton.Text = '添加信号'; % Create RemoveSignalButton app.RemoveSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.RemoveSignalButton.ButtonPushedFcn = createCallbackFcn(app, @RemoveSignalButtonPushed, true); app.RemoveSignalButton.Position = [220 100 100 22]; app.RemoveSignalButton.Text = '移除信号'; % Create SignalsListLabel app.SignalsListLabel = uilabel(app.SignalConfigPanel); app.SignalsListLabel.Position = [20 70 80 22]; app.SignalsListLabel.Text = '信号列表:'; % Create SignalsListBox app.SignalsListBox = uilistbox(app.SignalConfigPanel); app.SignalsListBox.Position = [20 20 300 50]; app.SignalsListBox.Items = {}; % Create StrategyPanel app.StrategyPanel = uipanel(app.UIFigure); app.StrategyPanel.Title = '时隙分配策略'; app.StrategyPanel.Position = [400 620 250 200]; % Create StrategyButtonGroup app.StrategyButtonGroup = uibuttongroup(app.StrategyPanel); app.StrategyButtonGroup.SelectionChangedFcn = createCallbackFcn(app, @StrategyButtonGroupSelectionChanged, true); app.StrategyButtonGroup.Position = [20 100 200 80]; app.StrategyButtonGroup.Title = '选择策略'; % Create FixedRadioButton app.FixedRadioButton = uiradiobutton(app.StrategyButtonGroup); app.FixedRadioButton.Text = '固定分配'; app.FixedRadioButton.Position = [11 35 75 22]; % Create PriorityRadioButton app.PriorityRadioButton = uiradiobutton(app.StrategyButtonGroup); app.PriorityRadioButton.Text = '优先级分配'; app.PriorityRadioButton.Position = [11 10 100 22]; app.PriorityRadioButton.Value = true; % Create TotalSlotsLabel app.TotalSlotsLabel = uilabel(app.StrategyPanel); app.TotalSlotsLabel.Position = [20 60 80 22]; app.TotalSlotsLabel.Text = '总时隙数:'; % Create TotalSlotsEditField app.TotalSlotsEditField = uieditfield(app.StrategyPanel, 'numeric'); app.TotalSlotsEditField.ValueChangedFcn = createCallbackFcn(app, @TotalSlotsEditFieldValueChanged, true); app.TotalSlotsEditField.Position = [110 60 60 22]; app.TotalSlotsEditField.Value = 50; % Create SimulationPanel app.SimulationPanel = uipanel(app.UIFigure); app.SimulationPanel.Title = '仿真控制'; app.SimulationPanel.Position = [670 620 250 200]; % Create RunSimulationButton app.RunSimulationButton = uibutton(app.SimulationPanel, 'push'); app.RunSimulationButton.ButtonPushedFcn = createCallbackFcn(app, @RunSimulationButtonPushed, true); app.RunSimulationButton.Position = [30 150 190 30]; app.RunSimulationButton.Text = '运行系统仿真'; % Create RunFeedbackButton app.RunFeedbackButton = uibutton(app.SimulationPanel, 'push'); app.RunFeedbackButton.ButtonPushedFcn = createCallbackFcn(app, @RunFeedbackButtonPushed, true); app.RunFeedbackButton.Position = [30 100 190 30]; app.RunFeedbackButton.Text = '运行反馈控制'; % Create RunAnalysisButton app.RunAnalysisButton = uibutton(app.SimulationPanel, 'push'); app.RunAnalysisButton.ButtonPushedFcn = createCallbackFcn(app, @RunAnalysisButtonPushed, true); app.RunAnalysisButton.Position = [30 50 190 30]; app.RunAnalysisButton.Text = '运行性能分析'; % Create ResultsTabGroup app.ResultsTabGroup = uitabgroup(app.UIFigure); app.ResultsTabGroup.Position = [20 20 1150 580]; % Create SignalsTab app.SignalsTab = uitab(app.ResultsTabGroup); app.SignalsTab.Title = '信号可视化'; % Create OriginalAxes app.OriginalAxes = uiaxes(app.SignalsTab); title(app.OriginalAxes, '原始信号') xlabel(app.OriginalAxes, '时间 (s)') ylabel(app.OriginalAxes, '幅度') app.OriginalAxes.Position = [20 300 530 250]; app.OriginalAxes.Toolbar = []; % Create TDMAxes app.TDMAxes = uiaxes(app.SignalsTab); title(app.TDMAxes, 'TDM复用信号') xlabel(app.TDMAxes, '时间 (s)') ylabel(app.TDMAxes, '幅度') app.TDMAxes.Position = [20 20 530 250]; app.TDMAxes.Toolbar = []; % Create DemuxAxes app.DemuxAxes = uiaxes(app.SignalsTab); title(app.DemuxAxes, '解复用信号') xlabel(app.DemuxAxes, '时间 (s)') ylabel(app.DemuxAxes, '幅度') app.DemuxAxes.Position = [580 300 530 250]; app.DemuxAxes.Toolbar = []; % Create SyncedAxes app.SyncedAxes = uiaxes(app.SignalsTab); title(app.SyncedAxes, '同步后信号') xlabel(app.SyncedAxes, '时间 (s)') ylabel(app.SyncedAxes, '幅度') app.SyncedAxes.Position = [580 20 530 250]; app.SyncedAxes.Toolbar = []; % Create PerformanceTab app.PerformanceTab = uitab(app.ResultsTabGroup); app.PerformanceTab.Title = '性能分析'; % Create BERAxes app.BERAxes = uiaxes(app.PerformanceTab); title(app.BERAxes, '均方误差 (MSE)') xlabel(app.BERAxes, '信号编号') ylabel(app.BERAxes, 'MSE') app.BERAxes.Position = [50 150 1000 400]; app.BERAxes.Toolbar = []; % Create ParametersTab app.ParametersTab = uitab(app.ResultsTabGroup); app.ParametersTab.Title = '系统参数'; % Create ParametersTextArea app.ParametersTextArea = uitextarea(app.ParametersTab); app.ParametersTextArea.Position = [20 50 1100 500]; app.ParametersTextArea.Value = {'系统参数将在此显示'}; % Create StatusLabel app.StatusLabel = uilabel(app.UIFigure); app.StatusLabel.HorizontalAlignment = 'right'; app.StatusLabel.Position = [100 830 800 22]; app.StatusLabel.Text = '准备就绪'; % Create ProgressBar app.ProgressBar = uilamp(app.UIFigure); app.ProgressBar.Position = [930 830 20 20]; app.ProgressBar.Color = [0.47 0.67 0.19]; % Create SNRLabel app.SNRLabel = uilabel(app.UIFigure); app.SNRLabel.Position = [950 620 80 22]; app.SNRLabel.Text = '信噪比 (dB):'; % Create SNREditField app.SNREditField = uieditfield(app.UIFigure, 'numeric'); app.SNREditField.ValueChangedFcn = createCallbackFcn(app, @SNREditFieldValueChanged, true); app.SNREditField.Position = [1040 620 60 22]; app.SNREditField.Value = 20; % Create IterationsLabel app.IterationsLabel = uilabel(app.UIFigure); app.IterationsLabel.Position = [950 590 80 22]; app.IterationsLabel.Text = '迭代次数:'; % Create IterationsEditField app.IterationsEditField = uieditfield(app.UIFigure, 'numeric'); app.IterationsEditField.ValueChangedFcn = createCallbackFcn(app, @IterationsEditFieldValueChanged, true); app.IterationsEditField.Position = [1040 590 60 22]; app.IterationsEditField.Value = 5; % Create DurationLabel app.DurationLabel = uilabel(app.UIFigure); app.DurationLabel.Position = [950 560 80 22]; app.DurationLabel.Text = '持续时间 (s):'; % Create DurationEditField app.DurationEditField = uieditfield(app.UIFigure, 'numeric'); app.DurationEditField.ValueChangedFcn = createCallbackFcn(app, @DurationEditFieldValueChanged, true); app.DurationEditField.Position = [1040 560 60 22]; app.DurationEditField.Value = 1; % Create SamplingRateLabel app.SamplingRateLabel = uilabel(app.UIFigure); app.SamplingRateLabel.Position = [950 530 80 22]; app.SamplingRateLabel.Text = '采样率 (Hz):'; % Create SamplingRateEditField app.SamplingRateEditField = uieditfield(app.UIFigure, 'numeric'); app.SamplingRateEditField.ValueChangedFcn = createCallbackFcn(app, @SamplingRateEditFieldValueChanged, true); app.SamplingRateEditField.Position = [1040 530 60 22]; app.SamplingRateEditField.Value = 1000; % Create PriorityWeightsLabel app.PriorityWeightsLabel = uilabel(app.UIFigure); app.PriorityWeightsLabel.Position = [950 500 100 22]; app.PriorityWeightsLabel.Text = '优先级权重:'; % Create PriorityWeightsEditField app.PriorityWeightsEditField = uieditfield(app.UIFigure, 'text'); app.PriorityWeightsEditField.ValueChangedFcn = createCallbackFcn(app, @PriorityWeightsEditFieldValueChanged, true); app.PriorityWeightsEditField.Position = [1040 500 120 22]; app.PriorityWeightsEditField.Value = ''; app.PriorityWeightsEditField.Tooltip = '输入权重向量,如: [0.4, 0.3, 0.3]'; end end methods (Access = public) % Construct app function app = TDMApp222 % Create and configure components createComponents(app) % Register the app with App Designer registerApp(app, app.UIFigure) % Execute the startup function runStartupFcn(app, @startupFcn) if nargout == 0 clear app end end % Code that executes before app deletion function delete(app) % Delete UIFigure when app is deleted delete(app.UIFigure) end end end
06-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值