Sunday, 27 October 2019

SwiftUI - Canvas exceeding screen width - App Rejected

My app was rejected twice on submission to the app store based on an issue where the login screen is exceeding the boundaries of an iPad display. I have tried to replicate the issue but cannot on the simulator or on a physical iPad

Apple sent me the following response

From Apple
4. Design: Preamble
Guideline 4.0 - Design

We noticed that the login screen of your app was still crowded or laid out in a way that made it difficult to use your app.
We launched the app on iPad (6th generation) running iOS 13.1.3 on Wifi.

Next Steps
To resolve this issue, please revise your app to ensure that the content and controls on the screen are easy to read and interact with.

Resources
For more information, please review the following resources on the iOS Developer Center page:

   - UI Do's and Don'ts
   - iOS Human Interface Guidelines
   - UIKit

Please see attached screenshot for details.

Clipped login screen

I cannot replicate this. Here's my code:

Login.swift

import SwiftUI

struct Login: View {

    @EnvironmentObject var session: SessionStore
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: KeyboardGuardian.KeyboardSlots.count.rawValue)

    @State var email: String = ""
    @State var password: String = ""
    @State var loading = false
    @State var error = false


    func getUser () {
        session.listen()
    }

    func signIn () {
        loading = true
        error = false
        session.signIn(email: email, password: password) { (result, error) in
            self.loading = false
            if error != nil {
                self.error = true
            } else {
                self.email = ""
                self.password = ""
            }
        }
    }

    var body: some View {
        VStack {
            Image("Cloud Pager")
                .resizable()
                .foregroundColor(.white)
                .aspectRatio(contentMode: ContentMode.fill)
                .padding()

            Text("Cloud Pager")
                .font(.largeTitle)
                .foregroundColor(.white)
                .bold()
                .padding(Edge.Set.bottom, 30)

            Spacer()

            ZStack(alignment: .leading) {
                Text("Email")
                    .foregroundColor(email.isEmpty ? .white : .black)
                    .fontWeight(email.isEmpty ? .regular : .bold)
                    .padding(.leading, 10)
                    .offset(y: email.isEmpty ? 0 : -30)

                TextField("", text:$email)
                    .background(Color.clear)
                    .foregroundColor(.white)
                    .textContentType(.emailAddress)
                    .keyboardType(.emailAddress)
                    .padding(.leading, 10)
                    .padding(.trailing, 10)
            }
            Rectangle()
                .frame(height: 3.0, alignment: .bottom)
                .foregroundColor(Color.white)
                .padding(.bottom, 40)
                .padding(.leading, 10)
                .padding(.trailing, 10)

            ZStack(alignment: .leading) {
                Text("Password")
                    .foregroundColor(password.isEmpty ? .white : .black)
                    .fontWeight(password.isEmpty ? .regular : .bold)
                    .padding(.leading, 10)
                    .offset(y: password.isEmpty ? 0 : -30)
                SecureField("", text:$password)
                    .background(Color.clear)
                    .foregroundColor(.white)
                    .textContentType(.password)
                    .padding(.leading, 10)
                    .padding(.trailing, 10)
            }
            Rectangle()
                .frame(height: 3.0, alignment: .bottom)
                .foregroundColor(Color.white)
                .padding(.bottom, 50)
                .padding(.leading, 10)
                .padding(.trailing, 10)

            VStack {
                Button(action: signIn) {
                    HStack(alignment: .center) {
                        Spacer()
                        if loading {
                            ActivityIndicator()
                        } else {
                            Text("Sign In")
                                .foregroundColor(.blue)
                                .bold()
                        }
                        Spacer()
                    }
                }.padding().background(Color.white).cornerRadius(30.0)
            }
            .padding(Edge.Set.bottom, 8)
        }
        .padding()
        .background(Color.blue.edgesIgnoringSafeArea(.all))
        .statusBar(hidden: true)
        .onAppear(perform: getUser)
        .offset(y: kGuardian.slide).animation(.easeInOut(duration: 0.5))
    }
}

struct ActivityIndicator: UIViewRepresentable {

    func makeUIView(context: Context) -> UIActivityIndicatorView {
        let v = UIActivityIndicatorView()

        return v
    }

    func updateUIView(_ activityIndicator: UIActivityIndicatorView, context: Context) {
        activityIndicator.startAnimating()
    }
}

struct Login_Previews: PreviewProvider {
    static var previews: some View {
        Login()
            .environmentObject(SessionStore())
    }
}

On every iPad simulator I run the app on (and a physical 6th Generation iPad) I cannot replicate the above screenshot. Mine always look like this:

Non clipped screenshot

Can anyone figure out what is going on here. My app settings are set to Portrait only on iPhone and iPad devices

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
    <key>CFBundleShortVersionString</key>
    <string>$(MARKETING_VERSION)</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UIApplicationSceneManifest</key>
    <dict>
        <key>UIApplicationSupportsMultipleScenes</key>
        <false/>
        <key>UISceneConfigurations</key>
        <dict>
            <key>UIWindowSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneConfigurationName</key>
                    <string>Default Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
                </dict>
            </array>
        </dict>
    </dict>
    <key>UIBackgroundModes</key>
    <array>
        <string>remote-notification</string>
    </array>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UIRequiresFullScreen</key>
    <true/>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
    </array>
</dict>
</plist>


from SwiftUI - Canvas exceeding screen width - App Rejected

No comments:

Post a Comment