List View longer than its content (SwiftUI) - ios

My question is regarding the List in SwiftUI. I provide a picture and the code in order to present the problem easier.
List(){
Section(header: Text("Notifications").textCase(nil).font(.title2)) {
Radio_Buttons_Group()
}
Section(header: Text("Apperance").textCase(nil).font(.title2)) {
Radio_Buttons_Group()
}
}
.listStyle(GroupedListStyle())
What I'm trying to figure out is how to get that blue line(it comes from Xcode preview, it represents the List View) to end after the last element.
Thank You

Related

What is wrong with the iOS Keyboard toolbar in SwiftUI

I am aware I asked a similar question before, but it seems like I have not understood the core concept of how to present a custom toolbar above a keyboard.
I successfully solved my problem on how to present one with a search field (SwiftUI 2.0: Custom keyboard elements).
Now I want to present a keyboard when a textfield within a detail view of a list is clicked, but again the keyboard toolbar does not show. Does anyone have an idea why?
VStack {
Text("Weight:")
TextField("0", text: $weight)
.keyboardType(.decimalPad)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
HStack {
Button(action: {
print("Set bodyweight")
},
label: {Text("Bodyweight")
})
Picker("", selection: $weightType) {
ForEach(weightSuffix.allCases, id: \.self) {
Text($0.rawValue)
}
}
.pickerStyle(.segmented)
}
}
}
}
.border(Color.red)
[EDIT]
After AsperiĀ“s comment I Created a small git: https://gist.github.com/joni8a/bc021ef597cb6efa1ab0ca277d602478
Now it gets even weirder, if I attach the toolbar modifier to the list element I get the intended behavior, showing 1 button above the toolbar
If I append the toolbar modifier to the textfield inside the detail view I get the following result:
I think this is a weird behavior. It seems like I have not understood a core concept of SwiftUI. On the other hand if I can't attach the viewmodifer to the textfield itself, it is hard to uncouple the detail view from the list view ...

How to display a detailed view on startup for a NavigationView (SwiftUI)

This tutorial uses a NavigationView to display a List of elements which can be clicked, leading to a detailed view, LandmarkDetail. On an iPhone, the UI uses the StackNavigationViewStyle() which looks and works fine, but on an iPad the NavigationView is displayed on the side. I want to be able to fill up the remaining space with a detailed view (see below).
I have tried to display the detailed view, LandmarkDetail, beside the NavigationView like so:
var body: some View {
NavigationView {
List {
Toggle(isOn: $showFavoritesOnly) {
Text("Favorites only")
}
ForEach(filteredLandmarks) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
}
.navigationTitle("Landmarks")
LandmarkDetail(landmark: ModelData().landmarks[0])
}
}
This approach works fine for the iPad, but produces unexpected results (overlapping tiles, etc.) on the iPhone (see below). Is there a better way for achieving my desired results?
Thanks for any help and I apologise about potential obvious mistakes, etc. This is my first time using SwiftUI and there are noticeably less resources available than for Android development.
Creating a modifier which programmatically assigned the NavigationView style depending on the target device fixed this issue.
extension View
{
func navigationStyleModification() -> some View
{
if UIDevice.current.userInterfaceIdiom == .phone
{
return AnyView(self.navigationViewStyle(StackNavigationViewStyle()))
} else
{
return AnyView(self.navigationViewStyle(DefaultNavigationViewStyle()))
}
}
}
The modifier can be called via:
NavigationView
{
...
}.navigationStyleModification()
I hope this helps someone who has a similar issue.

Force one NavigationLink to the detail view in SwiftUI

