I am trying to make a list of buttons/links that all have the same width, regardless of text content. Unfortunately, it seems like the Link() items do not respect the .frame(maxWidth) settings and just do whatever they want. I cannot find any resources online that describe how to do this, so I am turning here to see if anyone can help me determine the best way to line these up to be the same width.
My code below:
VStack(alignment: .center) {
Button {
bypass.toggle()
} label: {
Text("Push to Bypass")
.frame(maxWidth: .infinity)
}
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(Color(hue: 1.0, saturation: 1.0, brightness: 1.0, opacity: 0.825))
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
Link("Settings", destination: URL(string: "http://192.168.10.1/TSettings")!)
.frame(maxWidth: .infinity)
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(.white)
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
Link("Recorder Settings", destination: URL(string: "http://192.168.10.1/VB")!)
.frame(maxWidth: .infinity)
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(.white)
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
Link("Download Data", destination: URL(string: "http://192.168.10.1/ddownload")!)
.frame(maxWidth: .infinity)
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(.white)
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
Link("Download Audio", destination: URL(string: "http://192.168.10.1/generate")!)
.frame(maxWidth: .infinity)
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(.white)
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
}.fixedSize(horizontal: true, vertical: false)
What it currently looks like:
Add this to your struct:
#Environment(\.openURL) var openURL
Use a regular button and apply the desired modifiers:
Button {
openURL(URL(string: "http://192.168.10.1/TSettings")!)
} label: {
Text("Settings")
.frame(maxWidth: .infinity)
}
Get rid of .fixedSize(horizontal: true, vertical: false) at the end and use Link with label: init:
Link(destination: URL(string: "http://192.168.10.1/TSettings")!) {
Text("Settings")
.frame(maxWidth: .infinity)
}
.font(.title2)
.fontWeight(.bold)
.buttonStyle(.borderedProminent)
.foregroundColor(.white)
.tint(Color(red: 0.005, green: 0.669, blue: 0.791))
Related
How can I make sure that my UI looks good on different devices such as the iPhone 13 and the iPhone 8?
Here is my code that is unresponsive
It is just a simple layout
import SwiftUI
let grey = Color(red: 0.928, green: 0.928, blue: 0.928)
let i = 0
var columns: [GridItem] =
Array(repeating: .init(.flexible()), count: 3)
let categories: [Category] = [
.init(name: "Pasta", imageName: "square.and.arrow.up"),
.init(name: "Asian", imageName: "square.and.arrow.down.fill"),
.init(name: "Main", imageName: "rectangle.portrait.and.arrow.right"),
.init(name: "Quick", imageName: "pencil.slash"),
.init(name: "Veg", imageName: "scribble.variable"),
.init(name: "Dessert", imageName: "pencil.circle.fill"),
]
struct SearchView: View {
var body: some View {
VStack{
Text("Search For Recipes")
.font(.system(size: 35))
.padding(.top, 80)
.padding(.horizontal, -70)
.frame(width: 200, height: 10, alignment: .leading)
Spacer()
SearchBox()
.padding(.top, 50)
Spacer()
Recomend()
.padding(.top)
.padding(.leading, -100)
Spacer()
LazyVGrid(columns: columns){
ForEach((0...5), id: \.self) { _ in
MenuChoice()
}
}
.padding(20)
.padding(.bottom, 100)
.padding(.top)
.frame(maxWidth: .infinity)
.frame(height:500)
}
}
}
struct SearchBox: View {
var body: some View{
VStack{
HStack{
Image(systemName: "magnifyingglass")
Text("Search for recipes")
}
.frame(width: 200, height: 10, alignment: .leading)
.padding(.trailing, 60)
}
.frame(width: 300, height: 50)
.background(grey)
.cornerRadius(8)
.padding(.trailing, 50)
}
}
struct MenuChoice: View{
var body: some View{
ZStack{
ForEach(categories, id: \.self) { category in
VStack{
Spacer()
.frame(width: 100, height: 100)
.background(Color(red: 50, green: 207, blue: 255))
.cornerRadius(5)
.shadow(color: .init(.sRGB, white: 0.7, opacity: 1), radius: 4, x: 0.0, y: 2)
.padding(.bottom)
.overlay(
VStack(spacing: 8) {
Image(systemName: category.imageName)
.padding(.top, -10)
.font(.system(size: 30))
Text(category.name)
.foregroundColor(.black)
.font(.system(size: 20))
.padding(.top, 5)
}
)
}
}
}
}
}
struct Recomend: View{
var body: some View{
Button {
print("Image tapped!")
} label: {
ZStack{
RoundedRectangle(cornerRadius: 8)
.frame(width: 250, height: 50)
.foregroundColor(grey)
Text("See All Recomended Recipes")
.foregroundColor(Color.black)
}
}
}
}
struct SearchView_Previews: PreviewProvider {
static var previews: some View {
SearchView()
.previewDevice(PreviewDevice(rawValue: "iPhone 13"))
SearchView()
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
}
}
On the iPhone 13 it looks good but on the iPhone 8 it looks squashed and not good.
How can i make my code responsive for different screen heights/widths?
Following the comments you could go in this direction:
This adapts nicely and also is a lot less code.
struct ContentView: View {
var body: some View {
VStack{
Text("Search For Recipes")
.font(.system(size: 35))
.frame(maxWidth: .infinity, alignment: .leading)
SearchBox()
.padding(.bottom)
.padding(.bottom)
Recomend()
Spacer()
LazyVGrid(columns: columns, spacing: 18){
ForEach(categories) { category in
MenuChoice(category: category)
}
}
Spacer()
}
.padding()
}
}
struct SearchBox: View {
var body: some View{
VStack {
HStack{
Image(systemName: "magnifyingglass")
Text("Search for recipes")
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(grey)
.cornerRadius(8)
}
}
struct MenuChoice: View{
let category: Category
var body: some View{
VStack(spacing: 8) {
Image(systemName: category.imageName)
.padding(.top)
.font(.system(size: 30))
Text(category.name)
.foregroundColor(.black)
.font(.system(size: 20))
.padding(.bottom)
}
.frame(width: 100, height: 100)
.background(Color(red: 50, green: 207, blue: 255))
.cornerRadius(5)
.shadow(color: .init(.sRGB, white: 0.7, opacity: 1), radius: 4, x: 0.0, y: 2)
}
}
struct Recomend: View{
var body: some View{
Button {
print("Image tapped!")
} label: {
Text("See All Recomended Recipes")
.padding()
.foregroundColor(Color.black)
.frame(maxWidth: .infinity, alignment: .leading)
.background(grey)
.cornerRadius(8)
}
}
}
Good afternoon community,
I have a problem with my app, I am trying to make it look good in both situations, so when I change orientation my app returns to the main screen, it does not stay on the second screen, will someone have a solution to this problem?
I don't know if my view breaks or cannot cover the space that I have determined, I leave my code below.
import SwiftUI
struct LoginView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
init() {
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().tintColor = .clear
UINavigationBar.appearance().backgroundColor = .clear
}
var backButton : some View {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image("Backarrow")
.aspectRatio(contentMode: .fit)
.foregroundColor(.white)
Text(" Back")
.foregroundColor(.yellow)
}
}
}
var topImage:some View{
Image("header2")
.resizable()
.overlay( ImageOverlay() , alignment: .center)
.background(Color.black)
}
var usernameTextField:some View{
HStack{
TextField("", text: $LoginViewM.username)
.placeholder(Text("Numero de telefono,email o usuario").padding().foregroundColor(.white), show: LoginViewM.password.isEmpty)
.background(Color.black)
Image("menuCloseSmall")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.lineLimit(1)
.foregroundColor(.white)
.minimumScaleFactor(0.5)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
}
var errorUsernameLabel:some View{
VStack{
Text(" Hey you, no user found. Make sure you’ve provided the ")
.lineLimit(1)
Text("correct information.")
}
.multilineTextAlignment(.leading)
.foregroundColor(.redBlueParrot)
.minimumScaleFactor(0.5)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var passwordTextField:some View{
HStack{
TextField("Contraseña", text: $LoginViewM.password)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.padding(.bottom)
.foregroundColor(.white)
.placeholder(Text("Contraseña").padding().foregroundColor(.white), show: LoginViewM.username.isEmpty)
.lineLimit(1)
.minimumScaleFactor(0.5)
.background(Color.black)
Image("editShow")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
}
var errorPasswordLabel:some View{
VStack{
Text(" Incorrect password for \(LoginViewM.password). Please try again.")
}
.lineLimit(1)
.minimumScaleFactor(0.5)
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var buttonLogin:some View{
NavigationLink(
destination: Text("Hola"),
label: {
Text("Iniciar sesion")
}) .font(.custom("Montserrat-Medium", size: 16))
.foregroundColor(Color.ligthGray)
.frame(minWidth: 0, idealWidth: 174, maxWidth: 174, minHeight: 0, idealHeight: 48, maxHeight: 48, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.gray, lineWidth: 1.5))
}
var textInBottom:some View{
HStack(spacing:5){
Text("Olvidaste tu")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("contraseña"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
Text("o")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("usuario"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
}
}
#ObservedObject var LoginViewM = LoginViewModel()
var body: some View {
GeometryReader{ geometry in
NavigationView{
VStack(spacing:2){
topImage
.frame(width: geometry.size.width, height: geometry.size.height * 0.39)
VStack(spacing:17){
usernameTextField
.frame(width: geometry.size.width*0.90, height: geometry.size.height*0.05)
errorUsernameLabel
.frame(width: geometry.size.width*0.90,height: geometry.size.height*0.06, alignment: .center)
passwordTextField
.frame(width: geometry.size.width*0.90, height: geometry.size.height*0.05)
errorPasswordLabel
.frame(height: geometry.size.height*0.06, alignment: .center)
}.frame( height: geometry.size.height * 0.40)
VStack{
buttonLogin
}.frame(height: geometry.size.height * 0.10, alignment: .center)
Spacer()
textInBottom
.frame(height: geometry.size.height * 0.05, alignment: .center)
Spacer()
}
.ignoresSafeArea(.all)
.background(Color.black)
}
.navigationBarItems(leading: backButton)
.navigationBarBackButtonHidden(true)
.background(Color.black)
.navigationViewStyle(StackNavigationViewStyle())
}
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
}
}
I am trying to create a medium Widget like in YouTube Music, but I am don't understand how to create an interaction with the particular item in a Widget. How my app should understand when user press on first or second item and then how I am must handle this action inside app. My app use Swift not SwiftUI, only for a Widget I use SwiftUI. In past I didn't have experience with a SwityUI.
My code for Widget:
struct WidgetTestEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
HStack(spacing: 100){
Text("Favourite").foregroundColor(.white).font(.system(size: 16, weight: .bold, design: .default))
Image("Label").resizable().frame(width: 80, height: 15, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
}.frame(maxWidth: .infinity, maxHeight: 50, alignment: .center).background(Color.black).offset(y: -9)
HStack {
Spacer()
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Spacer().frame(width: 10, height: 10, alignment: .center)
}.background(Color(red: 0.118, green: 0.118, blue: 0.15)).offset(y: -9)
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center).background(Color(red: 0.118, green: 0.118, blue: 0.15))
}
}
You can do this using Link in SwiftUI.
Link(destination: url, label: {
// add your UI components in this block on which you want to perform click action.
}
url: Provide a unique string to identify widget action in the main app.
Now In the main app, use below method in AppDelegate.swift file:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
}
In this method, you can identify the URL that comes from the WidgetKit action.
I'm trying to get the last styling done on my Widget but I just can't seem to get the number "+1.75" and the Orange dot to align with the "Wheat" text. How do I properly align this row?
I've tried using Spacer() but it just doesn't seem to work?
struct CropPriceView: View {
#Environment(\.widgetFamily) var family: WidgetFamily
var body: some View {
if family == .systemSmall{
VStack{
HStack{
VStack{
HStack{
Circle()
.fill(Color(#colorLiteral(red: 0.9333333333, green: 0.6784313725, blue: 0.262745098, alpha: 1)))
.frame(width: 10, height: 10)
VStack(alignment: .leading){
Text("Wheat")
.foregroundColor(Color(#colorLiteral(red: 0.168627451, green: 0.1647058824, blue: 0.1647058824, alpha: 1)))
.font(Font.custom("TPFrank-Bold", size: 14))
.lineSpacing(0.18)
Text("MATIF")
.font(Font.custom("TPFrank-Regular", size: 12))
.foregroundColor(Color(#colorLiteral(red: 0.5921568627, green: 0.5921568627, blue: 0.5921568627, alpha: 1)))
.lineSpacing(0.15)
}
Spacer()
}
}
Spacer()
Text("+1.75")
.foregroundColor(Color(#colorLiteral(red: 0.4431372549, green: 0.7490196078, blue: 0.3882352941, alpha: 1)))
.font(Font.custom("TPFrank-Medium", size: 14))
.lineSpacing(0.35)
}
Spacer()
HStack{
Spacer()
Text("168.02")
.foregroundColor(Color(#colorLiteral(red: 0.168627451, green: 0.1647058824, blue: 0.1647058824, alpha: 1)))
.font(Font.custom("TPFrank-Bold", size: 22))
.lineSpacing(0.55)
}
}.padding(EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15))
}
}
}
Hopefully this helps, let me know if it works for you. I believe you were looking for .firstTextBaseline to align with the first Text.
struct Example_WidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
HStack(alignment: .firstTextBaseline) {
Image(systemName: "circle.fill")
.resizable()
.frame(width: 10, height:10)
.foregroundColor(Color.orange)
VStack (alignment: .leading){
Text("Wheat")
.font(.subheadline)
.fontWeight(.bold)
.allowsTightening(true)
Text("MATIF")
.font(.footnote)
.fontWeight(.bold)
.foregroundColor(Color.secondary)
.allowsTightening(true)
}
Spacer()
Text("+1.75")
.font(.footnote)
.fontWeight(.bold)
.foregroundColor(Color.green)
.allowsTightening(true)
}
Spacer()
HStack {
Spacer()
Text("168.02")
.font(.title)
.fontWeight(.bold)
}
}
.padding(.all, 10)
}
}
Set HStack alignment: .top
var body: some View {
if family == .systemSmall{
VStack{
HStack(alignment: .top) { //<<--Here
VStack{
HStack(alignment: .top) { //<<--Here
I'm trying to align text in two different HStacks but having difficulties getting the second (shorter length) one to align with the first HStack. I've tried using .frame(minWidth:0, maxWidth: .infinity) and Spacer()'s but can't find a solution. Is this possible at all?
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
HStack {
Spacer()
Text("Lorem ipsum dolor")
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
Spacer()
}.padding()
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
HStack {
Spacer()
Text("Lorem ipsum")
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
Spacer()
}.padding()
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
}
}
}
I attempted to use a HorizontalAlignment guide, but they became off-centred:
struct ContentView: View {
var body: some View {
VStack(alignment: .controlLeadingEdge) {
HStack {
Text("Lorem ipsum dolor")
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
.alignmentGuide(.controlLeadingEdge, computeValue: { d in d[HorizontalAlignment.leading] })
}.padding()
.frame(minWidth: 0, maxWidth: 300)
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
HStack {
Text("Lorem ipsum")
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
.alignmentGuide(.controlLeadingEdge, computeValue: { d in d[HorizontalAlignment.leading] })
}.padding()
.frame(minWidth: 0, maxWidth: 300)
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
}
}
}
extension HorizontalAlignment {
private enum ControlAlignment: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
return context[HorizontalAlignment.controlLeadingEdge]
}
}
static let controlLeadingEdge = HorizontalAlignment(ControlAlignment.self)
}
Here is one way to do it:
Repeat the first text, give it .opacity(0) and put it in a ZStack with .leading alignment
struct ContentView: View {
var body: some View {
let firstText = Text("Loren ipsum dolor")
let secondText = Text("Loren ipsum")
VStack(alignment: .leading) {
HStack {
Spacer()
firstText
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
Spacer()
}.padding()
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
HStack {
Spacer()
ZStack(alignment: .leading) {
firstText.opacity(0)
secondText
}
.font(.system(size: 22, weight: .ultraLight, design: .rounded))
Spacer()
}.padding()
.overlay(
Rectangle()
.stroke(Color(#colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)), style: StrokeStyle(lineWidth: 0.5, dash: [5.0])))
}
}
}