expected result
current result
I want to make it animation controllable
Open - text shows with animation
Close - text hide with animation
My code:
struct HomeView: View {
#State var isOpen = false
var body: some View {
ZStack {
Image("background")
.resizable()
VStack(alignment: .leading) {
Text("Appearing title text")
.frame(width: isOpen ? 200 : 0, height: 20, alignment: .leading)
.animation(.linear(duration: 2))
.font(.system(size: 20))
.foregroundColor(.white)
HStack {
Button("Open") {
isOpen = true
}
Button("Close") {
isOpen = false
}
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.padding(.top, 100)
}
.ignoresSafeArea()
}
}
Prompt me, please, how can I do it?
Related
I have something like that for the first time. The preview and the simulator do not look identical. I really have no idea how to fix it. Normally the simulator and the preview should be identical?
But it may be that I've nested something but I don't know what exactly.
The images and code are below:
Simulator
Preview Layout
var body: some View {
ZStack {
Image("bg-official")
.resizable()
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Text("NUMBER MATCH")
.fontWeight(.bold)
.font(.title)
GeometryReader { (geometry : GeometryProxy) in
ZStack {
RoundedRectangle(cornerRadius: 30)
.foregroundColor(Color("bg-roundedrectangle"))
.frame(width: 295, height: 310)
VStack(spacing: 3){
HStack(spacing: 3) {
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.black.opacity(0.7))
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.topLeft])
Text("60 Seconds")
.font(.title3)
.foregroundColor(.white)
}
}
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.black.opacity(0.7))
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.topRight])
Text("Endless")
.font(.title3)
.foregroundColor(.white)
}
}
}
HStack(spacing: 3) {
Spacer()
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.bottomLeft])
Text("Game Center")
.font(.title3)
.foregroundColor(.black)
}
}
Button {
withAnimation() {
sheetManager.present(with: .init(
systemName: "info",
title: "Game Info",
content: "The aim of this game is to match as many tiles as you can with the same number and earn points. Tap a tile to select it and tap another tile with matching number of the first tile you tapp ed. Be careful and quick; the game will end if you tap a wrong tile, if the timer runs out or if th board gets filled by tiles!"))
}
} label: {
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.bottomRight])
Text("Game Info")
.font(.title3)
.foregroundColor(.black.opacity(0.9))
}
}
Spacer()
}
}
}
}
.popup(with: sheetManager)
}
}
}}
In my application I want to get simple round buttons based on SF Symbols of the same size. However, the same approach results in different image sizes depending on the symbol.
For example, an image with a plus sign is larger than a minus sign.
To solve this problem, I use the ZStack trick in which I put a transparent plus under the minus. But I think this is not the best solution. Are there any better solutions?
HStack{
Image(systemName: "plus")
.padding()
.overlay(
Circle()
.stroke(Color.primary,
lineWidth:1))
Image(systemName: "minus")
.padding()
.overlay(
Circle()
.stroke(Color.primary,
lineWidth:1))
//my solution
ZStack {
Image(systemName: "plus")
.padding()
.opacity(0.0)
.overlay(
Circle()
.stroke(Color.primary,
lineWidth:1))
Image(systemName: "minus")
}
}
"minus" in the center has a smaller size than "plus", "minus" on the right - my solution:
You can use ViewModifier or if are buttons ButtonStyle
ViewModifier
#available(iOS 13.0, *)
struct fillButtonCircle: ViewModifier {
var foregroundColor: Color = .white
var backgroundColor: Color = .green
var dimension: CGFloat = 10
func body(content: Content) -> some View {
content
.foregroundColor(foregroundColor)
.padding(dimension)
.background(backgroundColor)
.clipShape(Circle())
.frame(width: dimension, height: dimension)
.overlay(
Circle()
.stroke(Color.primary,
lineWidth:1))
}
}
ButtonStyle
#available(iOS 13.0, *)
struct CircleScaleButton: ButtonStyle {
var color: Color = .blue
var maxHeight: CGFloat = 35
public func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: maxHeight, alignment: .center)
.foregroundColor(.black)
.background(RoundedRectangle(cornerRadius: 35/2.0).fill(self.color))
.compositingGroup()
.clipShape(Circle())
.overlay(
Circle()
.stroke(Color.primary,
lineWidth:1))
.opacity(configuration.isPressed ? 0.8 : 1.0)
.scaleEffect(configuration.isPressed ? 0.9 : 1.0)
}
}
Example
struct SwiftUIViewTest: View {
var body: some View {
VStack {
Text("Button")
HStack {
Button(action: {}, label: {
Image(systemName: "plus")
})
.buttonStyle(CircleScaleButton(color: .clear, maxHeight: 45))
Button(action: {}, label: {
Image(systemName: "minus")
})
.buttonStyle(CircleScaleButton(color: .clear, maxHeight: 45))
}
Spacer()
.frame(height: 50)
Text("Image")
HStack {
Image(systemName: "plus")
.modifier(fillButtonCircle(foregroundColor: .black, backgroundColor: .clear, dimension: 40))
Image(systemName: "minus")
.modifier(fillButtonCircle(foregroundColor: .black, backgroundColor: .clear, dimension: 40))
}
}
}
}
use .circle
import SwiftUI
struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "plus.circle")
.resizable()
.frame(width: 50, height: 50, alignment: .center)
Image(systemName: "minus.circle")
.resizable()
.frame(width: 50, height: 50, alignment: .center)
}
}
}
My app has a SwiftUI View that contains both a TextEditor to collect a log entry and a List containing past entries.
When the text editor has a non-empty string, a button is presented to process the entry, add it to the data populating the list, and reset the TextEditor. Presently the button appears suddenly whenever text is typed, and I would love to animate that more smoothly, perhaps by fading in the opacity or scaling up the button. However, I can't figure out where to enter that animation.
#State var newEntryString = ""
var body: some View {
NavigationView{
VStack{
Text("Create a new log entry.")
.padding()
TextEditor(text: $newEntryString)
.cornerRadius(3.0)
.padding()
.border(Color.gray, width: 1)
.frame(minWidth: 0, idealWidth: 100, maxWidth: .infinity, minHeight: 0, idealHeight: 100, maxHeight: 150, alignment: .center)
HStack {
Spacer()
if !newEntryString.isEmpty{
Button(action: {
addEntry()
}) {
Text("Add Entry")
}.buttonStyle(JournalButtonStyle())
.animation(Animation.default.speed(1))
}
}
Divider()
List {
ForEach(entrys) { item in
Text(item.timestamp!, formatter: entryFormatter).font(.footnote)
.foregroundColor(.gray)
.padding(.bottom, -10)
Text((item.entryString!))
}
.onDelete(perform: deleteEntrys)
}.onTapGesture {
UIApplication.shared.endEditing()
}
Use animation on container, like
HStack {
Spacer()
if !newEntryString.isEmpty{
Button(action: {
addEntry()
}) {
Text("Add Entry")
}.buttonStyle(JournalButtonStyle())
}
}.animation(Animation.default.speed(1)) // << here !!
I am new in SwiftUI and I am having an issue with my "hamburger" menu.
Basically I have created 2 views for the Home page: Home view and Home Side Menu view.
My main goal is to put the "hamburger" button at the top left of the view and open the side menu when it is clicked.
However when I use .edgesIgnoringSafeArea(.top) and put the "hamburger" button at the top left of the view, the button doesn't open the menu.
If, instead, I don't add .edgesIgnoringSafeArea(.top), the button is displayed in the middle of the view and works correctly opening the menu when it is clicked.
Could you please help me to see what I have done wrong.
Thanks in advance.
Home View:
import SwiftUI
struct HomeView: View {
var body: some View {
NavigationView{
ScrollView{
VStack(alignment: .center) {
Text("Home")
.font(.system(size: 22))
.fontWeight(.bold)
.foregroundColor(.white)
.padding(.top, 20)
.padding(.bottom, 20)
}
.frame(width: UIScreen.main.bounds.width, height: 80)
.background(Color.blue)
Image("image")
.resizable()
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.all)
}
.edgesIgnoringSafeArea(.top)
}
.navigationBarBackButtonHidden(true)
}
}
Home Side Menu view:
import SwiftUI
struct HomeSideMenuView : View {
#State var showMenu = false
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
withAnimation {
self.showMenu = false
}
}
}
return NavigationView {
GeometryReader { geometry in
ZStack(alignment: .leading) {
VStack {
HomeView()
.overlay(
Button (action:{
withAnimation {
self.showMenu = true
}
}){
Image(systemName: "line.horizontal.3")
.padding()
.imageScale(.large)
.font(Font.system(size: 20, weight: .bold))
}
.padding()
.foregroundColor(.white)
.shadow(color: Color.gray, radius: 0.2, x: 1, y: 1)
.frame(maxWidth: geometry.size.width, maxHeight: geometry.size.height, alignment: .topLeading)
.edgesIgnoringSafeArea(.top) // -> if I add this line, the button doesn't work
)
}
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: self.showMenu ? geometry.size.width/1.5 : 0)
.disabled(self.showMenu ? true : false)
if self.showMenu {
MenuView()
.frame(width: geometry.size.width/1.5, height: geometry.size.height)
.transition(.move(edge: .leading))
}
}
.gesture(drag)
}
}
.navigationBarBackButtonHidden(true)
}
}
i am having the same issue, i guess the first top 100px are reserved to the navigationBar, just add
.navigationBarTitle("")
.navigationBarHidden(true)
to your views containers (first child of NavigationView).
Hope this helps
I am new to SwiftUI and I would some assistance with regards positioning of a Custom Button which I am unable to to centre.
I have used VStack and HStack to try and get the button bottom centered, but button keeps aligning left.
Any assistance will be appreciated.
struct ContentView: View {
var body: some View {
VStack {
NavigationView {
Section {
VStack(alignment: .leading) {
Text("Meal Description").foregroundColor(.green)
Spacer()
NavigationLink(destination: PoundedYam()) {
Text("Pounded Yam & Egusi Soup")
}
NavigationLink(destination: YamPepSoup()) {
Text("Yam and Pepper Soup")
}
NavigationLink(destination: JollofRice()) {
Text("Jollof Rice & Plantain")
}
Spacer()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
}.padding()
}
Section {
Image("africanfoods")
.resizable()
.frame(width: 275.0, height: 250.0)
.clipShape(Circle())
.overlay(Circle().stroke(Color.black, lineWidth: 5))
.scaledToFit()
}
VStack { //For Button
Spacer()
Button( action: {},
label: { Text("Create Order") })
}
.navigationBarTitle(Text("Menu"))
} //NavView End
} //VStack End
}
}
You can add .frame(maxWidth: .infinity) to the Button. This will also increase teachability.
Button("Create Order") { }
.frame(maxWidth: .infinity)
May be not most elegant solution but it works:
HStack() {
Spacer()
Button( action: {},
label: { Text("Create Order") })
Spacer()
}
First fast idea: set your button in HStack between Spacers:
// ...
VStack { //For Button
Spacer()
HStack {
Spacer()
Button( action: {}, label: { Text("Create Order") })
Spacer()
}
}
.navigationBarTitle(Text("Menu"))
// ...
and the result is: