SwiftUI how do I perfectly align on of my object in my HStack in the center of my screen? - alignment

I am trying to figure out how to align my "Create" Button in the exact middle of my screen with my "share" button to the right of my centered "Create" Button, without using arbitrary numbers.
HStack (spacing: 40) {
Text("Create")
.fontWeight(.bold)
.frame(width: 185, height: 40, alignment: .center)
.cornerRadius(50)
.overlay(
Capsule(style: .circular)
.stroke(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1), style: StrokeStyle(lineWidth: 2)))
Image(systemName:"square.and.arrow.up")
.resizable()
.frame(width: 25, height: 30)
.font(Font.title.weight(.light))
} .foregroundColor(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1))

Here is how I would do it (no hardcoded numbers)
HStack {
Spacer()
Text("Create")
.fontWeight(.bold)
.frame(width: 185, height: 40, alignment: .center)
.cornerRadius(50)
.overlay(
Capsule(style: .circular)
.stroke(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1), style: StrokeStyle(lineWidth: 2)))
Spacer()
.overlay(
HStack {
Image(systemName:"square.and.arrow.up")
.resizable()
.frame(width: 25, height: 30)
.font(Font.title.weight(.light))
Spacer()
}
.padding(.leading) // << here can be any distance to center button
)
}
.foregroundColor(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1))

There's probably a better way, but this will do it. It just adds the action button as an overlay to the main Create button. But by using a PreferenceKey, the action button knows the size (and origin) of the Create button and can offset itself accordingly. Using rectangles here to represent the buttons so it's easier to read.
struct BoundsPreferenceKey: PreferenceKey {
typealias Value = CGRect
static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
value = value.union(nextValue())
}
}
struct CenteredView: View {
let spacing: CGFloat = 40
var body: some View {
HStack {
Rectangle().fill(Color.blue)
.frame(width: 185, height: 40)
.preference(key: BoundsPreferenceKey.self, value: CGRect(origin: .zero, size: CGSize(width: 185, height: 40)))
.overlayPreferenceValue(BoundsPreferenceKey.self) { rect in
Rectangle().fill(Color.green)
.frame(width: 25, height: 30)
.offset(x: rect.size.width/2 + self.spacing, y: 0)
}
}
}
}
You could use GeometryReader to avoid specifying the height and width, but you need to specify it for the frame anyway.
Alternatively, look at a custom alignment guide.

It could be like this:
HStack{
Spacer()
Spacer().overlay(Button("Create"){}.padding(10).border(Color.blue, width: 3.0))
Spacer()
}

Related

Confusion with passing data to another view. SwiftUI

