Coming from UIKit, I was just trying SwiftUI.
I just wanted to show hello world in a view with navigation bar. So I wrote below code.
I can see Text widget but I can't see NavigationView widget.
var body: some View {
NavigationView {
VStack(alignment: .center) {
Text("Hello World")
}
}
.navigationBarTitle(Text("ForgotPassword")
.font(.largeTitle)
.fontWeight(.medium), displayMode: .inline)
.shadow(color: Color.blue, radius: 0, x: 0, y: 5)
.navigationViewStyle(DefaultNavigationViewStyle())
.background(Color.red)
}
Am I doing something wrong here?
try this:
var body: some View {
NavigationView {
VStack(alignment: .center) {
Text("Hello World")
}.navigationBarTitle(Text("ForgotPassword")
.font(.largeTitle)
.fontWeight(.medium), displayMode: .inline)
.shadow(color: Color.blue, radius: 0, x: 0, y: 5)
.navigationViewStyle(DefaultNavigationViewStyle())
}
}
Related
I'm trying to give a shadow to Button using following code.
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal){
HStack(){
ForEach(menuOptions, id: \.self){m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
.background(.clear)
}.background(.clear)
And my MenuButton struct:
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{}, label: {
Text(title)
.font(.system(size: 17))
.frame(width:120, height:35)
.cornerRadius(10)
.foregroundColor(Color("secondaryColor"))
.background(Rectangle().fill(.white).shadow(color:.gray,radius:2).cornerRadius(10))
})
}
}
this would be my output:
Expected output:
In above image you can see that shadow is not proper.
How can I achieve the following?
#Dans code works. But its not so much the .tint as the .background of the button, and the order of applying modifiers.
You used a rectangle, then applied shadow, then used cornerRadius. In this order the cornerRadius "cuts off" the shadow applied before.
If you use RoundedRectangle instead (as Dan did) it works fine.
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.white)
.shadow(color:.gray,radius: 2, y: 1)
)
Or you just change the ordering of the modifiers. First cornerRadius, then shadow.
.background(
Rectangle()
.fill(.white)
.cornerRadius(12)
.shadow(color:.gray,radius: 2, y: 1)
)
I believe adding a .buttonStyle(.borderedProminent) and .tint(.clear) may help achieve your desired look. Something like this;
struct ButtonView: View {
let menuOptions = ["Entradas", "Bebidas", "Plato Fuerte", "Postre"]
var body: some View {
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal) {
HStack {
ForEach(menuOptions, id: \.self){ m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
//.background(.clear)
}//.background(.clear)
}
}
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{ }, label: {
Text(title)
.font(.system(size: 17))
.frame(width: 120, height: 35)
.cornerRadius(10)
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 10, style: .circular)
.fill(.white)
.shadow(color: .gray, radius: 2, x: -1, y: 2)
)
})
.buttonStyle(.borderedProminent)
.tint(.clear)
}
}
Result
I am currently having trouble with my Custom Tab Bar there is a gray area above it (Tab View) that controls each tab but I need that to go under my custom tab bar but functionality of the TabView still be in effect and be used with the icons. You can hide the Tab bar with UITabBar.apperance() which gets rid of the gray area but no longer has any functions.. but I need that gray area to go under the tabs. If that makes sense?
Home.swift
import SwiftUI
struct Home: View {
//Hiding Tab Bar..
init() {
UITabBar.appearance().isHidden = false
}
var body: some View {
VStack(spacing: 0){
//Tab View...
TabView{
Color.blue
.tag("house.circle")
Color.green
.tag("pencil")
Color.pink
.tag("magnifyingglass")
Color.red
.tag("bell")
Color.yellow
.tag("cart")
}
//Custom Tab Bar...
CustomTabBar()
}
.ignoresSafeArea()
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
//Extending View To Get Screen Frame...
extension View {
func getRect()->CGRect {
return UIScreen.main.bounds
}
}
CustomTabBar.swift
import SwiftUI
struct CustomTabBar: View {
var body: some View {
HStack(spacing: 0){
// Tab Bar Button...
TabBarButton(systemName: "house.circle")
.background(Color.blue)
TabBarButton(systemName: "pencil")
.background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(systemName: "bell")
.background(Color.red)
TabBarButton(systemName: "cart")
.background(Color.yellow)
}
.padding(.top)
//Decreasing the extra padding added...
.padding(.vertical, -0)
.padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
.background(Color.white)
}
}
struct CustomTabBar_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}
}
}
//extending view to get safe area...
extension View {
func getSafeArea()-> UIEdgeInsets {
return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
struct TabBarButton: View {
var systemName: String
var body: some View{
Button(action: {
}, label: {
VStack(spacing: 8){
Image(systemName)
.resizable()
//Since its asset image...
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:28, height: 28)
}
.frame(maxWidth: .infinity)
})
}
}
EDIT: SECOND IMAGE I am hiding the tab bar setting it to true instead of false.
//Hiding Tab Bar..
init() {
UITabBar.appearance().isHidden = true
}
you could try this to "cover" the original TabView bar:
In Home replace VStack with ZStack.
and
struct CustomTabBar: View {
var body: some View {
VStack (alignment: .leading) {
Spacer()
HStack(spacing: 0) {
TabBarButton(systemName: "house.circle").background(Color.blue)
TabBarButton(systemName: "pencil").background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(systemName: "bell").background(Color.red)
TabBarButton(systemName: "cart").background(Color.yellow)
}
}
.padding(.bottom, getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
.background(Color.white)
}
}
you will then need to implement the action of each of your CustomTabBar buttons.
EDIT1:
ok, as I mentioned you need to implement the actions for your buttons.
There are many ways to do this, this is just one approach:
struct CustomTabBar: View {
#Binding var tagSelect: String
var body: some View {
VStack (alignment: .leading) {
Spacer()
HStack(spacing: 0) {
TabBarButton(tagSelect: $tagSelect, systemName: "house.circle").background(Color.blue)
TabBarButton(tagSelect: $tagSelect, systemName: "pencil").background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(tagSelect: $tagSelect, systemName: "bell").background(Color.red)
TabBarButton(tagSelect: $tagSelect, systemName: "cart").background(Color.yellow)
}
}
.padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
// no background or use opacity, like this
.background(Color.white.opacity(0.01)) // <-- important
}
}
extension View {
func getSafeArea()-> UIEdgeInsets {
return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
struct TabBarButton: View {
#Binding var tagSelect: String
var systemName: String
var body: some View{
Button(action: {tagSelect = systemName }, label: {
VStack(spacing: 8){
Image(systemName)
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:28, height: 28)
}
.frame(maxWidth: .infinity)
})
}
}
struct Home: View {
#State var tagSelect = "house.circle"
init() {
UITabBar.appearance().isHidden = false
}
var body: some View {
ZStack {
TabView (selection: $tagSelect) {
Color.blue.tag("house.circle")
Color.green.tag("pencil")
Color.pink.tag("magnifyingglass")
Color.red.tag("bell")
Color.yellow.tag("cart")
}
CustomTabBar(tagSelect: $tagSelect)
}
.ignoresSafeArea()
}
}
extension View {
func getRect()->CGRect {
return UIScreen.main.bounds
}
}
I want to hide some text behind the NavigationBarTitle and show it when user press a button, it's working fine. The only problem is with the animation. At loading we see the text moving behind the NavigationBarTitle and that's not what i want.
How can i fix this?
I tried with offset and position but it's not working...
Code :
import SwiftUI
struct TestZStackNavigationView: View {
#State var isShowed = false
let screenSize: CGRect = UIScreen.main.bounds
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 0){
Text("Im the hidden text")
.fontWeight(.bold)
.foregroundColor(Color.white)
.frame(width: screenSize.width, height: 40, alignment: .center)
.background(Color.red)
// .offset(y: self.isShowed ? -315 : -355)
.position(x: screenSize.width / 2, y: self.isShowed ? 20 : -40)
.animation(.easeIn(duration: 0.5))
Button(action: {
self.isShowed.toggle()
}) {
Text("click me")
}
.navigationBarTitle(Text("Navigation Bar Title"), displayMode:.inline)
}
}
}
}
struct TestZStackNavigationView_Previews: PreviewProvider {
static var previews: some View {
TestZStackNavigationView()
}
}
There are two possibilities
make animation per-state (and no other changes)
.animation(.easeIn(duration: 0.5), value: isShowed)
replace implicit animation as modifier and add explicit animation in action
.position(x: screenSize.width / 2, y: self.isShowed ? 20 : -40)
// .animation(.easeIn(duration: 0.5)) // remove from here
Button(action: {
withAnimation(Animation.easeIn(duration: 0.5)) { // << add this
self.isShowed.toggle()
}
}) {
Text("click me")
}
I want to use it now with an ObservedObject but i got that same behavior as first code. Why?
struct TestZStackNavigationView: View {
// #State var isShowed = false
let screenSize: CGRect = UIScreen.main.bounds
#ObservedObject var online = NetStatus()
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 0){
Text("Im the hidden text")
.fontWeight(.bold)
.foregroundColor(Color.white)
.frame(width: screenSize.width, height: 40, alignment: .center)
.background(Color.red)
.position(x: screenSize.width / 2, y: online.connected ? -40 : 20)
.animation(.easeIn(duration: 0.5), value: online.connected)
.navigationBarTitle(Text("Navigation Bar Title"), displayMode:.inline)
}
}
}
}
How can I insert the preview of a widget into the app?
Can anyone give me some advice?
I did a naive version of a Widget configuration preview using SwiftUI. I used a RoundedRectangle with a small 3D rotation and applied a shadow:
I contained the code inside a custom View called WidgetView:
struct WidgetView<Content: View>: View {
let content: Content
init(#ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 24, style: .continuous)
.fill(Color(.systemBackground))
content
}
.frame(width: 162, height: 162)
.rotation3DEffect(.degrees(10), axis: (x: 1, y: 1, z: 0))
.shadow(color: Color(UIColor.systemGray), radius: 20, x: -5, y: 10)
}
}
The usage is quite simple. Just add the content view you want inside the Widget view:
WidgetView {
HealthActiveEnergyView(entry: ActiveEnergyEntry.mock())
}
.preferredColorScheme(.light)
.previewLayout(layout)
struct HealthActiveEnergyView: View {
var entry: ActiveEnergyEntry
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(NSLocalizedString("Active", comment: ""))
.foregroundColor(entry.configuration.accentColor)
Spacer()
Image(systemName: "flame.fill")
.font(.system(.title))
.foregroundColor(entry.configuration.accentColor)
}
Text(dateFormatter.string(from: entry.date))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.totalOfKilocalories)")
.font(.system(.largeTitle, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
Spacer()
}
Spacer()
Text(NSLocalizedString("AVG 7 DAYS", comment: ""))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.avgOfKilocalories)")
.font(.system(.callout, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
.font(.caption)
Spacer()
}
}
.padding()
}
}
My NavigationView and Title when using SwiftUI never appear where I'd expect them to appear when run on a device or simulator. I want them to be pretty much under the back button that is top left but when run on a device or simulator it goes quite far down the page, here is a screenshot of my simulator resized beside the preview and you can see how different this is.
Here is my code:
import SwiftUI
struct DetailView: View {
let tarot: Tarot
var body: some View {
NavigationView {
VStack() {
Image(tarot.tarotImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.padding(.init(top: 80, leading: 30, bottom: 80, trailing: 30))
Text(tarot.tarotDescription)
.padding(.horizontal)
}
.navigationBarTitle(tarot.tarotName, displayMode: .automatic)
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(tarot: cardsArray[0])
}
}
You shouldn't have more than one NavigationView in your navigation stack.
Try to remove the NavigationView from your DetailView:
struct DetailView: View {
let tarot: Tarot
var body: some View {
VStack {
Image(tarot.tarotImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.padding(.init(top: 80, leading: 30, bottom: 80, trailing: 30))
Text(tarot.tarotDescription)
.padding(.horizontal)
}
.navigationBarTitle(tarot.tarotName, displayMode: .automatic)
}
}