iOS26 UI adaption: host view navigation bar

This commit is contained in:
True Zhuanjia committed 2026-03-07 10:08:17 +08:00
1 parent 4b56a44a47
commit 4a9e7ad2a1
3 files changed
+71 -43

No files matched your search

+17 -17
View File
@@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>GCSupportsGameMode</key>
<true/>
<key>CADisableMinimumFrameDuration</key> <key>CADisableMinimumFrameDuration</key>
<true/> <true/>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
@@ -58,31 +56,24 @@
<string>Bluetooth access allows Moonlight to connect to Citrix X1 mice.</string> <string>Bluetooth access allows Moonlight to connect to Citrix X1 mice.</string>
<key>NSBluetoothPeripheralUsageDescription</key> <key>NSBluetoothPeripheralUsageDescription</key>
<string>Bluetooth access allows Moonlight to connect to Citrix X1 mice.</string> <string>Bluetooth access allows Moonlight to connect to Citrix X1 mice.</string>
<key>NSMicrophoneUsageDescription</key>
<string>VoidLink需要麦克风访问权限。现阶段,麦克风重定向仅支持Sunshine基地版,且麦克风音频流【未经加密】。
VoidLink uses microphone to stream your voice to gaming PC. Microphone redirection currently works with Sunshine-Foundation (a fork of Sunshine) only, and the mic audio stream is NOT ENCRYPTED at this stage.</string>
<key>NSBonjourServices</key> <key>NSBonjourServices</key>
<array> <array>
<string>_nvstream._tcp</string> <string>_nvstream._tcp</string>
</array> </array>
<key>NSLocalNetworkUsageDescription</key> <key>NSLocalNetworkUsageDescription</key>
<string>VoidLink uses the local network to connect to your gaming PC for streaming.</string> <string>VoidLink uses the local network to connect to your gaming PC for streaming.</string>
<key>NSMicrophoneUsageDescription</key>
<string>VoidLink需要麦克风访问权限。现阶段,麦克风重定向仅支持Sunshine基地版,且麦克风音频流【未经加密】。
VoidLink uses microphone to stream your voice to gaming PC. Microphone redirection currently works with Sunshine-Foundation (a fork of Sunshine) only, and the mic audio stream is NOT ENCRYPTED at this stage.</string>
<key>NSMotionUsageDescription</key> <key>NSMotionUsageDescription</key>
<string>VoidLink uses the device Gyro and Acceleration data to emulate motion controls when streaming.</string> <string>VoidLink uses the device Gyro and Acceleration data to emulate motion controls when streaming.</string>
<key>UIApplicationSceneManifest</key> <key>UIApplicationSceneManifest</key>
<dict> <dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key> <key>UISceneConfigurations</key>
<dict> <dict>
<key>UIWindowSceneSessionRoleExternalDisplay</key>
<array>
<dict>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>External Display Configuration</string>
</dict>
</array>
<key>UIWindowSceneSessionRoleApplication</key> <key>UIWindowSceneSessionRoleApplication</key>
<array> <array>
<dict> <dict>
@@ -92,9 +83,16 @@ VoidLink uses microphone to stream your voice to gaming PC. Microphone redirecti
<string>SceneDelegate</string> <string>SceneDelegate</string>
</dict> </dict>
</array> </array>
<key>UIWindowSceneSessionRoleExternalDisplay</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>External Display Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict> </dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict> </dict>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
@@ -102,6 +100,8 @@ VoidLink uses microphone to stream your voice to gaming PC. Microphone redirecti
<array> <array>
<string>audio</string> <string>audio</string>
</array> </array>
<key>UIDesignRequiresCompatibility</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>Launch Screen</string> <string>Launch Screen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
+10
View File
@@ -49,4 +49,14 @@ import Foundation
@objc static func isIPad() -> Bool { @objc static func isIPad() -> Bool {
return UIDevice.current.userInterfaceIdiom == .pad return UIDevice.current.userInterfaceIdiom == .pad
} }
@objc static let liquidGlassEnabled: Bool = {
if #available(iOS 26.0, tvOS 26.0, *) {
let useLegacyUI = Bundle.main.object(forInfoDictionaryKey: "UIDesignRequiresCompatibility") as? Bool
return useLegacyUI != true
} else {
return false
}
}()
} }
@@ -148,11 +148,13 @@ static NSMutableSet* hostList;
- (void)updateTitle { - (void)updateTitle {
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
UINavigationBarAppearance* appearance = navBarAppearanceStandard;
NSDictionary* titleTextAttributes = @{ NSDictionary* titleTextAttributes = @{
NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium], NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium],
NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色
}; };
[navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; appearance.titleTextAttributes = titleTextAttributes;
navBarAppearanceStandard = appearance;
} }
if (_selectedHost != nil) { if (_selectedHost != nil) {
@@ -164,11 +166,14 @@ static NSMutableSet* hostList;
} }
else { else {
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
UINavigationBarAppearance* appearance = navBarAppearanceStandard;
NSDictionary* titleTextAttributes = @{ NSDictionary* titleTextAttributes = @{
NSFontAttributeName: [UIFont systemFontOfSize:22 weight:UIFontWeightMedium], NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium],
NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色
}; };
[navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; appearance.titleTextAttributes = titleTextAttributes;
navBarAppearanceStandard = appearance;
} }
/* /*
self.navigationController.navigationBar.titleTextAttributes = @{ self.navigationController.navigationBar.titleTextAttributes = @{
@@ -1386,26 +1391,35 @@ static NSMutableSet* hostList;
// 创建按钮 // 创建按钮
CGFloat buttonHeight = 30; CGFloat buttonHeight = 30;
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor = [ThemeManager appPrimaryColor]; // #0A85FF button.backgroundColor = GenericUtils.liquidGlassEnabled ? UIColor.whiteColor : [ThemeManager appPrimaryColor]; // #0A85FF
button.layer.cornerRadius = buttonHeight/2; button.layer.cornerRadius = buttonHeight/2;
button.clipsToBounds = YES; button.clipsToBounds = !GenericUtils.liquidGlassEnabled;
// 设置图标(SF Symbol) // 设置图标(SF Symbol)
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:17 weight:UIImageSymbolWeightMedium]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration
configurationWithPointSize:GenericUtils.liquidGlassEnabled ? 18.7 :17
weight:GenericUtils.liquidGlassEnabled ? UIImageSymbolWeightRegular :UIImageSymbolWeightMedium];
UIImage *image = [UIImage systemImageNamed:@"plus.circle" withConfiguration:config]; UIImage *image = [UIImage systemImageNamed:@"plus.circle" withConfiguration:config];
[button setImage:image forState:UIControlStateNormal]; [button setImage:image forState:UIControlStateNormal];
[button setTitle:[LocalizationHelper localizedStringForKey:@" Add Host"] forState:UIControlStateNormal]; // 注意空格用于间隔 button.imageEdgeInsets = GenericUtils.liquidGlassEnabled ? UIEdgeInsetsMake(0, 7.6, 0.75, 0) : UIEdgeInsetsZero;;
NSString* buttonStringHead = GenericUtils.liquidGlassEnabled ? @" " : @"";
[button setTitle: [buttonStringHead stringByAppendingString:
[LocalizationHelper localizedStringForKey:@" Add Host"]]
forState:UIControlStateNormal]; // 注意空格用于间隔
} else { } else {
[button setTitle:[LocalizationHelper localizedStringForKey:@"Add Host"] forState:UIControlStateNormal]; // 注意空格用于间隔 [button setTitle:[LocalizationHelper localizedStringForKey:@"Add Host"] forState:UIControlStateNormal]; // 注意空格用于间隔
} }
// [button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; // [button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; button.titleLabel.font = [UIFont systemFontOfSize:GenericUtils.liquidGlassEnabled ? 17 : 16 weight:UIFontWeightMedium];
// 文字颜色设置为 tintColor 控制 // 文字颜色设置为 tintColor 控制
button.tintColor = UIColor.whiteColor; if(GenericUtils.liquidGlassEnabled) button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0.9, 0);
button.tintColor = GenericUtils.liquidGlassEnabled ? [ThemeManager appPrimaryColor] : UIColor.whiteColor;
[button setTitleColor:button.tintColor forState:UIControlStateNormal]; [button setTitleColor:button.tintColor forState:UIControlStateNormal];
// button.tintColor = UIColor.whiteColor;
// [button setTitleColor:button.tintColor forState:UIControlStateNormal];
// 设置按下时的 tintColor(变灰或淡) // 设置按下时的 tintColor(变灰或淡)
UIColor *highlightColor = [ThemeManager textColorGray]; UIColor *highlightColor = [ThemeManager textColorGray];
@@ -1420,6 +1434,7 @@ static NSMutableSet* hostList;
// 创建 UIBarButtonItem // 创建 UIBarButtonItem
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:button]; UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:button];
return barItem; return barItem;
} }
@@ -1433,7 +1448,9 @@ static NSMutableSet* hostList;
// 设置图标(SF Symbol) // 设置图标(SF Symbol)
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:buttonHeight*0.85 weight:UIImageSymbolWeightRegular]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:
GenericUtils.liquidGlassEnabled ? buttonHeight*0.73 : buttonHeight*0.85
weight:UIImageSymbolWeightRegular];
UIImage *image = [UIImage systemImageNamed:@"questionmark.circle" withConfiguration:config]; UIImage *image = [UIImage systemImageNamed:@"questionmark.circle" withConfiguration:config];
[button setImage:image forState:UIControlStateNormal]; [button setImage:image forState:UIControlStateNormal];
[button setTitle:@"" forState:UIControlStateNormal]; // 注意空格用于间隔 [button setTitle:@"" forState:UIControlStateNormal]; // 注意空格用于间隔
@@ -1486,19 +1503,17 @@ static NSMutableSet* hostList;
- (void)setupNavBar{ - (void)setupNavBar{
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
Class appearanceClass = NSClassFromString(@"UINavigationBarAppearance"); UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init];
navBarAppearanceStandard = [[appearanceClass alloc] init]; [appearance configureWithOpaqueBackground];
[navBarAppearanceStandard performSelector:@selector(configureWithOpaqueBackground)]; // 不透明 appearance.backgroundColor = [ThemeManager hostViewBackgroundColor];
[navBarAppearanceStandard setValue:[ThemeManager hostViewBackgroundColor] forKey:@"backgroundColor"]; // 设置你需要的背景色 appearance.shadowColor = nil;
[navBarAppearanceStandard setValue:nil forKey:@"shadowColor"]; // 设置你需要的背景色
NSDictionary* titleTextAttributes = @{ NSDictionary* titleTextAttributes = @{
NSForegroundColorAttributeName: [ThemeManager textColor] NSForegroundColorAttributeName: [ThemeManager textColor]
}; };
[navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; appearance.titleTextAttributes = titleTextAttributes;
[navBarAppearanceStandard setValue:[UIColor clearColor] forKey:@"shadowColor"]; appearance.shadowColor = [UIColor clearColor];
[navBarAppearanceStandard setValue:nil forKey:@"backgroundImage"]; appearance.backgroundImage = nil;
navBarAppearanceStandard = appearance;
//navBarAppearanceStandard.backgroundImage = nil;
} }
[self applyNavBarAppearance]; [self applyNavBarAppearance];
@@ -1516,10 +1531,10 @@ static NSMutableSet* hostList;
[_settingsButton setAction:@selector(revealToggle:)]; [_settingsButton setAction:@selector(revealToggle:)];
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
[_settingsButton setTitle:nil]; [_settingsButton setTitle:nil];
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:23 weight:UIImageSymbolWeightMedium ]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:GenericUtils.liquidGlassEnabled ? 18 : 23 weight:UIImageSymbolWeightMedium ];
UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[_settingsButton setImage:image]; [_settingsButton setImage:image];
_settingsButton.imageInsets = UIEdgeInsetsMake(10, 10, 0, 0); _settingsButton.imageInsets = GenericUtils.liquidGlassEnabled ? UIEdgeInsetsMake(0, 0, 0, 0.55) : UIEdgeInsetsMake(10, 10, 0, 0);
} else { } else {
[_settingsButton setTitle:[LocalizationHelper localizedStringForKey:@"Settings"]]; [_settingsButton setTitle:[LocalizationHelper localizedStringForKey:@"Settings"]];
} }
@@ -1530,9 +1545,10 @@ static NSMutableSet* hostList;
// Set the host name button action. When it's tapped, it'll show the host selection view. // Set the host name button action. When it's tapped, it'll show the host selection view.
_upButton = [[UIBarButtonItem alloc] init]; _upButton = [[UIBarButtonItem alloc] init];
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
[_upButton setTitle:@""]; [_upButton setTitle:@""];
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:21.5 weight:UIImageSymbolWeightMedium ]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:21.5 weight:UIImageSymbolWeightMedium];
UIImage *image = [[UIImage systemImageNamed:@"tv" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; UIImage *image = [[UIImage systemImageNamed:@"tv" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[_upButton setImage:image]; [_upButton setImage:image];
_upButton.imageInsets = UIEdgeInsetsMake(25, 20, 0, 15); _upButton.imageInsets = UIEdgeInsetsMake(25, 20, 0, 15);
@@ -1551,16 +1567,18 @@ static NSMutableSet* hostList;
self.collectionView.backgroundColor = [ThemeManager hostViewBackgroundColor]; self.collectionView.backgroundColor = [ThemeManager hostViewBackgroundColor];
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *)) {
[navBarAppearanceStandard setValue:[ThemeManager hostViewBackgroundColor] forKey:@"backgroundColor"]; UINavigationBarAppearance* appearance = navBarAppearanceStandard;
appearance.backgroundColor = [ThemeManager hostViewBackgroundColor];
NSDictionary* titleTextAttributes = @{ NSDictionary* titleTextAttributes = @{
NSForegroundColorAttributeName: [ThemeManager textColor] NSForegroundColorAttributeName: [ThemeManager textColor]
}; };
[navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; appearance.titleTextAttributes = titleTextAttributes;
navBarAppearanceStandard = appearance;
} }
_settingsButton.tintColor = [ThemeManager appPrimaryColor]; _settingsButton.tintColor = [ThemeManager appPrimaryColor];
_upButton.tintColor = [ThemeManager appPrimaryColor]; _upButton.tintColor = [ThemeManager appPrimaryColor];
((UIButton*)_addHostButton.customView).backgroundColor = [ThemeManager appPrimaryColor]; ((UIButton*)_addHostButton.customView).backgroundColor = GenericUtils.liquidGlassEnabled ? UIColor.clearColor : [ThemeManager appPrimaryColor];
((UIButton*)_helpButton.customView).tintColor = [ThemeManager appPrimaryColor]; ((UIButton*)_helpButton.customView).tintColor = [ThemeManager appPrimaryColor];
[self applyNavBarAppearance]; [self applyNavBarAppearance];