I'm building this project, and I have two views: MenuView and CreateBoardView.
What I want to achieve is to be able to create a new board on the menu screen, and so that the data I'd enter (board name and description) would be shown in the new created box. But I'm really confused about how to make it.
Here's the code for my MenuView:
import Foundation
import SwiftUI
struct MenuView: View {
#EnvironmentObject var AboutBoard: BoardModel
var body: some View {
ZStack {
VStack {
HStack(spacing: 80) {
VStack(alignment: .leading, spacing: 10) {
Text("Hey,")
.font(Font.custom("Montserrat", size: 25))
Text("username")
.font(Font.custom("Montserrat-Bold", size: 30))
}
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 100, height: 100, alignment: .trailing)
}
.padding(.top, 30)
HStack(alignment: .top, spacing: 30) {
VStack(alignment: .leading) {
Text("New board")
.font(Font.custom("Montserrat-Bold", size: 25))
.foregroundColor(.white)
Text("Create with your friends")
.font(Font.custom("Montserrat", size: 18))
.foregroundColor(.white)
.padding(.bottom, 10)
NavigationLink(destination: CreateBoardView()) {
Text("Create board")
}.padding(15)
.frame(width: 180, height: 50, alignment:.center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.58, green: 0.12, blue: 0.68)), (Color.init(red: 0.58, green: 0.12, blue: 0.68))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 20))
.foregroundColor(.white)
.scaledToFill()
.font(Font.custom("Montserrat-Bold", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 5, x: 0, y: 7)
.navigationBarBackButtonHidden(true)
.navigationBarTitleDisplayMode(.inline)
}
Image("Forum")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
}
.frame(width: 350, height: 180, alignment: .center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.88, green: 0.33, blue: 1.00)), (Color.init(red: 0.69, green: 0.05, blue: 1.00))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 30))
HStack(spacing: 150) {
Text("Your boards")
.font(Font.custom("Montserrat-Bold", size: 20))
Text("See all")
.font(Font.custom("Montserrat", size: 15))
}.padding(.top, 20)
HStack(spacing: 30) {
ForEach(0..<10) {_ in
Text(AboutBoard.BoardName)
.font(Font.custom("Montserrat", size: 20))
Text(AboutBoard.BoardDescription)
.font(Font.custom("Montserrat", size: 20))
}
.frame(width: 250, height: 210)
.background(
Image("Board-Holder")
.resizable()
.scaledToFit()
.frame(width: 250, height: 210)
)
}
Spacer()
}
}
.environmentObject(BoardModel())
}
}
struct MenuPagePreview: PreviewProvider {
static var previews: some View {
MenuView()
}
}
And my CreateBoardView:
import Foundation
import SwiftUI
struct CreateBoardView: View {
#StateObject var BoardInfo = BoardModel()
#State private var SetDeadline = false
#State private var ShowMenu = false
var body: some View {
ZStack {
VStack {
Text("Create a new board")
.font(Font.custom("Montserrat-Medium", size: 30))
.padding(.bottom, 50)
.padding(.top, 50)
Text("Enter your board's name")
.font(Font.custom("Montserrat", size: 20))
.padding(.bottom, 30)
TextField("Board name", text: $BoardInfo.BoardName)
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(RoundedRectangle(cornerRadius: 20).fill(.white))
.scaledToFill()
.font(Font.custom("Montserrat", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.disableAutocorrection(true)
Text("Add board description")
.font(Font.custom("Montserrat", size: 20))
.padding(.bottom, 30)
TextField("Board description", text: $BoardInfo.BoardDescription)
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(RoundedRectangle(cornerRadius: 20).fill(.white))
.scaledToFill()
.font(Font.custom("Montserrat", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.disableAutocorrection(true)
NavigationLink(destination: MenuView()) {
Text("Create board")
}
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.72, green: 0.26, blue: 0.67)), (Color.init(red: 0.47, green: 0.16, blue: 0.74))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 20))
.foregroundColor(.white)
.scaledToFill()
.font(Font.custom("Montserrat-Bold", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.sheet(isPresented: $ShowMenu){
MenuView()
}
}
}
}
}
struct CreateBoardPreview: PreviewProvider {
static var previews: some View {
CreateBoardView()
}
}
I also have this BoardModel but I don't know if I'm even doing it right.
import Foundation
import SwiftUI
class BoardModel: ObservableObject {
static let shared = BoardModel()
#Published var BoardName: String = ""
#Published var BoardDescription: String = ""
}
So how to make it such way so that the CreateBoardView would take the input and then have it stored and shown in the menu?
Thanks.

How to place Image(plus) to top right of custom frame in swiftui?

I am trying to put a plus sign in a tight frame at a very specific spot (at the right of the title text) but i cannot seem to do so
Do you know how I can do so?
var body: some View {
VStack {
HStack {
Image(systemName: "plus")
VStack(alignment: .leading, spacing: 15) {
Text("This Month's Goal")
.bold()
.frame(width: 300, height: 10, alignment: .center)
Text("100 out of 2000")
.frame(width: 300, height: 10, alignment: .center)
//replace percent with percent and code percent to move with data
ProgressBarView(width: 300, height: 30, percent: 50, color1: Color(#colorLiteral(red: 0.01413772535, green: 0.2225477993, blue: 0.9861308932, alpha: 1)), color2: Color(#colorLiteral(red: 0.5605781674, green: 0.9172690511, blue: 0.8047055602, alpha: 1)))
}
Spacer()
}
.padding()
}
.background(Color.white)
.frame(width: 350, height: 120, alignment: .center)
.cornerRadius(25.0)
}
This is what it looks like right now, Somewhere in the circled spot in the same frame would be ideal.
struct TestView: View {
var body: some View {
VStack {
HStack {
Image(systemName: "plus")
VStack(alignment: .leading, spacing: 15) {
ZStack(alignment: .trailing) {
VStack {
Text("This Month's Goal")
.bold()
.frame(width: 300, height: 10, alignment: .center)
Text("100 out of 2000")
.frame(width: 300, height: 10, alignment: .center)
}
Button(
action: { },
label: { Image(systemName: "plus.circle") }
)
}
//replace percent with percent and code percent to move with data
ProgressBarView(width: 300, height: 30, percent: 50, color1: Color(#colorLiteral(red: 0.01413772535, green: 0.2225477993, blue: 0.9861308932, alpha: 1)), color2: Color(#colorLiteral(red: 0.5605781674, green: 0.9172690511, blue: 0.8047055602, alpha: 1)))
}
Spacer()
}
.padding()
}
.background(Color.white)
.frame(width: 350, height: 120, alignment: .center)
.cornerRadius(25.0)
}
}
Result:
Incidentally, your progress bar might look better if you calculate the width of the completion bar (the blue-green overlay) as height + (width - height) * percent / 100 instead of as width * percent / 100.

NavigationBar thick / swiftui

I created the Navigation View, but when you jump to the page, the navigation bar is very thick, although nothing happens.
I want the stick to be thinner. I do not know how to do it. I could not find the examples, I could not do it myself. Can you do it.
HStack(spacing: 10) {
NavigationLink(destination: PicturePage()){
Text("Kahve Falı")
.font(.title)
.foregroundColor(Color(#colorLiteral(red: 0.7239437103, green: 0.2440972626, blue: 0.4727140069, alpha: 1)))
.frame(maxWidth: geometry.size.width)
.frame(height: geometry.size.height / 5)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(#colorLiteral(red: 0.8527825475, green:
0.821311295, blue: 0.8959596753, alpha: 1)), lineWidth: 3)
)
}.navigationBarTitle(Text("Geri"))
.navigationBarHidden(true)
}
Navigation page
struct PicturePage: View {
//3-1//
var body: some View {
GeometryReader { geometry in
Color.black.edgesIgnoringSafeArea(.all)
VStack {
VStack {
Text("Picture")
.font(.system(size: 60))
.frame(height: geometry.size.height / 10)
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
Spacer().frame(height: geometry.size.height / 15)
}
VStack {
Text("Merhaba").frame(width: geometry.size.width, height: geometry.size.height / 10)
.foregroundColor(Color.white)
}
VStack {
Image("AstroGirl").resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width, height: geometry.size.height / 3)
Spacer().frame(height: geometry.size.height / 15)
}
// This `HStack` is changed
HStack(spacing: 30) {
ForEach(0 ..< 3) { _ in
CircleView()
.frame(width: geometry.size.width / 5, height: geometry.size.height / 10)
.shadow(color: Color.yellow, radius: 10, x: 0, y: 0)
}
}
Spacer().frame(height: geometry.size.height / 10)
VStack {
Button(action: {}, label: {
Text("Gönder")
.frame(width: geometry.size.width / 3, height: 50)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 30))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
}
}
}
}
Look for property displayMode and set that to .inline
Here is a good overview of the options available and usage:
https://www.hackingwithswift.com/articles/216/complete-guide-to-navigationview-in-swiftui
More info on your follow up question...
You can extend the UINavigationController and make the background transparent for all your views. Add the below to a new swift file in your project.
extension UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
navigationBar.standardAppearance = appearance
navigationBar.compactAppearance = appearance
navigationBar.scrollEdgeAppearance = appearance
navigationBar.prefersLargeTitles = false // use inline titles on very view
// navigationBar.isHidden = true // hide the nav bar completely on every view
}
}

TextEditor added / SwiftUi

I could not adjust the appearance of the Text Editor I created.text will have margins.
I tried to do it myself but I messed it up, I couldn't.I want it to be like the picture.
VStack {
TextEditor(text: $inputText)
.background(Color.black)
.frame(height:geometry.size.height / 3, alignment: .center)
.cornerRadius(25)
.border(Color.yellow, width: 5)
.lineSpacing(10)
.autocapitalization(.words)
.disableAutocorrection(true)
.padding()
}
Spacer().frame(height: geometry.size.height / 15)
VStack {
Button(action: {}, label: {
Text("Gönder")
.frame(width: geometry.size.width / 3, height: 50)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 30))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
First , for changing TextEditor background color
I could not find a SwiftUI 100% solution for that (maybe apple will support this in future ) , so you need to change every UITextView.appearance().backgroundColor in the app
init() {
UITextView.appearance().backgroundColor = UIColor.black
}
don't miss import UIKit
Then for corner radius , you need to use overlay modifier for a rounded corners
VStack {
TextEditor(text: $inputText)
.frame(height:geometry.size.height / 3, alignment: .center)
.lineSpacing(10)
.autocapitalization(.words)
.disableAutocorrection(true)
.padding()
}.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.yellow, lineWidth: 5)
)
.padding()

Button overlay is showing over Button Text, SwiftUI

My Button requires a couple overlays to get the style it needs (stroke, shadow etc).
However these overlays then go over the Button text.
View:
struct ProfileTest: View {
var body: some View {
Button(action: {
}){
HStack {
Text("OFFLINE")
.font(.custom("Seravek-Bold", size: 25))
.fontWeight(.bold)
.foregroundColor(Color.blue)
}
}.padding(EdgeInsets(top: 12, leading: 15, bottom: 12, trailing: 15))
.cornerRadius(50)
.overlay(
RoundedRectangle(cornerRadius: 50)
.stroke(Color.black, lineWidth: 1)
)
.overlay(
RoundedRectangle(cornerRadius: 50)
.fill(Color.red)
.shadow(color: Color.black.opacity(1), radius: 1)
)
.opacity(0.7)
.padding(.bottom, 100)
.padding(.bottom, 20)
}
}
How can I adjust my view so that the blue text shows above the background?
You can use a custom ButtonStyle.
Create your own shape and add .overlay(configuration.label) on top of it:
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.hidden()
.padding(EdgeInsets(top: 12, leading: 15, bottom: 12, trailing: 15))
.cornerRadius(50)
.overlay(
RoundedRectangle(cornerRadius: 50)
.stroke(Color.black, lineWidth: 1)
)
.overlay(
RoundedRectangle(cornerRadius: 50)
.fill(Color.red)
.shadow(color: Color.black.opacity(1), radius: 1)
)
.opacity(0.7)
.overlay(configuration.label)
.padding(.bottom, 100)
.padding(.bottom, 20)
}
}
You can also use configuration.isPressed to customise your label behaviour on button press.
Apply it to your Button:
struct ContentView: View {
var body: some View {
Button(action: {}) {
HStack {
Text("OFFLINE")
.font(.custom("Seravek-Bold", size: 25))
.fontWeight(.bold)
.foregroundColor(Color.blue)
}
}
.buttonStyle(CustomButtonStyle())
}
}

Resources