Why is .imageScale(.large) not big like in iOS stock apps? - ios

I am using the NavigationView with some navigationBarItems.
I have specified that the dimension (or scale) of both buttons has to be .large (like in the SwiftUI tutorials by Apple) but as you can see below they are not as big as the navigationBarItems in iOS stock apps like in Shortcuts or Wallet.
Any help is appreciated!
Thanks!
Images:
Shortcuts App by Apple
My View
struct GroupsTab: View {
var addButton: some View {
Button(action: {}) {
Image(systemName: "plus.circle.fill")
.imageScale(.large)
// TO ACHIEVE THE SAME RESULT AS IN IOS I NEED TO SCALE THE IMAGE BY ABOUT 1.2 BUT IT BECOMES BLURRY
//.scaleEffect(1.2)
}
}
var editButton: some View {
Button(action: {}) {
Text("Edit")
.imageScale(.large)
}
}
var body: some View {
NavigationView {
Text("hello world")
.navigationBarItems(leading: editButton, trailing: addButton)
.navigationBarTitle("Groups")
}
}
}

Instead of .imageScale(.large) use .font(.largeTitle)

Related

Image positionning issue in SwiftUI

I am having an alignment problem while using SwiftUI.
Maybe I should say a layout issue. Anyway here is the situation:
This is the relevant part of the app interface:
One can see that while the text ("+++++") is centered, the flag is not. It is slightly shifted to the left. This left-shifting is precisely my problem. I would like the image to be centered as the text is.
Here follows the code, I would like to know what I am doing wrong for the image not to be centered:
import SwiftUI
struct TheNiceView: View {
........
var body: some View {
VStack {
HStack {
Spacer()
TheButtonView()
Spacer()
}
HStack {
Spacer()
Button(action: {})
{
Text("+++++")
.font(.largeTitle)
.foregroundColor(.gray)
.fontWeight(.heavy)
}
Spacer()
}
}
}
}
struct TheButtonView: View {
........
let imgSide:CGFloat = 72.0
var body: some View {
HStack {
Button(action: {})
{
Image(uiImage: ThaiFlagImg)
.resizable()
.frame(width: imgSide, height: imgSide)
}
}
}
}
Just in case this may be useful, this is the image used for the flag:
1
Thailand flag has five horizontal stripes in the colours red, white, blue, white and red. The image you use has 7 srtips.
2
Using the Spacers and HStack are unnecessary.
I used the following image without the Spacers and HStack, both the +++ button and the flag are aligned in the center.
https://upload.wikimedia.org/wikipedia/commons/a/a9/Flag_of_Thailand.svg
struct TheNiceView: View {
var body: some View {
VStack {
TheButtonView()
Button(action: {}) {
Text("+++++")
.font(.largeTitle)
.foregroundColor(.gray)
.fontWeight(.heavy)
}
}
}
}
struct TheButtonView: View {
let imgSide:CGFloat = 72.0
var body: some View {
Button(action: {}){
Image( "ThaiFlagImg")
.resizable()
.frame(width: imgSide, height: imgSide)
}
}
}

Why SwiftUI context menu show all row view in preview?

