11

I'm using SwiftUI to develop a people list page, the iPhone X screen is big enough but the titles are out of the screen in iPhone 8:

iPhone X:

enter image description here

However in iPhone 8 or smaller screen the "Find People" is too close to left and "Follow All" is even out of screen:

enter image description here

I know in UIKit autolayout will solve this very easy but I wonder what's the best way or proper way for SwiftUI to solve this, some answer saying using like Spacer or HStack, but none of them actually work.

var body: some View {
    NavigationView {
        List {
            ForEach(people) {person in
                PersonView(person: person)
            }
        }.navigationBarItems(leading:
            VStack(spacing: 10) {
                HStack(spacing: 100) {
                    Text("Find People").font(.system(size: 30)).bold()
                    Text("Follow All").foregroundColor(Color(ColorUtils.hexStringToUIColor(hex: Constants.THEME.THEME_COLOR)))
                }
                HStack(spacing: 20) {
                     Text("Import from: ")
                     ForEach(socialIcons, id: \.self) {icon in
                         Image(icon).resizable().frame(width: 25, height: 25)
                     }
                }
            }
        )
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Invincible_Pain
  • 491
  • 2
  • 6
  • 17
  • I think the problem is that you are effectively specifying an item that you need to be trailing (the "Follow All") text as part of the `leading` views, since you want the social items on the next line. If I removed various stacks and the social icons and just had the two text items, leading and trailing, it is OK – Paulw11 Nov 28 '19 at 00:58
  • You may need to re-design your layout. "Find People" should be `.navigationBarTitle`, with the social import and the follow all as part of the `NavigationView` content. – Paulw11 Nov 28 '19 at 01:06

4 Answers4

9

You are putting static spacing so that issue is occurring. you can fix it using Spacer() Modifier and give some Frame().

var body: some View {
    NavigationView {
        List {
            ForEach(peoples, id: \.self) {person in
                PersonView(person: person)
            }
        }.navigationBarItems(leading:
            VStack(spacing: 5) { // Change Spacing as you want
                HStack {
                    Text("Find People").font(.system(size: 30)).bold()
                    Spacer()
                    Text("Follow All").foregroundColor(Color(ColorUtils.hexStringToUIColor(hex: Constants.THEME.THEME_COLOR)))
                }
                HStack() {
                    Text("Import from:")
                    Spacer()
                    ForEach(socialIcons, id: \.self) {icon in
                        Image(icon).resizable().frame(width: 25, height: 25)
                            .padding(.horizontal)
                    }
                }
            }.frame(width: UIScreen.main.bounds.width-20, alignment: .center)
        )
    }
}
Rohit Makwana
  • 4,337
  • 1
  • 21
  • 29
3

i've created a useful View extension for proportional size which will calculate the size using the percentage of the screen size as the parameter and return the size as per the screen size

extension View {
      func propotionalFrame(width: CGFloat, height: CGFloat, isSquared: Bool = false, alignment: Alignment = .center) -> some View {
        let finalWidth = UIScreen.main.bounds.width * width
        let finalHeight = isSquared ? finalWidth : UIScreen.main.bounds.height * height
        return frame(width: finalWidth, height: finalHeight)
      }
    }

usage:

Image(systemName: "person.circle.fill")
      .resizable()
      .propotionalFrame(width: 0.3, height: 0.2)
2

Instead of hardcoding spacing, use dynamic instruments, like Spacer() and .padding. See below modified your code as example. Hope it helps.

HStack {
    Text("Find People").font(.system(size: 30)).bold()
    Spacer()
    Text("Follow All").foregroundColor(Color(ColorUtils.hexStringToUIColor(hex: Constants.THEME.THEME_COLOR)))
}
HStack {
     Text("Import from: ")
     Spacer()
     ForEach(socialIcons, id: \.self) {icon in
         Image(icon).resizable().frame(width: 25, height: 25)
            .padding(.horizontal)
     }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
2
import SwiftUI

extension CGFloat {
    @usableFromInline
    enum Device {
        case iPhone11Pro

    var size: (width: CGFloat, height: CGFloat) {
        switch self {
        case .iPhone11Pro:
            return (375, 812)
        }
    }
}

/// calculates the height as per figma, note: set the default development device as per figma
@usableFromInline
static func fig(height: CGFloat, device: Device = .iPhone11Pro) -> CGFloat {
    UIScreen.height * (height / device.size.height)
}

/// calculates the width as per figma, note: set the default development device as per figma
@usableFromInline
static func fig(width: CGFloat, device: Device = .iPhone11Pro) -> CGFloat {
    UIScreen.width * (width / device.size.width)
}

}

  • but its for particular device and everytime i need to define the device , i want to be all devices without telling which one im using – Saurabh Pathak Sep 01 '22 at 14:27
  • @SaurabhPathak No it'll work for all screen sizes, here we are saying that we want to use certain % of height and width of the device, I've chosen iPhone 11 Pro because my designer used it in figma, so here, so if your designer used something else then you can add that device and its size. then build the app in different devices then see your view's will adjust according to screen size. – Mohammed Owais Khan Sep 02 '22 at 08:28
  • And it'll only work for portrait mode, if you also want same thing in landscape mode then you must use GeometryReader. – Mohammed Owais Khan Sep 02 '22 at 08:29