Новичок в SwiftUI, пытающийся понять изменения макета без (я думаю, у него нет ) ограничений макета

#swiftui

Вопрос:

Проблема в том, что я не понимаю, как исправить мое представление контента на экране и обрабатывать такие вещи, как вращение, или даже как сделать другие размеры экрана динамичными. Ниже приведен весь мой код просмотра. Когда я создаю новое приложение из коробки, оно выглядит хорошо в предварительном просмотре, так, как мне нравится. Тем не менее, размеры экрана меняются, и все, что мне нужно сделать, — это ввести магические числа, потому что нет супервизора или кадра для определения размера. Кроме того, я, кажется, не могу обрезать края экрана. Так что мой фоновый вид очень велик. Как это обрабатывается в SwiftUI?

  import SwiftUI
 import AuthenticationServices


 struct LoginScreen: View {

     var body: some View {
    
         ZStack{
             backgroundLayout
             loginLayout
         }
    
     }

     var loginLayout: some View {
         VStack {
             welcomeText
             signInWithAppleButton
         }
     }


     var backgroundLayout: some View {
         ZStack{
             Rectangle()
                 .foregroundColor(.init(.sRGB, red: 0, green: 0.750, blue: 0.750, opacity: 0.25))
             Circle()
                 .foregroundColor(.blue)
                 .offset(x: 200, y: -200)
                 .aspectRatio(1/3, contentMode: .fill)
                 .clipped()
             Circle()
                 .foregroundColor(.green)
                 .offset(x: -200, y: 200)
                 .aspectRatio(1/3, contentMode: .fill)
                 .clipped()
         }
     }

     var welcomeText: some View {
    
         HStack {
             VStack {
                 Text("Sign Up")
                     .font(.largeTitle)
                     .bold()
                 Text("Sign In")
                     .font(.title)
                     .bold()
                 Text("Get Started!")
                     .font(.title2)
                     .bold()
             }
             .offset(x: -100, y: -150)
         }
     }

     var signInWithAppleButton: some View {
    
         SignInWithAppleButton(
             .continue,
        
             onRequest: { request in
                 request.requestedScopes = [.fullName, .email]
              },
             onCompletion: { result in
                  switch result {
                     case .success (let authenticationResults):
                         print("Authorization successful! :(authenticationResults)")
                     case .failure(let error):
                         print("Authorization failed: "   error.localizedDescription)
                  }
             }
         )
         .offset(x: 0, y: 150)
         .frame(width: 200, height: 50, alignment: .center)
    
         }

     }



     struct Login_Preview: PreviewProvider {

          static var previews: some View {
              LoginScreen()
    
          }
     }
 

Комментарии:

1. Если вы используете ZStack offset , вы, вероятно, делаете что-то не так. Используйте VStack или HStack вместо этого.

2. Как я буду создавать слои с любым из них? И как бы я обрезал круги?

3. Вы, вероятно, захотите взглянуть на GeometryReader . Это дает вам контроль над чертежами, которые вы делаете. Со следующим обновлением SwiftUI вы также можете рассмотреть возможность использования a Canvas в качестве фона (хотя это все еще бета-версия).

4. Я безуспешно пытался заглянуть в учебник геометрии. Не могли бы вы, пожалуйста, предоставить некоторый контекст того, как это могло бы удержать мое мнение с разумным смещением?

5. Чтобы понять ваше разочарование, я определенно был поставлен в тупик SwiftUI, особенно в самом начале. Было бы полезно разбить ваш вопрос на части, на которые можно ответить. Вот переписанный backgroundLayout , который делает фон размером с экран и центрирует круг в левом нижнем углу: gist.github.com/Baglan/7d16fa2dc124a436eac6eb62fda5ac8c

Ответ №1:

Попробовав несколько вещей, это все, что я смог придумать. Это не идеально и, конечно, не идеально, но, по крайней мере, работает примерно так, как ожидалось.

 import SwiftUI
import AuthenticationServices



struct LoginScreen: View {

var body: some View {
    loginLayout.background(backgroundLayout)
        .statusBar(hidden: true)
}

var loginLayout: some View {
    GeometryReader {geo in
        VStack {
            welcomeText.padding(.top, geo.size.height / 10)
            Spacer()
            signInWithAppleButton
                .padding(.bottom, geo.size.height / 10)
        }
    }
}


var backgroundLayout: some View {
    
    GeometryReader { geo in
        let circleSize = min(geo.size.width, geo.size.height)
        ZStack {
            Rectangle()
                .foregroundColor(.init(.sRGB, red: 0, green: 0.750, blue: 0.750, opacity: 0.25))
            
            Circle()
                .foregroundColor(.blue)
                .offset(x: circleSize / 1.75,
                        y: -geo.size.height / 2.5)
                .frame(width: circleSize, height: circleSize, alignment: .center)
            
            Circle()
                .foregroundColor(.green)
                .offset(x: -circleSize / 1.75,       y: geo.size.height / 2.5)
                .frame(width: circleSize, height: circleSize, alignment: .center)
        }
        .frame(width: geo.size.width, height: geo.size.height, alignment: .top)
    }
}

var welcomeText: some View {
    GeometryReader { geo in
    HStack {
        VStack {
            Text("Sign Up")
                .font(.largeTitle)
                .bold()
            Text("Sign In")
                .font(.title)
                .bold()
            Text("Get Started!")
                .font(.title2)
                .bold()
        }
        .padding(.leading, geo.size.width / 8)
        Spacer()
    }
    }
}

var signInWithAppleButton: some View {
    
    SignInWithAppleButton(
        // Add this below for Continue with Apple button
        .continue,
        
        onRequest: { request in
            request.requestedScopes = [.fullName, .email]
        },
        onCompletion: { result in
            switch result {
                case .success (let authenticationResults):
                    print("Authorization successful! :(authenticationResults)")
                case .failure(let error):
                    print("Authorization failed: "   error.localizedDescription)
            }
        }
    )
    .frame(width: 200, height: 50, alignment: .center)
}
}



struct Login_Preview: PreviewProvider {

    static var previews: some View {
        LoginScreen()
    
    }
}