I have a complex view in List row:
var body: some View {
VStack {
VStack {
FullWidthImageView(ad)
HStack {
Text("\(self.price) \(self.ad.currency!)")
.font(.headline)
Spacer()
SwiftUI.Image(systemName: "heart")
}
.padding([.top, .leading, .trailing], 10.0)
Where FullWidthImageView is view with defined contexMenu modifier.
But when I long-press on an image I see not the only image in preview, but all row view.
There is no other contextMenu on any element.
How to make a preview in context with image only?
UPD. Here is a simple code illustrating the problem
We don't have any idea why in your case it doesn't work, until we see your FullWidthImageView and how you construct the context menu. Asperi's answer is working example, and it is correctly done! But did it really explain your trouble?
The trouble is that while applying .contextMenu modifier to only some part of your View (as in your example) we have to be careful.
Let see some example.
import SwiftUI
struct FullWidthImageView: View {
#ObservedObject var model = modelStore
var body: some View {
VStack {
Image(systemName: model.toggle ? "pencil.and.outline" : "trash")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
}.contextMenu(ContextMenu {
Button(action: {
self.model.toggle.toggle()
}) {
HStack {
Text("toggle image to?")
Image(systemName: model.toggle ? "trash" : "pencil.and.outline")
}
}
Button("No") {}
})
}
}
class Model:ObservableObject {
#Published var toggle = false
}
let modelStore = Model()
struct ContentView: View {
#ObservedObject var model = modelStore
var body: some View {
VStack {
FullWidthImageView()
Text("Long press the image to change it").bold()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
while running, the "context menu" modified View seems to be "static"!
Yes, on long press, you see the trash image, even though it is updated properly while you dismiss the context view. On every long press you see trash only!
How to make it dynamic? I need that the image will be the same, as on my "main View!
Here we have .id modifier. Let see the difference!
First we have to update our model
class Model:ObservableObject {
#Published var toggle = false
var id: UUID {
UUID()
}
}
and next our View
FullWidthImageView().id(model.id)
Now it works as we expected.
For another example, where "standard" state / binding simply doesn't work check SwiftUI hierarchical Picker with dynamic data crashes
UPDATE
As a temporary workaround you can mimic List by ScrollView
import SwiftUI
struct Row: View {
let i:Int
var body: some View {
VStack {
Image(systemName: "trash")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
.contextMenu(ContextMenu {
Button("A") {}
Button("B") {}
})
Text("I don’t want to show in preview because I don’t have context menu modifire").bold()
}.padding()
}
}
struct ContentView: View {
var body: some View {
VStack {
ScrollView {
ForEach(0 ..< 20) { (i) in
VStack {
Divider()
Row(i: i)
}
}
}
}
}
}
It is not optimal, but in your case it should work
Here is a code (simulated possible your scenario) that works, ie. only image is shown for context menu preview (tested with Xcode 11.3+).
struct FullWidthImageView: View {
var body: some View {
Image("auto")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
.contextMenu(ContextMenu() {
Button("Ok") {}
})
}
}
struct TestContextMenu: View {
var body: some View {
VStack {
VStack {
FullWidthImageView()
HStack {
Text("100 $")
.font(.headline)
Spacer()
Image(systemName: "heart")
}
.padding([.top, .leading, .trailing], 10.0)
}
}
}
}
It's buried in the replies here, but the key discovery is that List is changing the behavior of .contextMenu -- it creates "blocks" that pop up with the menu instead of attaching the menu to the element specified. Switching out List for ScrollView fixes the issue.

SwiftUI View displayed with blue background

I'm trying to reproduce the Apple tutorial(Composing Complex Interfaces) and I have a very weird problem. My CategoryItem view is being displayed as a blue frame.
If I remove the NavigationLink which wraps it, everything works fine but with that one it doesn't.
struct CategoryRow: View {
var categoryName: String
var items: [Landmark]
var body: some View {
VStack(alignment: .leading) {
Text(self.categoryName)
.font(.headline)
.padding(.leading, 15)
.padding(.top, 5)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 0) {
ForEach(self.items) { landmark in
NavigationLink(
destination: LandmarkDetail(
landmark: landmark
)
) {
CategoryItem(landmark: landmark)
}
}
}
}.frame(height: 185)
}
}
}
NavigationLink has a blue accent color by default, just call .accentColor(Color.clear) on it
Or you could try this:
NavigationView {
NavigationLink(destination: Text("Detail view here")) {
Image("YourImage")
}
.buttonStyle(PlainButtonStyle())
}
https://www.hackingwithswift.com/quick-start/swiftui/how-to-disable-the-overlay-color-for-images-inside-button-and-navigationlink
renderingMode(.original) is what did it for me; .accentColor(Color.clear) made the image invisible (my best explanation here is because it didn't have a transparency).
NavigationView {
NavigationLink(destination: Text("Detail view here")) {
Image("YourImage")
.renderingMode(.original)
}
}
As the answer above mentioned, How to disable the overlay color for images inside Button and NavigationLink is a good write up as well.

Present Modal fullscreem SwiftUI

how can i present a modal that will take up the fullscreen and can't be dismissed by swiping it down? Currently I am using .sheet on a view to present a modal that is dismissible.
I haven't noticed any beta changes in Xcode that changes this behavior.
Any help would be appreciated :)
SwiftUI 1.0
I'm not sure if this what you'd want to go with but it's possible to create your own modal screen by using the ZStack and a state variable to control the hiding/showing of it.
Code
struct CustomModalPopups: View {
#State private var showingModal = false
var body: some View {
ZStack {
VStack(spacing: 20) {
Text("Custom Popup").font(.largeTitle)
Text("Introduction").font(.title).foregroundColor(.gray)
Text("You can create your own modal popup with the use of a ZStack and a State variable.")
.frame(maxWidth: .infinity)
.padding().font(.title).layoutPriority(1)
.background(Color.orange).foregroundColor(Color.white)
Button(action: {
self.showingModal = true
}) {
Text("Show popup")
}
Spacer()
}
// The Custom Popup is on top of the screen
if $showingModal.wrappedValue {
// But it will not show unless this variable is true
ZStack {
Color.black.opacity(0.4)
.edgesIgnoringSafeArea(.vertical)
// This VStack is the popup
VStack(spacing: 20) {
Text("Popup")
.bold().padding()
.frame(maxWidth: .infinity)
.background(Color.orange)
.foregroundColor(Color.white)
Spacer()
Button(action: {
self.showingModal = false
}) {
Text("Close")
}.padding()
}
.frame(width: 300, height: 200)
.background(Color.white)
.cornerRadius(20).shadow(radius: 20)
}
}
}
}
}
Example
(Excerpt from "SwiftUI Views" book)
So here, your popup is small, but you can adjust the dimensions to make it fullscreen with the frame modifier that is on that VStack.

Change UIView background color in SwiftUI

Hello everyone. I'm creating a simple iOS app with SwiftUI, and I'd like to change my view's background color to a custom one I have.
This is something extremely easy to do but it seems that it's impossible to achieve in SwiftUI without using ZStacks or workarounds like that, which if you use a List, for example, don't work.
I want to change the color of the view, not use a ZStack with a custom color and then put the rest of the views on top of it. I tried using UIView.appearance().backgroundColor = color when initializing my view, but then all the view is hidden and the screen is filled with the color chosen.
As I'm not good at explaining, here you have some images describing the problem:
Without color change
With color change
My code
import SwiftUI
struct TabController: View {
#State private var selection = 0
init() {
UIView.appearance().backgroundColor = UIColor(named: "backgroundColor")
}
var body: some View {
TabView(selection: $selection) {
HomePageView()
.tabItem {
Image(systemName: "house.fill")
.font(.title)
}
.tag(0)
Text("Second View")
.font(.title)
.tabItem {
Image(systemName: "bell.fill")
.font(.title)
}
.tag(1)
}.edgesIgnoringSafeArea(.top)
}
}
Hope this will help to understand:
var body: some View {
Color.purple
.overlay(
VStack(spacing: 20) {
Text("Overlay").font(.largeTitle)
Text("Example").font(.title).foregroundColor(.white)
})
.edgesIgnoringSafeArea(.vertical)
}
Another If you use the views in Group
var body: some View {
Group {
Text("Hello SwiftUI!")
}
.background(Color.black)
}
For changing the background color, I think the current method most people, and myself, are using is using a ZStack. I haven't seen many problems with putting a UIViewRepresentable on top of it.
var body: some View {
ZStack {
Color.blue
.edgesIgnoringSafeArea(.all)
VStack {
Text("Hello World!")
}
}
}

Resources