SwiftUI - background colour of the Section is not applied to entire section - ios

First of all playground example that demonstrates the problem:
import UIKit
import SwiftUI
import PlaygroundSupport
struct MyList: View {
var body: some View {
content
}
private var content: some View {
List {
Section {
Text("hello")
}
.background(Color.red) // This only changes small area around text. Looking for Workaround 2
}
.background(Color.blue) // This doesn't work (Workaround 1)
.foregroundColor(Color.yellow)
}
init() {
// Workaround 1 - works
UITableView.appearance().backgroundColor = .blue
// Workaround 2 - nothing below helps
UITableView.appearance().sectionIndexTrackingBackgroundColor = .green
UITableView.appearance().sectionIndexBackgroundColor = .green
UITableViewCell.appearance().backgroundColor = .green
UITableViewCell.appearance().backgroundView = nil
UITableViewCell.appearance().backgroundConfiguration = .clear()
}
}
let viewController = UIHostingController(rootView: MyList())
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = viewController
Explanation:
View has a List, which I need to change background for. There's a well-known workaround to change it via UITableView.appearance().backgroundColor, which is what I do. So far so good.
I also need to change the background of the section. In the image below I want the entire section to be red, not white. White should not exist at all:
But I can't find the way to achieve this. If I add .background(Color.red) to the Section, it only changes the small area around the text. OK, but if the white area is not part of List, and not Section then what is the rest of the white area?
I tried various workarounds found in SO, as listed under // Workaround 2 - nothing below helps. None of them help.
So my question is, simply put, how do I get rid of white area in this layout.
Note:
I would prefer to not switch away from List, unless it's the only option.
Answers involving introspect are fine too.

Change:
.background(Color.red) // This only changes small area around text. Looking for Workaround 2
To:
.listRowBackground(Color.red)
Reference

Related

Swaping the color scheme of tab view indicators in SwiftUI 3