I have a master-(primary)-detail setup in my app, where most of the list items in the top-level NavigationView go to another list of submenu items, with .isDetailLink(false), and then those submenu items then navigate to the detail view. This is all working as intended.
I'm trying to also put in a NavigationLink in the top level list to got to my settings page, which I want to force into the detail view. There isn't a submenu for this link, so I tried to navigate to it directly and force .isDetailView(true). However, this causes the view to open in what would be the primary window above, but hidden at first. The detail window only has a back button, which then makes the intended view pop out from the menu column.
Is there a way to force only the settings menu item to open in the detail view, essentially skipping one navigation level?
Thanks!
Here's the simplified version of what I'm currently trying:
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink(destination: SubMenu1()) {Text("MenuItem1")}
.isDetailLink(false)
NavigationLink(destination: SubMenu2()) {Text("MenuItem2")}
.isDetailLink(false)
NavigationLink(destination: SubMenu3()) {Text("MenuItem3")})
.isDetailLink(false)
NavigationLink(destination: SettingsView()) {Text("Settings")}
.isDetailLink(true)
}
}
}
}
struct SubMenu: View {
var body: some View {
List {
ForEach(menuItems, id: \.self) { item in
NavigationLink(destination: DetailView(item)) {
Text(item)
}
}
}
}
}
UPDATE
I've taken some screenshots to illustrate the issue:
The top level navigation view:
With one of the sub-menus selected, and .isDetailView(false). This is working properly:
Settings does not have a sub-menu like the others, so I want it to open directly on the right hand side. Instead, it opens like this, and is only revealed when the back button is pressed:
Hey, I have seen your screenshots. I Think you are using NavigationView 2 times there in Settings. Please remove any one of them, It should work fine!

SwiftUI - NavigationLink Content loaded too early

I have a basic list in my first View as Follows:
func buildList(sections: [Client]) -> some View {
let list = List {
ForEach(sections) { client in
Section(header: Text(client.name)) {
ForEach(client.projects) { project in
NavigationLink(destination: BuildsRouter.build(forProject: project)) {
HStack {
Text("Test \(project.id)").fontWeight(.ultraLight)
}
}
}
}
}
}
return list
}
I'm using NavigationLink to provide the details view for my Project object.
Thing is, when I make a Memory analysis graph I can see that BuildsView ( created from BuildsRouter.build(forProject: project) are created before I actually tap the navigation Link.
Question:
Is there any way to create the details View once the link is tapped?
True, I wrote a blog post on this. You can wrap the destination views in a Lazy Container as a workaround. Update: From Xcode 11.4.1 NavigationLinks are lazy by default.

How to disable SwiftUI's default behavior?

SwiftUI makes it very easy to build declarative UIs. However, sometimes they assume defaults that are not necessarily what we want.
Example:
When adding two buttons inside a list row, SwiftUI automatically makes the whole row touchable, and both button's actions are called on row tap. This is the default behavior, as demonstrated in their WWDC videos.
But I do not want this behavior. I want both buttons to work properly, and the row to not be tappable.
Question:
How can we tell our Guacamole expert (to use the WWDC reference) to stop assuming how I want my list (or any other behavior) to work?
Any help would be appreciated.
If the List's default behavior is not required, you could use a VStack:
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
Button(action: {
print("bar")
}) {
Image(systemName: "photo")
}
}
}
}
However if List is really required, then it could be customized by writing a custom ListStyle.
(Also take a look at this question: How to change ListStyle in List.)
It seems that SomethingStyle protocol is the way Apple wants developers to use to modify native SwiftUI elements/behavior. Another example would be ButtonStyle or TextFieldStyle, etc.
I am under the impression that Apple wants to enforce their style guidelines. Also to add onto #backslash-f answer you could also just use a for each instead of a list, this will give you a similar effect and allow much more customization.
struct doubleList: View {
var body: some View {
VStack{
ForEach(1 ..< 10) {index in
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
}
}
}
}
Another option to try would be to wrap an UITableView into an UIViewRepresentable and try to enable buttons that way
It seems there might be another way around this by using tap gestures
Image(systemName: "photo")
.gesture(TapGesture().onEnded() {
print("action2")
})

Resources