I am trying to recreate the following:
and I have the following code which has the gist of it, but not the exact look and feel, and I am still trying to get the hang of the UI aspects of Swift.
VStack(spacing: 30) {
Group {
VStack {
HStack {
Image(systemName: "2.circle")
Text("Jan 2th, 2021 at 2:34 PM")
}
HStack {
Divider()
VStack {
Text("Title here")
Text("Notes here")
Text("Item not tracked on this day")
}
}.frame(height: 200)
}
}
}
Can anymore provide a better way of mirroring the image?
Here is possible solution. Tested with Xcode 12.1 / iOS 14.1
var body: some View {
VStack(spacing: 30) {
HStack(alignment: .top) {
VStack {
Image(systemName: "2.circle")
.resizable()
.frame(width: 40, height: 40)
HStack {
Divider()
}
}
VStack(alignment: .leading) {
Text("Jan 2th, 2021 at 2:34 PM").padding(.bottom)
Text("Title here")
.font(.title).bold()
Text("Notes here")
.font(.title3).bold().padding(.bottom)
Text("Item not tracked on this day")
}
}
.fixedSize(horizontal: false, vertical: true)
}
}
Related
I'm trying to align a row in a list but can't work out the order that I need to place items in to get the desired results.
My current code is
HStack {
Image(imageName ?? "")
.renderingMode(.original)
.resizable()
.scaledToFit()
.frame(height: 72.0)
Text("**1**")
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
Currently this is giving me the below layout
But I'm trying to make it look like this
This is what you need:
struct ContentView: View {
var body: some View {
List {
HStack(spacing: 20.0) {
Image(systemName: "swift")
.resizable()
.scaledToFit()
.frame(height: 72.0)
VStack(alignment: .leading) {
Text("Name")
.bold()
HStack(alignment: .top) {
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
}
}
}
}
}
You just need more stacks to wrap things, like
HStack {
Image("picture")
.renderingMode(.original)
.resizable()
.scaledToFit()
.frame(height: 72.0)
VStack(alignment: .leading) { // << here !!
Text("Name").bold()
HStack(alignment: .top) { // << here !!
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
}
}
Tested with Xcode 14 / iOS 16
My project was using a List but I needed a ScrollView wrapped view so I changed the List to just a ForEach loop with a view and Divider in between. I noticed my Context Menu doesn't look the same as when it was in the List as in the screenshot below.
I'd like the item selected with context menu to look like the List item selected since I can no longer use List in the code, it doesn't look as pretty. Also I have to press on the image and or text to open the Context Menu unlike in a List you can select the row. The end result would be to mimic the style of the selected List item.
/// Context Menu looks terrible
VStack (alignment: .leading, spacing: 0){
ForEach(self.welcome.views.dropLast(), id: \.id) { view in
ForEach(view.views ?? [], id: \.id) { purple in
ForEach(purple.views, id: \.id) { fluffy in
VStack (alignment: .leading, spacing: 0){
if viewClass == "FeaturedHeaderView" {
Text(title)
.font(.title3)
.fontWeight(.bold)
} else {
HStack (spacing: 15){
RequestImage(Url(image), animation: nil)
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.clipped()
.cornerRadius(13.5)
VStack (alignment: .leading){
Text(name)
.font(.headline)
.fontWeight(.bold)
Text(author)
.foregroundColor(Color.secondary)
.font(.footnote)
Text(repo)
.foregroundColor(Color.secondary)
.font(.caption)
}
}
.contextMenu(ContextMenu(menuItems: {
HStack {
Button(action: {
openURL(URL(string: "URL")!)
}) {
Label("Open in Safari", systemImage: "safari.fill")
}
}
}))
}
}
Divider()
}
}
}
.padding(.all, 5)
.padding(.leading, 5)
}
/// List Context Menu looks great but can't use List in ScrollView
List {
ForEach(self.welcome.views.dropLast(), id: \.id) { view in
ForEach(view.views ?? [], id: \.id) { purple in
ForEach(purple.views.dropLast(), id: \.id) { fluffy in
VStack (alignment: .leading, spacing: 0){
if viewClass == "FeaturedHeaderView" {
Text(title)
.font(.title3)
.fontWeight(.bold)
} else {
HStack (spacing: 15){
RequestImage(Url(image), animation: nil)
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.clipped()
.cornerRadius(13.5)
VStack (alignment: .leading){
Text(name)
.font(.headline)
.fontWeight(.bold)
Text(author)
.foregroundColor(Color.secondary)
.font(.footnote)
Text(repo)
.foregroundColor(Color.secondary)
.font(.caption)
}
}
.contextMenu(ContextMenu(menuItems: {
HStack {
Button(action: {
openURL(URL(string: "URL")!)
}) {
Label("Open in Safari", systemImage: "safari.fill")
}
}
}))
}
}
}
}
}
.padding(.all, 10)
.listRowInsets(EdgeInsets())
}
The possible solution is to add background modifier above contextMenu, like
.frame(maxWidth: .infinity) // << to make it screen-wide
.background(
RoundedRectangle(cornerRadius: 12) // << tune as needed
.fill(Color(UIColor.systemBackground)) // << fill with system color
)
.contextMenu(ContextMenu(menuItems: {
Demo with some replication (used Xcode 12.4 / iOS 14.4)
I'm building an iOS app and currently I've found a strange behaviour with Divider component.
See the following screenshot:
The chevron on the top right side makes the other two(or more) components appear/disappear, the problem happens with the vertical Divider which should appear next to CONTROLS A.
The general SwiftUI hierarchy for the view is something similar to ScrollView -> VStack -> ForEach -> [HStack -> Img Divider VStack (with SOME TEXT + CONTROLS X)].
Note that it happens not only for the first component.
Controls X contains SwiftUI components, nothing custom.
Now some interesting facts I've found after debugging:
If I make the Divider show/disappear with a boolean flag which changes on tap, the Divider is shown as expected
If I make the Divider show/disappear with a boolean flag which changes on "onAppear" the Divider is not shown
The Divider view is included with width 0.33 but height 0 (that's the real problem)
Adding or removing views to "Controls A" can make the Divider show
Been trying to find the cause for it without success so I'm inclined to think it's probably a bug where the final height is not properly updated for the Divider component.
Update:
The issue happens only on some devices, iPhone 12 is one of them.
Here's some code to reproduce a similar issue (in this case the divider is visible but its height is wrong):
struct BugScreen: View {
var body: some View {
VStack {
Text("Bug Test")
ScrollView(showsIndicators: false) {
ForEach((1..<3)) { i in
MyView(index:i)
}
Spacer(minLength: 75)
}
.padding(.horizontal, 20)
}
.navigationBarTitle("", displayMode: .inline)
}
}
struct MyView: View {
#State var expanded = false
var index: Int
var body: some View {
VStack(spacing: 0) {
HStack(spacing: 15) {
Image("ImageName")
.resizable()
.frame(width: 50, height: 50)
Divider()
VStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 5) {
HStack {
Text("Test \(index)")
.font(.headline)
.fontWeight(.light)
.fixedSize(horizontal: false, vertical: true)
Spacer()
Image(systemName: expanded ? "chevron.up": "chevron.down")
.padding(.leading, 10)
.font(Font.body.weight(.thin))
}
}
Divider()
Text("Some text")
.fixedSize(horizontal: false, vertical: true)
}
}
.padding([.vertical, .leading])
.padding(.trailing, 5)
.background(
RoundedRectangle(cornerRadius: expanded ? 0: 25, style: .continuous).foregroundColor(.white)
)
.onTapGesture {
withAnimation { expanded.toggle() }
}
if expanded {
Divider().background(Color(.black))
VStack {
ForEach((1..<4)) { control in
Spacer(minLength: 10)
MyControlsView()
Divider().background(Color(.black))
}
Text("More text")
}
.padding(.horizontal, 10)
.background(Color.white)
}
Divider().background(Color(.black))
}
}
struct MyControlsView: View {
#State var sliderValue = 0.0
var body: some View {
VStack {
HStack {
Image("image_name")
.resizable()
.frame(width: 50, height: 50, alignment: .center)
Divider()
VStack(alignment: .leading) {
Text("My controls")
Divider()
VStack(alignment: .leading) {
Slider(value: $sliderValue, in: 0...100)
Slider(value: $sliderValue, in: 0...100)
Slider(value: $sliderValue, in: 0...100)
Text("Hello")
Text("Some other text")
}
.disabled(false)
.padding(0)
.background(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.foregroundColor(
.clear
)
)
}
}
}
.accentColor(.black)
.padding()
}
}
Found the way to make it behave as expected, just had to add .fixedSize(horizontal: false, vertical: true)
I'm currently working on trying to implement a custom dropdown menu in SwiftUI that displays a grid of buttons (1-16) and allows you to select one of them. I am using an overlay to display the dropdown below the corresponding button, and it seems to be functioning properly except it's displaying the dropdown below all of the other elements in the view. I found another post here regarding this issue and they used a ZStack to solve it, but I haven't been able to get the same success. Does anyone have any ideas on how to fix this? Here's my code:
struct ContentView: View {
#State var showDropdown = false
#State var selected = 0
var body: some View {
ZStack {
HStack(spacing: 30) {
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
} else {
EmptyView()
}
}, alignment: .topLeading
)
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
}
}
.padding()
.frame(maxHeight: .infinity)
.buttonStyle(PlainButtonStyle())
}
}
and here are some images of the results:
Before Press
After Press
Thank you in advance!
The .zIndex works for view in same container, so you need something like the following (or make custom flat layout container with all such buttons at same level, then rise clicked button atop).
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
}
}, alignment: .topLeading
)
}.zIndex(showDropdown ? 1 : 0) // << this !!
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}.zIndex(showDropdown ? 1 : 0) // << and this !!
I am trying to place this information underneath my list. I don't want it to be included in the list but rather it should be displayed on the view background. Sort of like the old settings in iOS 6. I've tried placing my code snippets in different spots and removing stacks snd even changing what stacks I'm using and I cant figure it out. Heres my code and I attached a screenshot https://i.stack.imgur.com/PcUgJ.png for reference. Thank you to anyone who can help my noob self.
My Code:
import SwiftUI
struct SettingsAboutView: View {
var body: some View {
List{
//Top Section
Section {
HStack(spacing: 30) {
Spacer()
ZStack {
Rectangle()
.frame(width: 50, height: 50)
.clipShape(Rectangle())
.shadow(radius: 2)
.foregroundColor(Color("PineGlade"))
Image(systemName: "leaf.arrow.circlepath")
.resizable()
.frame(width: 25, height: 25)
.clipShape(Rectangle())
.foregroundColor(.white)
}.cornerRadius(10)
VStack(alignment: .leading) {
Text("Gardn")
.font(.system(size: 32))
.fontWeight(.bold)
.foregroundColor(Color("ShipsOfficer"))
Text("OnlyOdds.co Labs")
.font(.system(size: 13))
.fontWeight(.medium)
.foregroundColor(Color("ShipsOfficer"))
}
Spacer()
}.padding()
NavigationLink(destination: SettingsPrivacyView()) {
Button(action: {
print("Privacy Settings")
}) {
SettingsCell(title: "Privacy", imgName: "eye.slash", clr: Color("PineGlade"))
}
}
NavigationLink(destination: SettingsNotificationsView()) {
Button(action: {
print("Notification Settings")
}) {
SettingsCell(title: "Notifications", imgName: "bell", clr: Color("PineGlade"))
}
}
}
//Technical Info
HStack(spacing: 62) {
Spacer()
Text("V \(UIApplication.appVersion!)")
.font(.system(size: 14))
.fontWeight(.light)
.foregroundColor(Color("ShipsOfficer"))
.opacity(0.5)
Text("Build \(UIApplication.appBuild!)")
.font(.system(size: 14))
.fontWeight(.light)
.foregroundColor(Color("ShipsOfficer"))
.opacity(0.5)
Spacer()
}
}.listStyle(GroupedListStyle())
.environment(\.horizontalSizeClass, .regular)
.navigationBarTitle("Settings", displayMode: .inline)
}
}
struct SettingsAboutView_Previews: PreviewProvider {
static var previews: some View {
SettingsAboutView()
}
}
extension UIApplication {
static var appVersion: String? {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
}
}
extension UIApplication {
static var appBuild: String? {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
}
}
What you are looking for is a Footer. The Section View takes Footer as ViewBuilder as argument.
Section(footer: Text("Your footer text")) {
//Your Content here
}
You can pass Text() or create your own custom view.
Just put the List in a VStack and put
Text(yourtext)
Under the list