Can't display custom pop-up because my tab view is in NavigationView - swift

I want to display a pop-up in my view, where I will be able to display a menu where I can choose how I fell, then it will show what I have chosen and close itself. If I am adding it to the view and it's presenting It shows wrong and Tab Bar does not disappear. Can someone provide a better way to show a pop-up over Tab Bar? The logic is something like this: button pressed -> shows pop-up -> choose status -> shows another pop-up -> disappears.
Code's provided below:
// Smile face that used in question
struct SmileFace: View {
var text: String
var image: String
#Binding var current: String
var body: some View {
Button {
withAnimation {
current = text
}
} label: {
VStack {
Image(image)
.resizable()
.scaledToFill()
.frame(width: 46, height: 46)
Text(text)
.foregroundColor(.white)
}
}
}
}
// Check in answer view
import SwiftUI
struct CheckInAskView: View {
let didClose: () -> Void
var didChose: Bool = false
#State var current: String
var emotions = [
"GREAT" : "good",
"GOOD" : "happy",
"OK" : "moderate",
"BAD" : "sad",
"TERRIBLE" : "verysad"
]
var body: some View {
VStack {
ZStack(alignment: .topLeading) {
Rectangle()
.fill(Color("navigation"))
.cornerRadius(15)
.frame(height: 601)
HStack(alignment: .top) {
ZStack(alignment: .top) {
Circle()
.fill(Color(red: 0.682, green: 0.384, blue: 0.486).opacity(0.10))
.frame(width: 173)
.offset(x: -173/2, y: -90/2)
.clipped()
}
Spacer()
Button {
didClose()
} label: {
ZStack {
Circle()
.fill(Color(red: 0.933, green: 0.933, blue: 0.933).opacity(0.30))
.frame(width: 24)
.clipped()
Image(systemName: "xmark")
.font(.system(size: 15))
.foregroundColor(Color(red: 0.762, green: 0.762, blue: 0.762))
}
.padding(10)
}
}
VStack(alignment: .center) {
Spacer()
Text("How do you feel now?")
.foregroundColor(.white)
.font(.custom("Manrope-Bold", size: 16))
HStack(spacing: 35) {
SmileFace(text: "GOOD", image: "good", current: $current)
}
.padding(.horizontal)
DoubleTextView(topText: "Recommendation for you", buttomText: "We have selected courses based on your goals and \nexperience", topTextSize: 16, buttomTextSize: 14)
BigFrameScrollViewHorizontal()
Spacer()
}
}
.frame(height: 601)
}
.frame(height: 601)
.transition(.move(edge: .bottom))
}
}
// View with all views
struct CheckInView: View {
#StateObject var sheetManager: SheetManager
var body: some View {
VStack {
HStack {
Text("How do you fell now?")
.foregroundColor(.white)
.font(.custom("Manrope-Bold", size: 16))
Spacer()
Button {
} label: {
ZStack {
HStack {
Text("Pass check in")
.padding([.top, .leading, .bottom])
.foregroundColor(.white)
.font(.custom("Manrope-Medium", size: 12))
Image(systemName: "chevron.right")
.foregroundColor(.white)
.font(.system(size: 15))
.padding(.trailing)
}
}
.background(Rectangle()
.fill(Color("active"))
.cornerRadius(100)
.frame(height: 26))
}
}
VStack {
Divider()
.background(Color("inactive"))
.padding(.vertical)
Divider()
.background(Color("inactive"))
.padding(.vertical)
Divider()
.background(Color("inactive"))
.padding(.vertical)
Divider()
.background(Color("inactive"))
.padding(.vertical)
Divider()
.background(Color("inactive"))
.padding(.vertical)
Divider()
.background(Color("inactive"))
.padding(.vertical)
}
HStack {
Button {
} label: {
ZStack {
Circle()
.fill(Color("navigation"))
.frame(width: 26)
Image(systemName: "chevron.left")
.foregroundColor(.white)
.font(.system(size: 14))
}
}
Button {
} label: {
ZStack {
Circle()
.fill(Color("navigation"))
.frame(width: 26)
Image(systemName: "chevron.right")
.foregroundColor(Color("inactive"))
.font(.system(size: 14))
}
}
}
.padding(.top)
}
.padding(.horizontal, 15.0)
}
}
struct CheckInView_Previews: PreviewProvider {
static var previews: some View {
CheckInView(sheetManager: SheetManager())
.background(.yellow)
}
}
If I have all of this, how can I create a pop-up over Tab View? Maybe a link to a similar problem?