I have a tab view defined by this code:
TabView {
ViewOne()
ViewTwo()
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
This creates a tabview indicator like this. However id like to either use a darker color or swap the scheme of this one component.
I believe the indexViewStyle is not customizable at the moment, because the IndexViewStyle protocol is not public.
However, you can try to use TabView(selection:) init and overlay, or somehow hide the original indexView and just make your own.
Not sure what does you mean by color scheme. If you want to change the color of the indicator or remove the background of the color you can do this:
struct PageView: View {
init() {
UIPageControl.appearance().currentPageIndicatorTintColor = .cyan
UIPageControl.appearance().pageIndicatorTintColor = UIColor.red.withAlphaComponent(1)
UIPageControl.appearance().backgroundStyle = .minimal
}
var body: some View {
TabView {
Text("First")
Text("Second")
Text("Third")
}
.tabViewStyle(.page)
}
}
UIPageControl.appearance().currentPageIndicatorTintColor change the color of the current page dot. UIPageControl.appearance().pageIndicatorTintColor change the rest of the dot. Also, in Swift 14 onwards, new style is introduced to UIPageControl. The prominent style which is the one you have now with the rounded view and the old style called minimal style which I change in my code above in UIPageControl.appearance().backgroundStyle.
The output of my code is
If you want to change the color accordingly to dark or light mode, you can add a color set in your Assets and use it.

How to change Background Color of a View containing a List back to White in SwiftUI

I am currently working with Lists in SwiftUI.
Problem: A default View in SwiftUI has a white background Color. However, when adding a List to it, the Background Color changes to systemGray6 while the List Cells take the white bgColor.
Goal: I would like to have a List with white bgColor and Cells with systemGray6 bgcolor.
I accomplished to change the Background Color of the List Rows :
List(users) { user in
// ...
}
.listRowBackground(Color(UIColor.systemGray6)
However, I can't find a solution for changing the Screen's bgColor back to white. I tried the obvious stuff like .background(Color.white).
Does anyone has a solution for this issue?
Thanks for your help.
you can change those colors as you wants, here a show example:(tested with Xcode 12.1 / iOS 14.1)
struct ContentView: View {
init() {
UITableView.appearance().backgroundColor = UIColor.white
}
var body: some View {
List
{
ForEach(0 ..< 20) { index in
Text("Row \(index)")
.listRowBackground(Color(UIColor.systemGray6))
}
}
}
}

How to set UIHostingController's background color to clear?

I need to be able to see through my SwiftUI Views as well as the UIHosting Controller presenting them in order to see a background image underneath them. The code below still shows a white rectangle under my SwiftUI View. Paul Hudson says to use edgesIgnoringSafeArea but I cannot use that as my SwiftUIView is embedded in a larger UI scheme. Is there any way to make this white rectangle I am seeing clear?
var body: some View {
ZStack {
VStack {
//omitted
}
}.background(Color.clear)
}
If you are using a UIHostingController, you need to set the backgroundColor property of its view to .clear as well.
yourHostingController.view.backgroundColor = .clear

Runtime crash trying to modify SwiftUI Navigation Bar Text attributes

I am trying to modify the navigation bar text attributes in SwiftUI (to add a text shadow) and have hit a wall trying to understand why I'm receiving run-time crashes in the simulator. There was another thread (ref: below) that was able to solve changing the font type using init() to modify the appearance, however trying to use init to modify the Text("") method to add a shadow results in a crash.
I've also tried extracting the Text("NavBarTitle") into its own method, then applying modifiers (no luck there). As seen in my code I've tried extracting the text into a variable results in a crash. Even just applying the modifiers directly causes a crash.
I'm not experienced enough in SwiftUI to call this a bug but it really feels like one.
Thanks for your help in advance!
import SwiftUI
struct ContentView: View {
init() {
UINavigationBar.appearance().largeTitleTextAttributes = [.shadow: 5]
}
let navigationBarText: Text = Text("Navigation Bar")
var body: some View {
NavigationView {
VStack {
Text("Hello, World!")
}
.navigationBarTitle(navigationBarText)
}
}
}
ref: https://stackoverflow.com/a/57632229/1514009
It should be provided NSShadow object instead of number, as below
init() {
let shadow = NSShadow()
shadow.shadowOffset = CGSize(width: 5, height: 2)
UINavigationBar.appearance().largeTitleTextAttributes = [.shadow: shadow]
}

Not possible to control animations in a Form?

Is it not meant to be possible to control the animations that take place inside of a Form view? I have here a playground that demonstrates the issue, along with a gif of what happens. As you can see, my transition on the 2nd animated view is completely ignored, and I had to manually slow down the video because the durations are ignored, too.
I don't really want a scaling transition, this was just to demonstrate that no matter what I put in there the animation is the same. Is that expected, or is it a bug? Or am I just doing something totally wrong?
It's also not clear to me why the animation of the VStack is handled so differently than the simple Text field, which slides down nicely while the VStack seems to be getting some combination of .move and .opacity.
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
#State var showGoodAnimation = false
#State var showBadAnimation = false
var body: some View {
Form {
Toggle(isOn: self.$showGoodAnimation.animation(.easeInOut(duration: 1))) {Text("Yay!")}
if self.showGoodAnimation {
Text("I animate beautifully.")
}
Toggle(isOn: self.$showBadAnimation.animation(.easeInOut(duration: 1))) {Text("Boo!")}
if self.showBadAnimation {
VStack {
Text("Hi.").padding()
Text("I'm a hot mess.").padding()
}
.frame(height: 250)
.transition(.scale)
}
Text("I'm just always here.")
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
At a guess, probably worked around this question some time ago, but for the benefit of those beating their head's against SwiftUI Form and the like now (as I was :-) )
It turns out that Forms, Lists and (no doubt) other components purposely ignore animation customisation because they are "higher-level" SwiftUI View components (unlike V and HStack's).
They do this because SwiftUI's higher-level components are intended to convey semantic information and (more practically) to work well across all platforms. To achieve this, Apple's engineering decision has been to make animation "easy", but (as observed) only to the extent of essentially turning it "on" or "off".
It's likely engineered like this because if a developer wants more control. Then Apple believes encouraging them to use the lower-level components will be less painful than trying to work around the optimisations they have applied to their higher-level view components.
Anyway, for the determined, there is at least one escape hatch via wrapping the View in a container and specifying the .animation(nil) modifier (as mentioned in Asperi's SO answer here.
An example of this is shown below for completeness; personally, I'm avoiding this pattern as I suspect it's a bit of a footgun.
import PlaygroundSupport
import SwiftUI
struct ContentView: View {
#State var showGoodAnimation = false
#State var showBadAnimation = false
var body: some View {
Form {
Toggle(isOn: self.$showGoodAnimation.animation(.easeInOut(duration: 1))) { Text("Yay!") }
if self.showGoodAnimation {
Text("I animate beautifully.")
}
Toggle(isOn: self.$showBadAnimation.animation()) { Text("Boo!") }
VStack {
if self.showBadAnimation {
List {
Text("I animated differently").padding()
Text("But am I a footgun?").padding()
}
.transition(.asymmetric(insertion: .slide, removal: .opacity))
.animation(.easeOut(duration: 5))
}
}
.animation(nil)
.transition(.slide)
Text("I'm just always here.")
}
}
}
PlaygroundPage.current.setLiveView(ContentView())

Resources