I want to know if I could access to apple default value of padding in SwiftUI? currently I am using a custom found value that is 16 for iPhone, but it could be deferent in deferent device or in new update of Swift or SwiftUI, therefore I want make it future update and device proof.
import SwiftUI
struct ContentView: View {
#State private var paddingLength: CGFloat = 16.0 // Do we have something like: Padding.defaultValue to use it?
var body: some View {
Spacer()
Text("Hello, world!")
.padding()
.background(Color.red)
Text("Hello, world!")
.padding(paddingLength)
.background(Color.yellow)
Spacer()
Button("update padding to 0") {
paddingLength = 0
}
.padding(.bottom)
Button("update padding to default") {
paddingLength = 16 // Do we have something like: Padding.defaultValue to use it?
}
.padding(.bottom)
Spacer()
}
}
I am not aware of any way to get the default value but you could solve it by letting the length property be an optional and set it to nil for the default value. Only downside of this is you can't call padding with the length attribute only so either call it with edges set to .all or use another property for this.
Here is a solution with a property for edges as well
#State var paddingLength: CGFloat? = nil
#State var edge: Edge.Set = .all
var body: some View {
Spacer()
Text("Hello, world!")
.padding()
.background(Color.red)
Text("Hello, world!")
.padding(edge, paddingLength)
.background(Color.yellow)
Spacer()
Button("update padding to 0") {
paddingLength = 0
}
.padding(.bottom)
Button("update padding to default") {
paddingLength = nil
}
.padding(.bottom)
Spacer()
}
Related
So i want my keyboard to overlay the view so that the view stays and not going upwards. i did several variations such as adding it in my loginstuff, or adding in it navigationView. it doesn't work at all
Here's my code
struct LoginView: View {
#StateObject var userData = UserData()
var body: some View {
NavigationView {
ZStack(alignment:.top) {
Color.pink.ignoresSafeArea(edges: .top)
VStack {
Image(systemName: "graduationcap.fill")
.resizable()
.scaledToFit()
.frame(width: /*#START_MENU_TOKEN#*/100/*#END_MENU_TOKEN#*/, height: /*#START_MENU_TOKEN#*/100/*#END_MENU_TOKEN#*/, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.foregroundColor(.white)
.padding(.top,30)
Text("Study +")
.font(.title)
.fontWeight(.medium)
.foregroundColor(.white)
Spacer()
//Mark : The login Thinggy
LoginStuffs()
}
}
.edgesIgnoringSafeArea(.bottom)
.navigationTitle("Login")
.navigationBarHidden(true)
}
}
}
Login Stuff
struct LoginStuffs: View {
#State var username:String = ""
#State var password:String = ""
#State var isShow:Bool = false
var body: some View {
Vstack{
Textfield()
Securefield()
Securefield()
}
.padding()
.frame(width:UIScreen.width,height:UIScreen.height/1.5)
.background(Color.white)
.cornerRadius(15, corners: [.topLeft, .topRight])
//.ignoresSafeArea(edges: /*#START_MENU_TOKEN#*/.bottom/*#END_MENU_TOKEN#*/)
}
}
Seems like there's a problem within my codes in which I did not know (probably due to not learn it properly). please do help, thank you for your attention
use on your NavigationView
.edgesIgnoringSafeArea(.bottom))
I am trying to create a full bleed SwiftUI 'header' view in my scene. This header will sit within a List or a scrollable VStack.
In order to do this, I'd like to have my text in the header positioned below the safe area, but the full view should extend from the top of the screen (and thus, overlap the safe area). Here is visual representation:
V:[(safe-area-spacing)-(padding)-(text)]
here is my attempt:
struct HeaderView: View {
#State var spacing: CGFloat = 100
var body: some View {
HStack {
VStack(alignment: .leading) {
Rectangle()
.frame(height: spacing)
.opacity(0.5)
Text("this!").font(.largeTitle)
Text("this!").font(.headline)
Text("that!").font(.subheadline)
}
Spacer()
}
.frame(maxWidth: .infinity)
.background(Color.red)
.background(
GeometryReader { proxy in
Color.clear
.preference(
key: SafeAreaSpacingKey.self,
value: proxy.safeAreaInsets.top
)
}
)
.onPreferenceChange(SafeAreaSpacingKey.self) { value in
self.spacing = value
}
}
}
This however, does not seem to correctly size 'Rectangle'. How can I size a view according to the safe area?
Is this what you're looking for? I try to avoid using GeometryReader unless you really need it... I created a MainView, which has a background and a foreground layer. The background layer will ignore the safe areas (full bleed) but the foreground will stay within the safe area by default.
struct HeaderView: View {
var body: some View {
HStack {
VStack(alignment: .leading) {
Text("this!").font(.largeTitle)
Text("this!").font(.headline)
Text("that!").font(.subheadline)
}
Spacer(minLength: 0)
}
}
}
struct MainView: View {
var body: some View {
ZStack {
// Background
ZStack {
}
.frame(maxWidth:. infinity, maxHeight: .infinity)
.background(Color.red)
.edgesIgnoringSafeArea(.all)
// Foreground
VStack {
HeaderView()
Spacer()
}
}
}
}
add an state to store desired height
#State desiredHeight : CGFloat = 0
then on views body :
.onAppear(perform: {
if let window = UIApplication.shared.windows.first{
let phoneSafeAreaTopnInset = window.safeAreaInsets.top
desiredHeight = phoneSafeAreaTopnInset + x
}
})
set the desiredHeight for your view .
.frame(height : desiredHeight)
Newbie here! I am building a quiz app using Swiftui, I built the view controller by previewing it in an iPhone 11 simulator.
And I thought the controlview would fit other iPhone sizes, like iPhone 8. Because Swiftui has a built-in auto layout.
But when I run the iPhone 8 simulator some of the content in the control view is not visible because they are below the screen.
Is there a way to fix it?
I tried to play with multiple Spacer() and different paddings but I can't seem to make it look good on both screen at the same time.
This is my code:
import SwiftUI
struct questionOne: View {
#State var totalClicked: Int = 0
#State var showDetails = false
#State var isSelected = false
var body: some View {
VStack {
TRpic().frame(width: 350.0, height: 233.0).cornerRadius(10).padding(.top, 80)
Spacer()
Text(verbatim: "What's the capital of Turkey?")
.font(.title)
.padding(.bottom, 60)
.frame(height: 100.0)
Button(action: {}) {
Text("Istanbul")
}.buttonStyle(MyButtonStyle())
Spacer()
Button(action: {self.isSelected.toggle()}) {
Text("Ankara")
}.buttonStyle(SelectedButtonStyle(isSelected: $isSelected))
Spacer()
Button(action: {}) {
Text("Athens")
} .buttonStyle(MyButtonStyle())
Spacer()
NavigationLink(destination: questionTwo()) {
VStack {
Text("Next Question")
Adview().frame(width: 150, height: 60)
}
}
}.edgesIgnoringSafeArea(.top)
}
}
struct MyButtonStyle: ButtonStyle {
func makeBody(configuration:
Self.Configuration) -> some View {
configuration.label
.padding(20)
.foregroundColor(.white)
.background(configuration.isPressed ? Color.red : Color.gray)
.cornerRadius(10.0)
}
}
struct SelectedButtonStyle: ButtonStyle {
#Binding var isSelected: Bool
public func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding(20)
.foregroundColor(.white)
.background(isSelected ? Color.green : Color.gray)
.cornerRadius(10.0)
}
}
enter image description here
Screenshot
Being in the given context I guess you do not want a scroll view, so regarding spacing I suggest using a VStack with spacing parameter VStack(alignment: .center, spacing: n){ ... } and remove the Spacers, if between 2 views you need another distance than n, just use padding to add some extra space.
This should adjust everything to fit the height of any screen, including the image, so do not need a fixed frame for it.
But, you might have a very wide image that could go beyond safe area, so, you could set a maximum width for the image as being the screen width
struct questionOne: View {
var body: some View {
GeometryReader { geometryProxy in
VStack(alignment: .center, spacing: 20) {
TRpic().frame(maxWidth: geometryProxy.size.width, alignment: .center)
.padding([.leading, .trailing], 10)
.......
}
}
}
I was trying to make a custom list. And its acting weired if we add Encapsulated VStack in scrollView and try to add new row from that VStack. But we have to encapsulate because in Xcode will give "complex view complier error". I am providing full code for better understanding. Please try to run it. New element is not added as expected and its pushing everything upward.
struct RowView: View {
var body: some View {
VStack{
HStack{
Spacer()
.foregroundColor(Color.black)
Spacer()
}
}
.background(Color.white)
.cornerRadius(13)
.padding()
}}
struct cView:View {
#State var array: [String] = []
#State var height: CGFloat = 60
var body: some View {
VStack{
Button(action: {
self.array.append("Test")
}, label: {
Text("Add")
})
VStack{
ForEach(array, id: \.self){_ in
RowView()
}
}
.background(Color.red)
.cornerRadius(13)
.padding()
}
}}
struct ContentView : View {
#State var array: [String] = []
var body: some View {
ScrollView{
VStack{
Text("d")
.frame(height: 90)
VStack{
cView()
}
}
}
.navigationBarTitle("Test", displayMode: .automatic)
}}
When I reformatted and removed unused stuff I got:
struct RowView: View {
let text: String
var body: some View {
VStack{
HStack{
Spacer()
Text(text).foregroundColor(Color.black)
Spacer()
}
}
.background(Color.white)
.cornerRadius(13)
.padding()
}
}
struct cView:View {
#State var array: [String] = []
#State var height: CGFloat = 60
var body: some View {
VStack{
Button(
action: { self.array.append("Test") },
label: { Text("Add") }
)
ForEach(array, id: \.self){text in
RowView(text: text)
}
.background(Color.red)
.cornerRadius(13)
.padding()
}
}
}
struct ContentView : View {
var body: some View {
List {
VStack{
Text("d")
cView()
}
}
}
}
ScrollView is a real PITA and it hates Text which is why I replaced it with a List. RowView was missing a Text IMHO so I put one in. The array in ContentView was never used so I removed it, similarly a navigatinBarTitle needs a NavigationView.
This isn't really an answer as it uses List instead of ScrollView but it does point to where your problems lie. It is also very strange as every thing is in a single List row but I tried to change as little as possible.
You might like to try running SwiftLint on your code. I often swear at it, especially when it complains about the cyclomatic complexity of my enum switches but it does improve my code.
Most likely a bug, but I did not need to encapsulate. And if I don't, the code works as expected:
struct RowView: View {
var body: some View {
VStack{
HStack{
Spacer()
.foregroundColor(Color.black)
Spacer()
}
}
.background(Color.white)
.cornerRadius(13)
.padding()
}
}
struct ContentView : View {
#State var array: [String] = []
#State var height: CGFloat = 60
var body: some View {
ScrollView{
VStack{
Text("d")
.frame(height: 90)
VStack{
Button(action: {
self.array.append("Test")
}, label: {
Text("Add")
})
VStack{
ForEach(array, id: \.self){_ in
RowView()
}
}
.background(Color.red)
.cornerRadius(13)
.padding()
}
}
}
.navigationBarTitle("Test", displayMode: .automatic)
}
}
I'm trying to achieve a following layout using Swift UI…
struct ContentView : View {
var body: some View {
List(1...5) { index in
HStack {
HStack {
Text("Item number \(index)")
Spacer()
}.padding([.leading, .top, .bottom])
.background(Color.blue)
Text("i")
.font(.title)
.italic()
.padding()
.aspectRatio(1, contentMode: .fill)
.background(Color.pink)
}.background(Color.yellow)
}
}
}
I'd like the Text("i") to be square, but setting the .aspectRatio(1, contentMode: .fill) doesn't seem to do anything…
I could set the frame width and height of the text so it's square, but it seems that setting the aspect ratio should achieve what I want in a more dynamic way.
What am I missing?
I think this is what you're looking for:
List(1..<6) { index in
HStack {
HStack {
Text("Item number \(index)")
Spacer()
}
.padding([.leading, .top, .bottom])
.background(Color.blue)
Text("i")
.font(.title)
.italic()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.aspectRatio(1, contentMode: .fill)
.background(Color.pink)
.fixedSize(horizontal: true, vertical: false)
.padding(.leading, 6)
}
.padding(6)
.background(Color.yellow)
}
The answer being said, i don't recommend giving SwiftUI too much freedom to decide the sizings. one of the biggest SwiftUI problems right now is the way it decides how to fit the views into each other. if something goes not-so-good on SwiftUI's side, it can result in too many calls to the UIKit's sizeToFit method which can slowdown the app, or even crash it.
but, if you tried this solution in a few different situations and it worked, you can assume that in your case, giving SwiftUI the choice of deciding the sizings is not problematic.
The issue is due to used different fonts for left/right sides, so paddings generate different resulting area.
Here is possible solution. The idea is to give right side rect based on default view size of left side text (this gives ability to track dynamic fonts sizes as well, automatically).
Tested with Xcode 12 / iOS 14
struct ContentView: View {
#State private var height = CGFloat.zero
var body: some View {
List(1...5, id: \.self) { index in
HStack(spacing: 8) {
HStack {
Text("Item number \(index)")
Spacer()
}
.padding([.leading, .top, .bottom])
.background(GeometryReader {
Color.blue.preference(key: ViewHeightKey.self, value: $0.frame(in: .local).size.height)
})
Text("i")
.italic()
.font(.title)
.frame(width: height, height: height)
.background(Color.pink)
}
.padding(8)
.background(Color.yellow)
.onPreferenceChange(ViewHeightKey.self) {
self.height = $0
}
}
}
}
struct ViewHeightKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
I managed to recreate the view in your first screenshot in SwiftUI. I wasn't sure on how much padding you wanted so I defined a private immutable variable for this value
The blue view is the one that will have the text content and could change in size so by using a GeometryReader you can get the size of the blue view and then use the height value from the size to set the width and height of the pink view. This means that whatever the height of the blue view is, the pink view will follow keeping an equal aspect ratio
The SizeGetter view below is used to get any views size using a GeometryReader and then binds that value back to a #State variable in the ContentView. Because the #State and #Binding property wrappers are being used, whenever the blueViewSize is updated SwiftUI will automatically refresh the view.
The SizeGetter view can be used for any view and is implemented using the .background() modifier as shown below
struct SizeGetter: View {
#Binding var size: CGSize;
var body: some View {
// Get the size of the view using a GeometryReader
GeometryReader { geometry in
Group { () -> AnyView in
// Get the size from the geometry
let size = geometry.frame(in: .global).size;
// If the size has changed, update the size on the main thread
// Checking if the size has changed stops an infinite layout loop
if (size != self.size) {
DispatchQueue.main.async {
self.size = size;
}
}
// Return an empty view
return AnyView(EmptyView());
}
}
}
}
struct ContentView: View {
private let padding: Length = 10;
#State private var blueViewSize: CGSize = .zero;
var body: some View {
List(1...5) { index in
// The yellow view
HStack(spacing: self.padding) {
// The blue view
HStack(spacing: 0) {
VStack(spacing: 0) {
Text("Item number \(index)")
.padding(self.padding);
}
Spacer();
}
.background(SizeGetter(size: self.$blueViewSize))
.background(Color.blue);
// The pink view
VStack(spacing: 0) {
Text("i")
.font(.title)
.italic();
}
.frame(
width: self.blueViewSize.height,
height: self.blueViewSize.height
)
.background(Color.pink);
}
.padding(self.padding)
.background(Color.yellow);
}
}
}
In my opinion it is better to set the background colour of a VStack or HStack instead of the Text view directly because you can then add more text and other views to the stack and not have to set the background colour for each one
I was searching very similar topic "Square Text in SwiftUI", came across your question and I think I've found quite simple approach to achieve your desired layout, using GeometryProxy to set width and heigh of the square view from offered geometry.size.
Checkout the code below, an example of TableCellView which can be used within List View context:
import SwiftUI
struct TableCellView: View {
var index: Int
var body: some View {
HStack {
HStack {
Text("Item number \(index)")
.padding([.top, .leading, .bottom])
Spacer()
}
.background(Color(.systemBlue))
.layoutPriority(1)
GeometryReader { geometry in
self.squareView(geometry: geometry)
}
.padding(.trailing)
}
.background(Color(.systemYellow))
.padding(.trailing)
}
func squareView(geometry: GeometryProxy) -> some View {
Text("i")
.frame(width: geometry.size.height, height: geometry.size.height)
.background(Color(.systemPink))
}
}