Related

Zoom Image over top of other Views SwiftUI

I have a image as thumbnail when image is tapped it should be expanded/zoom at the centre of screen with background as blur. I tried scale effect but the image is not on top of other view but looks like behind (see pics). How to achieve this zoomed imaged with blur background effect (see peacock pic this is the requirement)
#State var enlarge:Bool = false
var body: some View {
GeometryReader{geo in
VStack{
ZStack(alignment: .top){
LinearGradient(gradient:Gradient(colors: [.blue.opacity(0.3),.blue.opacity(0.2)]),startPoint: .top,endPoint:.bottom)
.ignoresSafeArea()
VStack(alignment: .leading,spacing :5){
HStack{
Text("Lorum Ipsum ackndweg")
.fontWeight(.semibold)
.padding(.top,15)
.padding(.leading,18)
.foregroundColor(ThemeColor.testName)
}
.frame(width: geo.size.width, alignment: .leading)
Image("capAm")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.padding(.leading,18)
.onTapGesture{
withAnimation
{
self.enlarge.toggle()
}
}
.scaleEffect(self.enlarge ? 4 : 1,anchor: .topLeading)
VStack(alignment:.leading,spacing: 5){
HStack{
Text("Turn Around Time :")
.font(.system(size: 14))
.foregroundColor(.red)
Text("Report Delivery : Daily")
.font(.system(size: 14))
.foregroundColor(.orange)
}
.frame(width: geo.size.width, alignment: .center)
VStack(alignment:.leading)
{
HStack{
Text("Turn Around Time(TAT) :")
.font(.system(size: 14))
.foregroundColor(.red)
Text("4 hours after acceptance of the sample at the centre")
.font(.system(size: 14))
.foregroundColor(.red)
.multilineTextAlignment(.leading)
}
}.frame(width: geo.size.width, alignment: .center)
}
}}}}}}
below just an idea
struct SwiftUIView: View {
#State private var enlarge = false
#State private var list = 1...10
#State private var current = 0
var body: some View {
ZStack {
ZStack {
Image(systemName: "\(current).circle")
.resizable()
.scaledToFit()
.frame(width: 60 , height: 60)
.padding()
.animation(.spring(), value: enlarge)
.foregroundColor(.yellow)
}
.frame(width: 300,
height: 200)
.background(Color.black.opacity(0.2))
.foregroundColor(Color.clear)
.cornerRadius(20)
.transition(.slide)
.opacity(self.enlarge ? 1 : 0)
.zIndex(2)
.onTapGesture{
withAnimation {
self.enlarge.toggle()
}
}
List {
ForEach(list, id:\.self) { i in
Label("detail of \(i)", systemImage: "\(i).circle")
.onTapGesture{
current = i
withAnimation {
self.enlarge.toggle()
}
}
}
}
.blur(radius: self.enlarge ? 3 : 0).offset(y: 1)
}
.onTapGesture{
withAnimation {
self.enlarge = false
}
}
}
}

SwiftUI, different Views in same GridView

