iOS 14 Medium Widget Size Background Image Refuses to Fill - swiftui

For some reason I'm unable to get an image background to aspectFill correctly in XCode Version 12.0, but only on the .systemMedium widget size. It seems to work perfectly on the small and large sizes.
I've got a pretty simple View:
import SwiftUI
#available(iOS 13.0.0, *)
struct Banana: View {
var body: some View {
VStack(alignment: .leading){
Spacer()
Text("Aardvark Exactlywhat")
.font(.largeTitle)
.bold()
.padding(.bottom, 20)
.padding(.leading, 20)
.padding(.trailing, 20)
.minimumScaleFactor(0.5)
.foregroundColor(.white)
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(4),
y: CGFloat(4))
}
.edgesIgnoringSafeArea(.all)
.background(
Image("bananas")
.resizable()
.scaledToFill()
).edgesIgnoringSafeArea(.all)
}
}
#available(iOS 13.0.0, *)
struct Banana_Previews: PreviewProvider {
static var previews: some View {
Banana()
}
}
And a pretty simple widget:
struct fruitWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Banana()
}
}
#main
struct fruitWidget: Widget {
let kind: String = "fruitWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
fruitWidgetEntryView(entry: entry)
}
.configurationDisplayName("fruit Widget")
.description("Enhance your day with delicious fruit.")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
struct fruitWidget_Previews: PreviewProvider {
static var previews: some View {
Group{
fruitWidgetEntryView(entry: SimpleEntry(date: Date()))
.previewContext(
WidgetPreviewContext(family: .systemSmall))
fruitWidgetEntryView(entry: SimpleEntry(date: Date()))
.previewContext(
WidgetPreviewContext(family: .systemMedium))
fruitWidgetEntryView(entry: SimpleEntry(date: Date()))
.previewContext(
WidgetPreviewContext(family: .systemLarge))
}
}
}
I've tried changing the aspect ratio, using GeometryReader and frame(), and a dozen other variations. Regardless of what I try, I get white space on the left and right in the medium widget. It only works for the large and small size. See image:

Here is fixed variant - as image in the background you have to expand VStack to full screen.
Note: edgesIgnoringSafeArea allows to go beyond safe area when content is wider, but not make content wide.
var body: some View {
VStack(alignment: .leading){
Spacer()
Text("Aardvark Exactlywhat")
.font(.largeTitle)
.bold()
.padding(.bottom, 20)
.padding(.leading, 20)
.padding(.trailing, 20)
.minimumScaleFactor(0.5)
.foregroundColor(.white)
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(4),
y: CGFloat(4))
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // << this one !!
.edgesIgnoringSafeArea(.all)
.background(
Image("plant")
.resizable()
.scaledToFill()
)
}

Related

Utilize HStack to confirm to logo and skip text

Does anyone know how to make the following view in SwiftUI?
HStack:
[ blank logo(centered) Skip(text)]
So I have the following HStack:
Zstack(alignment: .topLeading) {
VStack{
HStack {
Image("onboarding-logo")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
.padding(.top, 35)
}
}
}
Does anyone know how I can have a "Skip" text in the top right corner of the screen, but also keep my logo centered and not have anything on the left side? I've tried Spacers and all, but I'm having no luck.
I would like to click "Skip" and then lead to another view.
There are many ways to achieve this. Here I have used LazyVGrid since other answers based on Stacks
struct ContentView: View {
var body: some View {
VStack {
LazyVGrid(columns: [GridItem(), GridItem(), GridItem()], content: {
Spacer()
Image(systemName: "star.fill")
.frame(width: 150, height: 150, alignment: .center)
.border(.gray)
Button(action: {
}, label: {
Text("Skip")
})
})
.border(.gray)
Spacer()
}
}
}
Is this the screen configuration you want?
The Zstack is used to center the Hstack into which the image is placed, and the new HStack uses a spacer to move the Text to the right.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
VStack {
HStack(alignment: .center) {
Image("farnsworth")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
}
Spacer()
}
VStack {
HStack {
Spacer()
Button {
// do Something...
} label: {
Text("Skip>>")
.padding(.top, 10)
}
}
Spacer()
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

distance between ui components in swiftUi

I want to have a constant distance between the image and the text , I also want to have a constant distance between the image and trailing anchor of the green box.using padding and increase the length of the text the problem appears as you seen win the picture. how can I solve this problem? how can use auto layout in swiftUi the same way as UIKit?
import SwiftUI
struct SwiftUIView: View {
var orgName:String
var imgName:String
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 8)
.fill(Color.green)
.frame( height: 50)
.padding([.trailing, .leading], 20)
.padding([.top, .bottom], 10)
.overlay(
HStack(spacing: 10){
Text("\(orgName)")
.frame(width: .infinity, height: 50)
//Image( "\(imgName)")
Image( systemName: "phone.fill")}
//.padding(.trailing
// ,UIScreen.main.bounds.size.width-480)
)
}
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView(orgName:"aaaaa", imgName:"aimg")
}
}
In SwiftUI the order of modifiers matters! You need to set the overlay before the paddings.
You can use the below code for Overlay HStackView padding -
struct SwiftUIView: View {
var orgName:String
var imgName:String
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 8)
.fill(Color.green)
.frame( height: 50)
.overlay(
HStack {
Text("\(orgName)")
.frame(width: .infinity, height: 50)
Image(systemName: "phone.fill")
}.padding(),
alignment: .trailing
)
.padding([.top, .bottom], 10)
.padding([.trailing, .leading], 20)
}
}
}
Please check the result for your updated code here -
The important thing is swiftUI modifiers should use in correct order
So You can simply use paddings instead of frames. Then this will responsive for all devices as well.
import SwiftUI
struct SwiftUIView: View {
//MARK: - PRROPERTIES
var orgName:String
//MARK: - BODY
var body: some View {
HStack(spacing: 10){
Spacer()
Text("\(orgName)")
Image( systemName: "phone.fill")
}
.padding(.vertical , 15)
.padding(.horizontal, 10)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.green)
)
.padding(.horizontal, 15)
}
}
//MARK: - PREVIEW
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView(orgName:"aaaaaa")
}
}
preview

