I have a scrollable panel with buttons above the list. And in this layout the lower part of buttons is unclicable.
import SwiftUI
struct TestListScreen: View {
var body: some View {
NavigationView {
VStack(spacing: 0) {
ScrollView(.horizontal, showsIndicators: true) {
HStack(spacing: 8) {
ForEach(1..<10) { i in
Button { print(i) } label: {
Text("Button \(i)")
.padding(24)
.background(Color.yellow)
}
}
}
}
List {
ForEach(1..<100) { i in
Text(String(i))
}
}
.listStyle(.plain)
.listRowInsets(EdgeInsets())
.frame(maxHeight: .infinity)
}
.navigationBarTitle("Buttons above the list", displayMode: .inline)
}
}
}
struct TestListScreen_Previews: PreviewProvider {
static var previews: some View {
TestListScreen()
}
}
If I remove ScrollView wrapped buttons HStack, or if I remove the list under buttons, everything works well. Also I cannot replace list with a ScrollView + VStack because of poor performance.
So... the "problem" is that you have a scrolling view of button. That 16 pixels is to show the scrollbar when you drag the view.
Easy fix is to leave space for it by adding padding.
ScrollView(.horizontal, showsIndicators: true) {
HStack(spacing: 8) {
ForEach(1..<10) { i in
Button { print(i) } label: {
Text("Button \(i)")
.padding(24)
.background(Color.yellow)
}
}
}
.padding(.bottom, 16)
note: while adding the space does make the whole button clickable, if you just finished dragging the buttons, the 16 pixels is increased for a couple seconds after you finish dragging. During that time, part of the button sill won't be clickable, instead it makes the scrollbar tab get bigger.
Currently, I have to implement bottom sheet. And I found the very example of my need.
Is this component system component of swift or swiftui?
OR do I need to implement on my own?
PLEASE LET ME KNOW IF U HAVE SOME INFOS! XD
At first I implement with ZStack, drag gesture but the animation is not what I expected.
I need Information about whether there is component like .sheet(isPresented: Bool, content: View) of the modal like above image.
As our friend said before, it is a sheet. Inside the sheet you can either define a new view or call any of your views. Then you have to use the modifier .presentationDetents which receive a Set of PresentationDetents to say where the view has to stop when appearing on the screen. This modifier must be apply to the content of the sheet and not directly to the sheet.
struct ContentView: View {
#State var isSheetShown = false
var body: some View {
VStack {
Button("Show view"){
isSheetShown = true
}
}.sheet(isPresented: $isSheetShown, content: {
StackOfButtons()
.presentationDetents([.medium])
})
.padding()
}
}
Finally, to create that stack type of buttons you can put them all in a HStack, give them individually some padding, set a little of spacing in the HStack and the round the corners of the stack. Something like this:
struct StackOfButtons: View {
var body: some View {
HStack(spacing: 2){
Button {
print("Hola que ase")
} label: {
Image(systemName: "list.bullet")
.padding()
.background(.thinMaterial)
.foregroundColor(.black)
}
Button {
print("Hola que ase")
} label: {
Image(systemName: "list.dash")
.padding()
.background(.thinMaterial)
.foregroundColor(.black)
}
Button {
print("Hola que ase")
} label: {
Image(systemName: "list.number")
.padding()
.background(.thinMaterial)
.foregroundColor(.black)
}
}.cornerRadius(10)
}
}
Result
I am writing an application using Xcode 14.0.1, and testing on an iPhone 12 mini running iOS 16.0. The current project build is for iOS 14.7. Here is my TabView...
TabView {
ByEyeView()
.tabItem { Label("ByEye", systemImage: "eye") }
ChartView()
.tabItem { Label("Chart", systemImage: "square.grid.4x3.fill") }
ListView()
.tabItem { Label("List", systemImage: "list.bullet") }
EditView()
.tabItem { Label("Edit", systemImage: "square.and.pencil") }
CameraView()
.tabItem { Label("Camera", systemImage: "camera") }
SettingsView()
.tabItem { Label("Settings", systemImage: "gear") }
}
//.labelStyle(TitleAndIconLabelStyle())
//.padding(8)
//.ignoresSafeArea(edges: .bottom)
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
This gives a capsule at the bottom of the page with a small version of the icon and no text. I cannot enlarge the Label with .frame, and the .labelStyle() setting is ignored. I take it this is part of PageTabViewStyle() - the index is supposed to be small, and I can probably not change that. But the index sits over the view content, so I need its height if I am to keep buttons clear of it.
Can I find out the index height? Or does PageTabViewStyle assume that the index is small and you should work around it?
The commented-out .ignoreSafeArea() moves the index down while the page remains the same. The .padding() keeps it a bit clear of the bar at the bottom. This is what I am working with for now. This is foul: it will not work with other devices or screen orientations.
The bigger picture:
I have six entries. That does not fit in the default view, so I get a ... More tag which leads to an extra menu. Ugly. I like the PageTabViewStyle method of scrolling, but I want an index with a known height - preferably one that uses the full labels and sits at the bottom of the TabView layout, under the tabbed views.
This was one of those 'Magic Eye' things when you stare at it for days and it makes no sense, and suddenly everything rearranges itself...
Maybe TabPageViewStyle was intended to be for pages where there is no visible index, or overlaying a small index does no harm. This would work for browsing images. All the cunning has gone into making the index view unobtrusive. If you need to know how big it is, then perhaps TabPageViewStyle is not what you want.
What I said I wanted was actually a Scrollable horizontal list, followed by the currently selected list. Something like this...
let tabW = CGFloat(UIScreen.main.bounds.width / 5.0)
enum Page {
case ByEye
case Chart
case List
case Edit
case Camera
case Settings
}
#State private var page = Page.ByEye
func pageButton(_ select: Page, _ icon: String, _ title: String) -> some View {
return Button {
page = select
} label: {
VStack {
Image(systemName: icon)
Text(title)
} .frame(width: tabW)
} .foregroundColor( page == select ? Color.white : Color.gray )
}
var body: some View {
VStack() {
ScrollView(.horizontal) {
HStack() {
pageButton(Page.ByEye, "eye", "ByEye")
pageButton(Page.Chart, "square.grid.4x3.fill", "Chart")
pageButton(Page.List, "list.bullet", "List")
pageButton(Page.Edit, "square.and.pencil", "Edit")
pageButton(Page.Camera, "camera", "Camera")
pageButton(Page.Settings, "gear", "Settings")
}
}
switch page {
case .ByEye:
ByEyeView()
case .Chart:
ChartView()
case .List:
ListView()
case .Edit:
EditView()
case .Camera:
CameraView()
case .Settings:
SettingsView()
}
Spacer()
}
It is not much longer than my original version. It is not as pretty is it could be - when you overflow the title bar you get half an icon, where an ellipsis would be better. But I can fix that later.
The other answer is to write your own index table....
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack() {
pageButton(Page.EyeTest, "eyeglasses", "EyeTest", proxy)
pageButton(Page.Tone, "pause.rectangle", "Tone", proxy)
pageButton(Page.Chart, "square.grid.4x3.fill", "Chart", proxy)
pageButton(Page.ByEye, "eye", "ByEye", proxy)
pageButton(Page.List, "list.bullet", "List", proxy)
pageButton(Page.Camera, "camera", "Camera", proxy)
pageButton(Page.Settings, "gear", "Settings", proxy)
}
}
.onAppear { proxy.scrollTo(page, anchor: .center) }
.onChange(of: page) { page in
withAnimation {
proxy.scrollTo(page, anchor: .center)
}
}
}
This particular one has button-sized icons and text. 'page' is an enum, and also the tags of the TabView. If you stick it in the layout, you can make it fit around the TabView. You will want to hide the TabView index, which you can do with...
.tabViewStyle(PageTabViewStyle(indexDisplayMode:.never))
Very novice to the app development game. I am trying to put this toolbar above the .decimalPad and I cannot get this large gap to go away.
VStack {
Rectangle()
.foregroundColor(Color(UIColor.systemBackground))
.frame(height: 35)
.overlay {
HStack {
Spacer()
Button(action: {
isTextFieldFocused = false
}) { Text("Done")}
}
.offset(y: -3)
.padding(.trailing)
}
.opacity(isTextFieldFocused ? 1 : 0)
.ignoresSafeArea(.keyboard) //This makes sure the bottom tab bar stays below the keyboard.
}
I initially thought it was something in another view causing the spacing, but I managed to parse through the views in the canvas and it does it regardless.
Here is what I'd like it to look like, for reference.
What I want
To add a Button onto your keyboard, you use a .toolbar with the locations to .keyboard like this:
TextField("Enter Text", text: $text)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Button(action: {
isTextFieldFocused = false
}) { Text("Done")}
// If you want it leading, then use a Spacer() after
Spacer()
}
}
You were overthinking it by adding the Rectangle. This is why we look for minimal reproducible examples. We can dial in the fix for your specific code.
I want to change the discoverability title of a keyboard shortcut in SwiftUI.
As you can see below the title shows in the popup if used in text button, but if you use an image for the button it doesn't show in the popup (when holding cmd on the keyboard to view supported shortcuts by the app).
struct ContentView: View {
var body: some View {
VStack {
Button("Save to Favorites") {
}
.keyboardShortcut("a")
Button {
} label: {
Image(systemName: "heart.fill")
}
.keyboardShortcut("s")
}
}
}
How can I add a title to the shortcuts help popup?
Note that I have tried all accessibility stuff, i.e. label, identifier, hint, etc... and It didn't work.
Not a super elegant solution but I got it working by adding a Text with a .frame size of width: 0, height: 0. This effectively hides the Text from view but ensures it appears when the user holds down the ⌘ key.
Consider putting it in a ZStack too as the default arrangement could have it ever so slightly off centre.
VStack {
Button("Save to Favorites") {
}
.keyboardShortcut("a")
Button {
} label: {
ZStack {
Text("heart")
.frame(width: 0, height: 0) // <- this part
Image(systemName: "heart.fill")
}
}
.keyboardShortcut("s")
}