I need to add two different types of view in same grid view, there is an alignment issue between these view as shown in give image below. The view which contains image is taking more space from top and bottom even after fixing the size
struct TestView: View {
#StateObject var vm = BusinessProfileViewModel()
#Environment(\.presentationMode) private var presentationMode
let columns = [
GridItem(.flexible(minimum: 100), spacing: 20),
GridItem(.flexible(minimum: 100), spacing: 20)
]
var body: some View {
loadView()
}
}
extension TestView {
func loadView() -> some View {
GeometryReader { geometry in
ZStack(alignment: .bottomTrailing) {
ScrollView(.vertical, showsIndicators: false) {
topBusinessImage(geometry: geometry)
VStack {
featureProduct(geometry: geometry)
}.padding()
}.edgesIgnoringSafeArea(.top)
}
}
}
func topBusinessImage(geometry: GeometryProxy) -> some View {
VStack(spacing: 0) {
// Profile Image Stack
// Banner Zstack
ZStack (alignment: .top) {
Image(ImageName.productPlaceholder.rawValue)
.resizable()
.frame(height: geometry.size.height / 2.5)
}
}
}
func featureProduct(geometry: GeometryProxy) -> some View {
VStack(alignment: .leading) {
// product and services button
HStack {
Text("Products & Services")
.font(.custom(Popins.bold.rawValue, size: 20))
Spacer()
Button {
print("list")
} label: {
Image(ImageName.list.rawValue)
.resizable()
.frame(width: 24, height: 24)
}.padding(5)
}
LazyVGrid(columns: columns, spacing: 30) {
BusinessProductCell()
ProductOnlyDetailCell()
ProductOnlyDetailCell()
BusinessProductCell()
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
view that contains image
import SwiftUI
struct BusinessProductCell: View {
var body: some View {
loadView()
}
}
extension BusinessProductCell {
func loadView() -> some View {
VStack(alignment: .leading) {
ZStack(alignment: .topLeading) {
Image(ImageName.business.rawValue)
.resizable()
.frame(height: 205)
.cornerRadius(10)
HStack {
Button {
print("fav")
} label: {
Image(systemName: "heart.fill")
.resizable()
.scaledToFit()
.foregroundColor(UnifiedColor.blue)
.frame(width: 20, height: 20)
}.padding()
Spacer()
Button {
print("fav")
} label: {
Image(systemName: "ellipsis")
.resizable()
.scaledToFit()
.frame(width: 20)
.foregroundColor(.white)
}.padding()
}
}
Text("Dove Body Care")
.foregroundColor(.black)
.font(.custom(Popins.medium.rawValue, size: 16))
HStack {
Text("$49.99")
.font(.custom(Popins.medium.rawValue, size: 12))
.foregroundColor(UnifiedColor.textBlue)
Spacer()
HStack {
Text("(286 Favorites)")
.font(.custom(Popins.regular.rawValue, size: 8))
.foregroundColor(.gray)
Image(ImageName.heart_line.rawValue)
.resizable()
.frame(width: 15, height: 15)
}
}
}
}
}
struct BusinessProductCell_Previews: PreviewProvider {
static var previews: some View {
BusinessProductCell()
.frame(width: 200, height: 250)
}
}
View that only contains text or second view for gird view
struct ProductOnlyDetailCell: View {
var body: some View {
loadView()
}
}
extension ProductOnlyDetailCell {
func loadView() -> some View {
VStack(alignment: .leading, spacing: 10) {
HStack {
Image(ImageName.productPlaceholder.rawValue)
.resizable()
.scaledToFill()
.frame(width: 24, height: 24)
.clipShape(Circle())
.overlay {
Circle().stroke(.white, lineWidth: 1)
}
Text("Anton Jr.")
.font(.custom(Popins.regular.rawValue, size: 12 ))
.foregroundColor(.black)
.lineLimit(1)
Spacer()
Button {
print("more btn")
} label: {
Image(systemName: "ellipsis")
.resizable()
.foregroundColor(.black)
.frame(width: 18, height: 4)
.padding([.trailing, .top, .bottom])
}
}
Text("DJ for night")
.font(.custom(Popins.bold.rawValue, size: 14))
.foregroundColor(.black)
Text("Lorem ipsum dolor sitamet, consectetur adipiscingelit. Lectus idcommodoegestas metusinterdum dolor.")
.multilineTextAlignment(.leading)
.font(.custom(Popins.regular.rawValue, size: 12))
.foregroundColor(.black)
.opacity(0.8)
Spacer()
HStack (spacing: 0){
Text("$15K")
.font(.custom(Popins.bold.rawValue, size: 14))
.foregroundColor(.black)
Text("/")
.font(.custom(Popins.bold.rawValue, size: 14))
.foregroundColor(.gray)
Text("Night")
.font(.custom(Popins.regular.rawValue, size: 14))
.foregroundColor(.gray)
}
Text("25 minute ago")
.font(.custom(Popins.regular.rawValue, size: 10))
.foregroundColor(.gray)
}
.padding(10)
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.gray.opacity(0.1))
)
}
}

How to do a "reveal"-style collapse/expand animation in SwiftUI?

I'd like to implement an animation in SwiftUI that "reveals" the content of a view to enable expand/collapse functionality. The content of the view I want to collapse and expand is complex: It's not just a simple box, but it's a view hierarchy of dynamic height and content, including images and text.
I've experimented with different options, but it hasn't resulted in the desired effect. Usually what happens is that when I "expand", the whole view was shown right away with 0% opacity, then gradually faded in, with the buttons under the expanded view moving down at the same time. That's what happened when I was using a conditional if statement that actually added and removed the view. So that makes sense.
I then experimented with using a frame modifier: .frame(maxHeight: isExpanded ? .infinity : 0). But that resulted in the contents of the view being "squished" instead of revealed.
I made a paper prototype of what I want:
Any ideas on how to achieve this?
Something like this might work. You can modify the height of what you want to disclose to be 0 when hidden or nil when not so that it'll go for the height defined by the views. Make sure to clip the view afterwards so the contents are not visible outside of the frame's height when not disclosed.
struct ContentView: View {
#State private var isDisclosed = false
var body: some View {
VStack {
Button("Expand") {
withAnimation {
isDisclosed.toggle()
}
}
.buttonStyle(.plain)
VStack {
GroupBox {
Text("Hi")
}
GroupBox {
Text("More details here")
}
}
.frame(height: isDisclosed ? nil : 0, alignment: .top)
.clipped()
HStack {
Text("Cancel")
Spacer()
Text("Book")
}
}
.frame(maxWidth: .infinity)
.background(.thinMaterial)
.padding()
}
}
No, this wasn't trying to match your design, either. This was just to provide a sample way of creating the animation.
Consider the utilization of DisclosureGroup. The following code should be a good approach to your idea.
struct ContentView: View {
var body: some View {
List(0...20, id: \.self) { idx in
DisclosureGroup {
HStack {
Image(systemName: "person.circle.fill")
VStack(alignment: .leading) {
Text("ABC")
Text("Test Test")
}
}
HStack {
Image(systemName: "globe")
VStack(alignment: .leading) {
Text("ABC")
Text("X Y Z")
}
}
HStack {
Image(systemName: "water.waves")
VStack(alignment: .leading) {
Text("Bla Bla")
Text("123")
}
}
HStack{
Button("Cancel", role: .destructive) {}
Spacer()
Button("Book") {}
}
} label: {
HStack {
Spacer()
Text("Expand")
}
}
}
}
The result looks like:
I coded this in under 5 minutes. So of course the design can be optimized to your demands, but the core should be understandable.
import SwiftUI
struct TaskViewCollapsible: View {
#State private var isDisclosed = false
let header: String = "Review Page"
let url: String
let tasks: [String]
var body: some View {
VStack {
HStack {
VStack(spacing: 5) {
Text(header)
.font(.system(size: 22, weight: .semibold))
.foregroundColor(.black)
.padding(.top, 10)
.padding(.horizontal, 20)
.frame(maxWidth: .infinity, alignment: .leading)
Text(url)
.font(.system(size: 12, weight: .regular))
.foregroundColor(.black.opacity(0.4))
.padding(.horizontal, 20)
.frame(maxWidth: .infinity, alignment: .leading)
}
Spacer()
Image(systemName: self.isDisclosed ? "chevron.up" : "chevron.down")
.padding(.trailing)
.padding(.top, 10)
}
.onTapGesture {
withAnimation {
isDisclosed.toggle()
}
}
FetchTasks()
.padding(.horizontal, 20)
.padding(.bottom, 5)
.frame(height: isDisclosed ? nil : 0, alignment: .top)
.clipped()
}
.background(
RoundedRectangle(cornerRadius: 8)
.fill(.black.opacity(0.2))
)
.frame(maxWidth: .infinity)
.padding()
}
#ViewBuilder
func FetchTasks() -> some View {
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0 ..< tasks.count, id: \.self) { value in
Text(tasks[value])
.font(.system(size: 16, weight: .regular))
.foregroundColor(.black)
.padding(.vertical, 0)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
.frame(maxHeight: CGFloat(tasks.count) * 20)
}
}
struct TaskViewCollapsible_Previews: PreviewProvider {
static var previews: some View {
TaskViewCollapsible(url: "trello.com", tasks: ["Hello", "Hello", "Hello"])
}
}

Adding a "Hamburger" Menu to IOS application

I am trying to create a hamburger menu that when you click the "hamburger" (three horizontal lines) button, the menu will slide out. I am following the tutorial found here, but the only thing that isn't working is the lines for the Hamburger image is not showing up on my application. Everything else works, but for some reason this is the one thing that is not working.
Here is my code for the ContentView, where it hosts the problem code
struct ContentView: 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) {
MainView(showMenu: self.$showMenu)
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: self.showMenu ? geometry.size.width/2 : 0)
.disabled(self.showMenu ? true : false)
if self.showMenu {
MenuView()
.frame(width: geometry.size.width/2)
.transition(.move(edge: .leading))
}
}
.gesture(drag)
}
.navigationBarTitle("Side Menu", displayMode: .inline) // this works
//somewhere below here is the problem
.navigationBarItems(leading: (
Button(action: {
withAnimation {
self.showMenu.toggle()
}
}) {
Image(systemName: "three_horizontal_lines")
.imageScale(.large)
}
))
}
}
}
Here is the MainView:
struct MainView: View{
#Binding var showMenu: Bool
var body: some View{
Button(action: {
withAnimation{
self.showMenu = true
}
}){
Text("Show Menu")
}
}
}
Lastly, this is the MenuView:
struct MenuView: View{
var body: some View{
VStack(alignment: .leading){
HStack{
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Profile")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 100)
HStack{
Image(systemName: "envelope")
.foregroundColor(.gray)
.imageScale(.large)
Text("Messages")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
HStack{
Image(systemName: "gear")
.foregroundColor(.gray)
.imageScale(.large)
Text("Settings")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
Spacer()
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(/*#START_MENU_TOKEN#*/.all/*#END_MENU_TOKEN#*/)
}
}
I have checked for any misspellings and even copied and pasted the code from the original tutorial, but it seems nothing allows me to see the burger image like is shown on the tutorial. Any thoughts on what else I could try?

How can I switch 2 different views inside same "Main" view? SwiftUI

I have next problem with my SwiftUI view: I have "User View" , in this view I have 2 buttons - "Saved" and "My achievement". When user tapped on any button , it will show different views (for example: like TabBar).
It will be switch on same screen , not transition to the other view.
Photo
I can create another views , and put it into my , if it needs.
Hope your understand my quick English.
Thank You for help!
Code:
import SwiftUI
struct MainPage: View {
///State variable for default selected tag
#State var selectedView = 3
///Body-view for the main screen
var body: some View {
TabView(selection: $selectedView) {
//MARK: - First screen (1st view)
VStack {
Text("First View")
}///1st Global VStack
.tabItem {
Label("First Item", systemImage: "1.circle")
}.tag(1)
//MARK: - Scond screen (2nd view)
VStack {
Text("Second View")
}///2nd Global VStack
.tabItem {
Label("Second Item", systemImage: "2.circle")
}
.tag(2)
//MARK: - Profile screen (3rd view)
ZStack(alignment: .top) {
Color.clear
HStack(alignment: .center){
VStack {
HStack() {
HStack() {
Button(action: {}, label: {
Image(systemName: "person")
.resizable()
.scaledToFit()
.frame(width: 35 , height: 35)
.foregroundColor(.gray)
})
.padding(.leading , -30)
.padding(.trailing, 20)
Text("User")
.bold()
.font(.custom("title", size: 24))
.lineLimit(1)
}.padding(.trailing , 110)
.frame(width: 260)
Button(action: {}, label: {
Image(systemName: "gearshape")
.resizable()
.scaledToFit()
.frame(width: 35 , height: 35)
.foregroundColor(.gray)
})
}
HStack(spacing: 30) {
Image(systemName: "")
Button(action: {
}, label: {
Text("Saved")
.foregroundColor(.gray)
.font(.custom("title", size: 17))
.lineLimit(1)
})
Image(systemName: "")
Button(action: {}, label: {
Text("My achievement")
.foregroundColor(.gray)
.font(.custom("title", size: 17))
.lineLimit(1)
})
}.frame(width: 300, height: 30, alignment: .center)
HStack(alignment: .center ,spacing: 10){
VStack(alignment: .leading , spacing: 20) {
}.frame(width: 160, height: 2, alignment: .leading)
.background(Color.blue)
.padding(10)
VStack(alignment: .trailing){
}.frame(width: 100, height: 2, alignment: .trailing)
.background(Color.red)
.padding()
}.frame(width: 420, height: 2, alignment: .center)
.background(Color.gray)
.padding(10)
}
}///Top HStack
.frame(width: 300, height: 70, alignment: .center)
.padding()
}///3rd Global ZStack
.tabItem {
Label("Third item", systemImage: "3.circle")
}.tag(3)
//MARK: - End
}
}
}
You could do it with a segmented picker like this.
struct ExampleView: View
{
#State private var selectedView = 0
private let pickerOptions = ["Saved", "Achievements"]
var body: some View {
VStack {
HStack {
Text("ExampleView")
.font(.title)
.bold()
Spacer()
} //: HStack
.padding()
Divider()
Picker(selection: $selectedView, label: Text("")) {
ForEach(0..<pickerOptions.count) {
Text(self.pickerOptions[$0])
} //: ForEach
} //: Picker
.pickerStyle(SegmentedPickerStyle())
.padding()
if selectedView == 0
{
SavedView()
}
else if selectedView == 1
{
AchievementsView()
}
}
}
}