解决UI的布局问题

This commit is contained in:
anlicheng 2026-03-24 18:05:42 +08:00
parent 21be7cef58
commit e4a0728345
6 changed files with 65 additions and 73 deletions

View File

@ -16,7 +16,14 @@ class AppContext {
var networkContext: SDLAPIClient.NetworkContext = .default()
// app
var appScene: AppScene = .login(username: nil)
var loginScene: LoginScene = .login(username: nil)
//
enum LoginScene: Equatable {
case login(username: String?)
case register
case resetPassword
}
//
var loginCredit: Credit?
@ -40,14 +47,6 @@ class AppContext {
}
}
//
enum AppScene: Equatable {
case login(username: String?)
case logined
case register
case resetPassword
}
init(noticePort: Int) {
self.noticePort = noticePort
}

View File

@ -77,7 +77,6 @@ struct LoginView: View {
}
.padding(.bottom, 20)
}
.frame(width: 380, height: 520)
}
}
@ -106,7 +105,7 @@ struct LoginAccountView: View {
HStack {
Button("注册") {
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .register
self.appContext.loginScene = .register
}
}
.buttonStyle(.link)
@ -115,7 +114,7 @@ struct LoginAccountView: View {
Button("忘记密码?") {
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .resetPassword
self.appContext.loginScene = .resetPassword
}
}
.buttonStyle(.link)
@ -170,7 +169,7 @@ struct LoginAccountView: View {
do {
_ = try await appContext.loginWith(username: username, password: password)
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .logined
//self.appContext.appScene = .logined
}
} catch let err as SDLAPIError {
self.showAlert = true
@ -231,7 +230,7 @@ struct LoginTokenView: View {
do {
_ = try await appContext.loginWith(token: token)
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .logined
//self.appContext.appScene = .logined
}
} catch let err as SDLAPIError {
self.showAlert = true

View File

@ -7,7 +7,7 @@
import SwiftUI
struct RootView: View {
struct LoginRootView: View {
@Environment(AppContext.self) var appContext: AppContext
@State private var updateManager = AppUpdateManager.shared
@ -16,13 +16,10 @@ struct RootView: View {
// 1.
// 使 ZStack Group
ZStack(alignment: .center) {
switch appContext.appScene {
switch appContext.loginScene {
case .login(username: let username):
LoginView(username: username)
.id("scene_login") // ID
case .logined:
NetworkView()
.id("scene_logined")
case .register:
RegisterRootView()
.id("scene_register")
@ -32,9 +29,7 @@ struct RootView: View {
}
}
// 2.
// maxWidth/Height .infinity
// minWidth/minHeight
.frame(maxWidth: .infinity, maxHeight: .infinity)
.frame(width: 380, height: 500)
// 3. RootView
.clipped()
.transition(.asymmetric(
@ -48,7 +43,7 @@ struct RootView: View {
}
}
// 4. Scene
.animation(.spring(duration: 0.5), value: appContext.appScene)
.animation(.spring(duration: 0.5), value: appContext.loginScene)
.animation(.spring(duration: 0.4), value: updateManager.showUpdateOverlay)
// macOS
.background(VisualEffectView(material: .hudWindow, blendingMode: .behindWindow))
@ -82,8 +77,5 @@ struct RootView: View {
))
.zIndex(100) //
}
}
#Preview {
RootView()
}

View File

@ -14,21 +14,25 @@ struct RegisterRootView: View {
var body: some View {
ZStack(alignment: .center) {
switch registerModel.stage {
case .requestVerifyCode:
RegisterRequestVerifyCodeView()
case .submitVerifyCode:
RegisterSubmitVerifyCodeView()
case .setPassword:
RegisterSetPasswordView()
case .success:
RegisterSuccessView()
Color.clear
ZStack(alignment: .center) {
switch registerModel.stage {
case .requestVerifyCode:
RegisterRequestVerifyCodeView()
case .submitVerifyCode:
RegisterSubmitVerifyCodeView()
case .setPassword:
RegisterSetPasswordView()
case .success:
RegisterSuccessView()
}
}
.transition(.asymmetric(
insertion: .move(edge: registerModel.transitionEdge).combined(with: .opacity),
removal: .move(edge: registerModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
))
}
.transition(.asymmetric(
insertion: .move(edge: registerModel.transitionEdge).combined(with: .opacity),
removal: .move(edge: registerModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
))
.environment(registerModel)
// --- 使 overlay ---
.overlay(alignment: .topLeading) {
@ -40,7 +44,7 @@ struct RegisterRootView: View {
Button(action: {
//
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .login(username: nil)
self.appContext.loginScene = .login(username: nil)
}
}) {
HStack {
@ -127,8 +131,6 @@ struct RegisterRequestVerifyCodeView: View {
.controlSize(.large)
.frame(width: 280)
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
Spacer()
}
.padding(40)
.alert(isPresented: $showAlert) {
@ -244,8 +246,6 @@ struct RegisterSubmitVerifyCodeView: View {
.foregroundColor(.secondary)
}
.frame(width: 280)
Spacer()
}
.padding(40)
.alert(isPresented: $showAlert) {
@ -362,8 +362,6 @@ struct RegisterSetPasswordView: View {
.controlSize(.large)
.frame(width: 280)
.disabled(passwordError != nil)
Spacer()
}
.padding(40)
.alert(isPresented: $showAlert) {
@ -441,7 +439,7 @@ struct RegisterSuccessView: View {
Button(action: {
//
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .login(username: registerModel.username)
self.appContext.loginScene = .login(username: registerModel.username)
}
}) {
Text("立即开始使用")

View File

@ -14,21 +14,25 @@ struct ResetPasswordRootView: View {
var body: some View {
ZStack(alignment: .center) {
switch resetPasswordModel.stage {
case .requestVerifyCode:
GetVerifyCodeView()
case .submitVerifyCode:
SubmitVerifyCodeView()
case .resetPassword:
ResetPasswordView()
case .success:
ResetPasswordSuccessView()
Color.clear
ZStack(alignment: .center) {
switch resetPasswordModel.stage {
case .requestVerifyCode:
GetVerifyCodeView()
case .submitVerifyCode:
SubmitVerifyCodeView()
case .resetPassword:
ResetPasswordView()
case .success:
ResetPasswordSuccessView()
}
}
.transition(.asymmetric(
insertion: .move(edge: resetPasswordModel.transitionEdge).combined(with: .opacity),
removal: .move(edge: resetPasswordModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
))
}
.transition(.asymmetric(
insertion: .move(edge: resetPasswordModel.transitionEdge).combined(with: .opacity),
removal: .move(edge: resetPasswordModel.transitionEdge == .trailing ? .leading : .trailing).combined(with: .opacity)
))
.environment(resetPasswordModel)
.overlay(alignment: .topLeading) {
//
@ -36,7 +40,7 @@ struct ResetPasswordRootView: View {
Button(action: {
//
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .login(username: nil)
self.appContext.loginScene = .login(username: nil)
}
}) {
HStack {
@ -86,8 +90,6 @@ struct GetVerifyCodeView: View {
.controlSize(.large)
.frame(width: 280)
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
Spacer()
}
.padding(40)
.alert(isPresented: $showAlert) {
@ -179,8 +181,6 @@ struct SubmitVerifyCodeView: View {
.foregroundColor(.secondary)
}
.frame(width: 280)
Spacer()
}
.padding(40)
.task {
@ -294,8 +294,6 @@ struct ResetPasswordView: View {
.controlSize(.large)
.frame(width: 280)
.disabled(!isInputValid || isProcessing)
Spacer()
}
.padding(40)
.alert(isPresented: $showAlert) {
@ -364,7 +362,7 @@ struct ResetPasswordSuccessView: View {
Button(action: {
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
self.appContext.appScene = .login(username: self.resetPasswordModel.username)
self.appContext.loginScene = .login(username: self.resetPasswordModel.username)
}
}) {
Text("返回登录")
@ -377,8 +375,6 @@ struct ResetPasswordSuccessView: View {
}
.opacity(animateText ? 1.0 : 0.0)
.offset(y: animateText ? 0 : 20)
Spacer()
}
.padding(40)
.frame(maxWidth: .infinity, maxHeight: .infinity)

View File

@ -43,8 +43,8 @@ struct punchnetApp: App {
}
var body: some Scene {
WindowGroup(id: "main") {
RootView()
Window("登陆", id: "login") {
LoginRootView()
.navigationTitle("")
.environment(self.appContext)
.onAppear {
@ -59,6 +59,14 @@ struct punchnetApp: App {
.windowToolbarStyle(.unified)
.defaultPosition(.center)
Window("网络", id: "logined") {
SettingsView()
.environment(self.appContext)
.frame(width: 750, height: 500)
}
.windowResizability(.contentSize)
.defaultPosition(.center)
Window("设置", id: "settings") {
SettingsView()
.environment(self.appContext)