Scrollable content not working as expected in SwiftUI

I'm trying to create a scroll view with my custom view, but when I add scroll to view it's not working as expected, without scroll view working fine.
struct ContentView: View {
var body: some View {
ScrollView(.vertical) {
VStack {
ForEach (0..<2) { _ in
ListItem()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
// But the below code is working fine.
struct ContentView: View {
var body: some View {
VStack {
ForEach (0..<2) { _ in
ListItem()
}
}
}
}
// List Item
struct ListItem: View {
var body: some View {
VStack {
HStack {
Image("steve")
.resizable()
.clipShape(Circle())
.aspectRatio(contentMode: .fit)
.frame(maxWidth:44, maxHeight: 44)
VStack {
Text("Steve Jobs")
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
Text("1 hour ago")
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
}
Spacer()
}
ZStack(alignment:.top) {
GeometryReader { geometry in
VStack {
ZStack {
Image("poster_1")
.resizable()
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
.shadow(color: Color.black.opacity(0.12),
radius: 4, x: 1, y: 1)
.frame(width: geometry.size.width - 64,
height: geometry.size.height * 0.35)
.padding([.horizontal], 32)
.clipped()
ZStack {
Rectangle()
.fill(Color.black.opacity(0.75))
.frame(maxWidth:84 , maxHeight: 84)
.cornerRadius(12)
Image(systemName: "play.fill")
.font(.system(size: 44, weight: .bold))
.foregroundColor(.white)
}
}
VStack {
Text("Game of Thrones")
.accentColor(Color.gray.opacity(0.25))
.font(Font.subheadline.weight(.bold))
.padding([.horizontal], 32)
.padding([.bottom], 2)
.frame(maxWidth: .infinity,
alignment: .leading)
VStack {
Text("Game of Thrones is an American fantasy drama television series created by David Benioff and D. B. Weiss for HBO. ")
.accentColor(Color.gray.opacity(0.25))
.font(.footnote)
.frame(maxWidth: .infinity,
alignment: .leading)
.padding([.horizontal], 32)
Text("Show more...")
.accentColor(Color.gray.opacity(0.01))
.font(Font.footnote.weight(.bold))
.frame(maxWidth: .infinity,
alignment: .trailing)
.padding([.trailing], 32).onTapGesture {
print("okay")
}
}
}
}
}
}
}
}
}
ListItem contains multiple views which creates publisher info and movie information as shown below image.
Scrollview is scrolling but images are not shown in view as first image.
It is the geometry reader that you have in ListItem. Because neither a GeometryReader nor a Scrollview have their own size. Since neither no what size to render, they collapse. This is what you are seeing in your view. See this answer. The solution is to put the GeometryReader into ContentView outside the Scrollview and send the GeometryProxy that you called geometry into ListItem something like this:
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
ScrollView(.vertical) {
VStack {
ForEach (0..<2) { _ in
ListItem(geometry: geometry)
}
}
} // Scrollview
} // GeometryReader
}
}
struct ListItem: View {
let geometry: GeometryProxy
var body: some View {
...
}
This seems to fix it in Preview, though you may have to change your multipliers in the .frame() that uses geometry to size it how you want.

How to change size of field in TextField?

I need to change the size (actually just the height) of the TextField. Using .padding() increases just the area around the TextField, but not the field itself. I've tried some possible solutions:
Change the font size: This approach works, but I don't want to have a TextField with a too large text in itself.
Using custom modifier doesn't work. I get the message Inheritance from non-protocol type 'TextFieldStyle'. Seems to not working in Swift 5 anymore?
My current solution is:
#State private var searchText: String = ""
var body: some View {
HStack{
Image(systemName: "magnifyingglass")
.font(.system(size: 20, weight: .bold))
ZStack(alignment: .leading){
if searchText.isEmpty { Text("search") }
TextField("", text: $searchText,
onEditingChanged: { focused in
if focused {
// do something...
}
},
onCommit: {
// do something...
})
.keyboardType(.alphabet)
.disableAutocorrection(true)
.frame(height: 50)
}
.textFieldStyle(PlainTextFieldStyle())
}
.frame(height: 30)
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.accentColor(.white)
.padding()
.background(
Color("Color-2")
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.3), radius: 5, x: 5, y: 5)
)
.contentShape(Rectangle())
}}
Only the red area is "clickable"
import SwiftUI
struct ContentView: View {
#State var stringOfText: String = ""
var body: some View {
TextField("", text: $stringOfText)
.font(Font.system(size: 50))
.background(Color.yellow)
.foregroundColor(Color.clear)
.cornerRadius(10)
.overlay(Text(stringOfText), alignment: .leading)
.padding()
.shadow(radius: 10)
}
}

How to scale the contentview to multiple screen sizes? SwiftUI

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)
.......
}
}
}