I'm trying to add some content insets in TabView with page style. Is it possible to change TabView content width, so it could show a part of next and previous View? I can easily do it with HStack or ScrollView, but I wonder if I can do it with TabView as well, because TabView has many features I need in this case.
My test code looks like this:
var body: some View {
TabView {
Group {
ExcursionView(index: 1, count: 3)
ExcursionView(index: 2, count: 3)
ExcursionView(index: 3, count: 3)
}
.padding(.horizontal, 20)
}
.tabViewStyle(.page)
}
Related
I am looking for how to align items in a list horizontally, where the items start at the last item, or on the right edge, and go left from there.
For example, with a list of 1-20, I'd be looking to show items 1-5 off the left edge of the screen, with item 20 being the right-most item, right on the edge of the screen. An image of this can be shown below (it is not the solution running, but rather a contrived image to show the desired effect).
How can I do this in SwiftUI?
An HStack will simply center itself horizontally. HStack doesn't seem to have a horizontal alignment that I can control.
An HStack in a scrollview allows me to reach the right-most item, but still starts at the first item, or the left-most edge of the list.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Divider()
// the HStack just tries to fit everything within the width of the view,
// without anything going "offscreen"
HStack(spacing: 10) {
ForEach(1..<21) { index in
Text("\(index)")
}
Spacer()
}
Divider()
// placing the HStack within a ScrollView does allow elements to go offscreen,
// but the list starts at 1 and goes offscreen at 16 on the right
// I am looking for how to "anchor" the list on the right edge instead,
// with elements 1 through 5 being displayed off the left edge of the screen,
// and the right-most element being 20, directly on the right edge of the screen
ScrollView(.horizontal) {
HStack(spacing: 10) {
ForEach(1..<21) { index in
Text("\(index)")
}
}
}
.frame(height: 100)
Divider()
// are there any other ways to achieve my desired effect?
}
}
}
If I properly understand question looks like you need ScrollViewReader:
// Define array for your label
var entries = Array(0...20)
ScrollView(.horizontal) {
ScrollViewReader { reader in
HStack(spacing: 10) {
ForEach(entries, id: \.self) { index in
Text("\(index)")
}.onAppear {
// Here on appear scroll go to last element
reader.scrollTo(entries.count - 1)
}
}
}
}
I am trying to add a very short row to my list with a frame height of 2 but the list is adding an undesired padding above and below the list item or constraining to a minimum height and I don't know how to remove it. I have produced the following to illustrate the problem:
struct ContentView: View {
var body: some View {
List {
Color.red
.frame(height: 2)
Color.blue
.frame(height: 2)
}
}
}
How can I remove this padding above and below the list item? It's the same if using a section and adding header or footer. It will not allow me to have a list entry with small frame height.
In a LazyVStack I don't have this problem but I need to use a list.
Use .environment(\.defaultMinListRowHeight, 0) to make each row have a minimum height of 0. Otherwise, each row will always be at least 44 (the default) points high.
Use .listRowInsets(EdgeInsets()) to make each row have no inset. You could also do .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)), which results in the same.
struct ContentView: View {
var body: some View {
List {
Color.red
.frame(height: 5)
.listRowInsets(EdgeInsets()) /// 2.
Color.blue
.frame(height: 5)
.listRowInsets(EdgeInsets())
}
.environment(\.defaultMinListRowHeight, 0) /// 1.
}
}
Result:
I want to build a TabView with 4 tabs having collection views in it. Below is my code of one tab named 'Gallery'.
var body: some View {
NavigationView {
ScrollView {
GridStack(rows: 3, columns: 2) { row, column, totalColumn in
CardView(card: self.cards[(row * totalColumn) + column])
}.padding().background(Color.red)
}
.navigationBarTitle("Gallery")
}
}
When I give background color for ScrollView, scrolling is not working for NavigationView largeTitle. How can I achieve this, I want to give red color for full view's background? What if I need to achieve this same backgorund color for all tabs?
Here is possible approach (scroll view is not broken in such case)
NavigationView {
GeometryReader { gp in
ScrollView {
ZStack(alignment: .top) {
Rectangle().fill(Color.red) // << background
// ... your content here, internal alignment might be needed
}.frame(minHeight: gp.size.height)
}
.navigationBarTitle("Gallery")
}
}
I am developing an app based on a Tabview with three TabItems. Each TabItem is a List and I would be able to show a kind of modal view over those Lists. The problem becomes when I can not call a Sheet as modal view because Sheets are almost full windowed. I need some kind of bottom modal view, so I create a View that I present over a List with higher ZIndex. It seems to work until you click in the tabbar and select another TabItem having deployed the "modal" view. The error is:
[TableView] Warning once only: UITableView was told to layout its
visible cells and other contents without being in the view hierarchy
(the table view or one of its superviews has not been added to a
window). This may cause bugs by forcing views inside the table view to
load and perform layout without accurate information (e.g. table view
bounds, trait collection, layout margins, safe area insets, etc), and
will also cause unnecessary performance overhead due to extra layout
passes.
So, I would like as solution to restrict the tappable area to the "modal" view area. ¿Is there a way to achieve this?
Probably you have some condition state depending on which you present your "modal-like" view, so depending on the same condition you can disable below TabView, like below
TabView {
// ... tabs content here
}.disabled(showingModal)
Update: Here is a demo of approach that I meant (tested with Xcode 11.3+)
struct TestTabViewModal: View {
#State private var selectedTab = 0
#State private var modalShown = false
var body: some View {
ZStack {
TabView(selection: $selectedTab) {
VStack {
Button("Show Modal") { self.modalShown = true }
.padding(.top, 40)
Spacer()
}
.tabItem {
Image(systemName: "1.circle")
}.tag(0)
Text("2").tabItem {
Image(systemName: "1.circle")
}.tag(1)
}.disabled(modalShown)
if modalShown {
RoundedRectangle(cornerRadius: 10)
.fill(Color.yellow)
.frame(width: 320, height: 240)
.overlay(Button("CloseMe") { self.modalShown = false })
}
}
}
}
i'm trying to code a simple login page on my app. I started using SwiftUI on my newlly updated Mac OS Catalina. The Apple documentation is still lacking a lot.
I need to center a VStack vertically on a Scrollview ocupying the whole page with a "limit" on it's width of 400.
Something like this:
ScrollView(.vertical) {
VStack {
Text("Hello World")
}
.frame(maxWidth: 400, alignment: .center)
}
It was easy with UIScrollView, just needed to set the ContentView to fill height and width and then centering a Vertical StackLayout inside the Content View but now with SwiftUI i just wonder..
The goal is something like this (Credit to the author)
If someone is wondering why i want everything inside a scrollview, it's beacause my form is quite big and i expect the user to use both landscape and portrait view so i really need the content to be scrollable, bear in mind also that in a Ipad the form doens't fill the whole screen that's why i want it centered vertically.
You can vertically center content in a scroll view by using GeometryReader to get the parent view's dimensions and setting the scroll view's content's minHeight to the parent's height.
When the content is too big to fit vertically it'll just scroll like normal.
For example:
var body: some View {
GeometryReader { geometry in // Get the geometry
ScrollView(.vertical) {
VStack {
Text("Form goes here")
.frame(maxWidth: 400) // Set your max width
}
.padding()
.background(Color.yellow)
.frame(width: geometry.size.width) // Make the scroll view full-width
.frame(minHeight: geometry.size.height) // Set the content’s min height to the parent
}
}
}
I've build a more generic view based on #Alex answer
/// Custom vertical scroll view with centered content vertically
///
struct VScrollView<Content>: View where Content: View {
#ViewBuilder let content: Content
var body: some View {
GeometryReader { geometry in
ScrollView(.vertical) {
content
.frame(width: geometry.size.width)
.frame(minHeight: geometry.size.height)
}
}
}
}
You can use it anywhere in your app like this
var body: some View {
VScrollView {
VStack {
Text("YOUR TEXT HERE")
}
}
}