#ViewBuilder
func TabButton (image: String)-> some View{
Button {
withAnimation{currentTab = image}
} label: {
Image(image)
.resizable()
.renderingMode(.original)
.aspectRatio(contentMode: .fit)
.frame(width: 23, height: 22)
.foregroundColor(currentTab == image ? .primary : .gray)
.frame(maxWidth: .infinity)
}.buttonStyle(GradientButtonStyle())
}
}
I want rather than image from assets as input, system image whom is variable is input here and can change each time and not fixed. thank you
I use it like this,
struct MainView: View {
#State var showMenu: Bool = false
// Hiding Native One.
init(){
UITabBar.appearance().isHidden = true
}
#State var currentTab = "Home"
//offset for both drag gesture and showing menu.
#State var offset: CGFloat = 0
#State var lastStoredOffset: CGFloat = 0
var body: some View {
//let sideBarWidth = getRect().width - 90
// whole navigation view....
NavigationView{
HStack(spacing : 0){
//Side Menu
//SideMenu(showMenu: $showMenu)
//Main Tab View
VStack(spacing: 0){
TabView(selection: $currentTab){
Home(showMenu: $showMenu)
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(true)
.tag("Home")
}
this is the tabview code up
VStack(spacing: 0)
{
Divider()
HStack(spacing:0){
// tab buttons
TabButton(image: "Home")
}
}
}
}
I want system image rather than image here , need help please!
I can only guess ... but I think you want something like this?
struct MainView: View {
// Hiding Native One.
init(){
UITabBar.appearance().isHidden = true
}
#State var currentTab = "house"
var body: some View {
//let sideBarWidth = getRect().width - 90
// whole navigation view....
NavigationView{
VStack(spacing : 0) {
//Side Menu
//SideMenu(showMenu: $showMenu)
//Main Tab View
TabView(selection: $currentTab) {
Text("Home Content") // Home(showMenu: $showMenu)
.tag("house")
Text("Star Content") // ...
.tag("star")
Text("Settings Content") // ...
.tag("gear")
}
.tabViewStyle(.page(indexDisplayMode: .never))
Divider()
Spacer(minLength: 10)
HStack {
// tab buttons
TabButton(image: "house")
TabButton(image: "star")
TabButton(image: "gear")
}
}
}
}
func TabButton (image: String)-> some View{
Button {
withAnimation{ currentTab = image }
} label: {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 23, height: 22)
.foregroundColor( currentTab == image ? .primary : .gray)
.frame(maxWidth: .infinity)
}
// .buttonStyle(GradientButtonStyle())
}
}
Related
I want to recreate system picker behavioral with two options in wheels with SwiftUI and faced ton of problem. Some of this I solved but some still unsolved. I have pop-ups with different views inside. One of the view it's a DatePicker with displayedComponents: .hourAndMinute. And other one is two Pickers inside HStack. My question is how to make Pickers make look like in system: without white spacing between?
struct MultyPicker: View {
#State var value = 1
#State var value2 = 1
var body: some View {
ZStack(alignment: .bottom) {
Color.black.opacity(0.5)
ZStack {
VStack {
Text("Header")
.font(.title3)
.fontWeight(.bold)
HStack(spacing: 0) {
Picker(selection: $value, label: Text("")) {
ForEach(1..<26) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
Picker(selection: $value2, label: Text("")) {
ForEach(25..<76) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 34)
.foregroundColor(.white)
)
}
.padding(.horizontal)
.padding(.bottom, 50)
}
.edgesIgnoringSafeArea([.top, .horizontal])
}
}
// This extension for correct touching area
extension UIPickerView {
open override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: super.intrinsicContentSize.height)
}
}
Want to achive looks like that with one grey line in selected value
//
// Test2.swift
// Test
//
// Created by Serdar Onur KARADAĞ on 26.08.2022.
//
import SwiftUI
struct Test2: View {
#State var choice1 = 0
#State var choice2 = 0
var body: some View {
ZStack {
Rectangle()
.fill(.gray.opacity(0.2))
.cornerRadius(30)
.frame(width: 350, height: 400)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("HEADER")
HStack(spacing: 0) {
Picker(selection: $choice1, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
Picker(selection: $choice2, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
}
}
}
}
}
struct Test2_Previews: PreviewProvider {
static var previews: some View {
Test2()
}
}
SwiftUI multi-component Picker basically consists of several individual Picker views arranged horizontally. Therefore, we start by creating an ordinary Picker view for our first component. I am using Xcode version 13.4.1(iOS 15.0).
import SwiftUI
struct ContentView: View {
#State var hourSelect = 0
#State var minuteSelect = 0
var hours = [Int](0..<24)
var minutes = [Int](0..<60)
var body: some View {
ZStack {
Color.black
.opacity(0.5)
.ignoresSafeArea()
.preferredColorScheme(.light)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("Header")
HStack(spacing: 0) {
Picker(selection: $hourSelect, label: Text("")) {
ForEach(0..<self.hours.count) { index in
Text("\(self.hours[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
Picker(selection: $minuteSelect, label: Text("")) {
ForEach(0..<self.minutes.count) { index in
Text("\(self.minutes[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Output :
I have created with help from another tutorial a Custom tab Bar with animation for my Example App to test the Project etc..
and now I want to add the navigation for each Icon(symbol) so when the user presses TapBarButton 1(Symbol"house") they see the HomeView and when tap TapBarButton 2 the next view is visible with some Data, but I don't understand this topic in moment.
so here is the complete Code from this Section for the Custom Tab Bar.
I don't need a complete solution, I need only a start Point in which section of my code I must implement the Navigation and how is this the best way for Request?.
the code follow here.. ->
struct CustomTabBarNew: View {
#Binding var selectedTab: String
// Storing each Tab Midpoints to animate in future...
#State var tabPoints : [CGFloat] = []
var body: some View {
HStack(spacing: 10) {
// Tab Bar Buttons
TabBarButton(image: "house", selectedTab: $selectedTab, tabPoints: $tabPoints)
TabBarButton(image: "cloud.sun", selectedTab: $selectedTab, tabPoints: $tabPoints)
TabBarButton(image: "paperplane", selectedTab: $selectedTab, tabPoints: $tabPoints)
TabBarButton(image: "plus.app", selectedTab: $selectedTab, tabPoints: $tabPoints)
TabBarButton(image: "gearshape", selectedTab: $selectedTab, tabPoints: $tabPoints)
}
.padding()
.background(
Color.white
.clipShape(TabCurve(taboint: getCurvePoint() - 15))
)
.overlay(
Circle()
.fill(Color.white)
.frame(width: 10, height: 10)
.offset(x: getCurvePoint() - 20)
,alignment: .bottomLeading)
.cornerRadius(30.0)
.padding(.horizontal)
}
// extracting Points..
func getCurvePoint()->CGFloat {
// if tabpoint is empty...
if tabPoints.isEmpty {
return 10
}
else {
switch selectedTab {
case "house":
return tabPoints[0]
case "cloud.sun":
return tabPoints[1]
case "paperplane":
return tabPoints[2]
case "plus.app":
return tabPoints[3]
default:
return tabPoints[4]
}
}
}
}
struct CustomTabBarNew_Previews: PreviewProvider {
static var previews: some View {
HomeNewView()
}
}
struct TabBarButton: View {
var image: String
#Binding var selectedTab: String
#Binding var tabPoints: [CGFloat]
var body: some View{
// mid point for each animation of each button...
GeometryReader { reader -> AnyView in
let midX = reader.frame(in: .global).midX
DispatchQueue.main.async {
// avoiding junk data...
if tabPoints.count <= 5 {
tabPoints.append(midX)
}
}
// extracting Midpoint and Storing ...
return AnyView(
Button(action:
// changing Tab..
// Spring animation...
{
withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.5, blendDuration: 0.5)) {
selectedTab = image
}
}, label: {
// filling the color if its selcted..
Image(systemName: "\(image)\(selectedTab == image ? ".fill" : "")")
.font(.system(size: 25, weight: .semibold))
.foregroundColor(Color("TabSelected"))
// Lifting View..
// if its selected
.offset(y: selectedTab == image ? -10 : 0)
})
// MAX FRAME
.frame(maxWidth: .infinity, maxHeight: .infinity)
)
}
// MAX Height
.frame(height: 50)
}
}
I am trying to get a TabView in SwiftUI, but it just doesn't work... My code is here:
import SwiftUI
import SDWebImage
import HalfModal
struct ContentView: View {
#State var launches: [Launch] = []
// #State private var showingAlert = false
#State private var show_modal: Bool = false
#State private var mName: String = ""
#State private var mDate: String = ""
#State private var rID: String = ""
#State private var mImg: String = ""
#State private var mDesc: String = ""
#State private var showingHalfModal: Bool = false
#State private var choices = ["Launches", "Rockets"]
#State private var choice = 0
var rocketNames = ["5e9d0d95eda69955f709d1eb": "Falcon 1", "5e9d0d95eda69973a809d1ec": "Falcon 9", "5e9d0d95eda69974db09d1ed": "Falcon Heavy", "5e9d0d96eda699382d09d1ee": "Starship"]
init() {
UITableView.appearance().separatorStyle = .none
UITableViewCell.appearance().backgroundColor = .clear
UITableView.appearance().backgroundColor = .clear
}
var body: some View {
// Spacer()
// .frame(height: 100)
TabView {
Group {
NavigationView {
ZStack {
VStack {
// Spacer()
// .frame(height: 10)
// Text("SpaceX launch list")
// .font(.largeTitle)
Spacer()
.frame(height: 1)
.navigationBarTitle("Launches")
List {
ForEach(launches, id: \.id) { launch in
// Text("image")
// Image("imagenotfound")
Button(action: {
self.mName = launch.name
self.mDate = Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss")
self.rID = launch.rocket
self.mImg = launch.links.patch.missionPatch ?? "null"
self.mDesc = launch.details ?? "No description"
// sleep(1)
self.show_modal.toggle()
withAnimation {
self.showingHalfModal = true
}
}) {
HStack {
// Image("imagenotfound")
// .resizable()
// .frame(width: 50, height: 50)
URLimageView(urlString: launch.links.patch.missionPatch)
// .frame(width: 50, height: 50)
Group {
Text(launch.name)
.font(.system(size: 23))
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
Text(Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss"))
.font(.system(size: 11.5))
.foregroundColor(Color.gray)
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
Spacer()
}
}
}
.buttonStyle(PlainButtonStyle())
// .sheet(isPresented: self.$show_modal) {
// // ModalView(mission: launch.name, date: Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss"), rocket: launch.rocket)
// ModalView(mission: mName, date: mDate, rocket: rID)
// }
}
}.onAppear {
apiCall().getUsers{ (launches) in self.launches = launches}
}.listStyle(SidebarListStyle())
.frame(alignment: .center)
}
if showingHalfModal {
HalfModalView(content: AnyView(VStack(alignment: .leading) {
Text(mDesc)
.padding()
}), header: AnyView(HStack {
URLimageView(urlString: self.mImg)
VStack(alignment: .leading) {
Text(self.mName)
Text(self.mDate)
.font(.system(size: 10))
.foregroundColor(Color.gray)
}}), isPresented: $showingHalfModal)
}
}
}
}
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension Date {
func getFormattedDate(format: String) -> String {
let dateformat = DateFormatter()
dateformat.dateFormat = format
return dateformat.string(from: self)
}
}
I have tried following numerous tutorials that show that they get successful results, but mine still doesn't work...
Screenshot of issue:
It should show 2 tabs: Launches and Rockets... Any ideas on how to get it working?
Your view is too complex and you misplaced some subviews. If you clear the body a little bit, you can see that you attached tabItem modifiers outside the TabView:
var body: some View {
TabView {
Group {
NavigationView {
// ...
}
}
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
Instead, try the following structure:
var body: some View {
TabView {
NavigationView {
// ...
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
}
Note: I recommend you extract some views as subviews. Some examples can be found here:
SwiftUI - Can I share functions with an extracted subview?
How to change the style of image with a event in swiftui?
for example :change the image border color when I click a button, and the image is identified by name
Here is a demo
struct DemoImageBorder: View {
#State private var highlighted = false
var body: some View {
VStack {
Button("Highlight") { self.highlighted.toggle() }
Divider()
Image("some_name_here")
.border(self.highlighted ? Color.red : Color.clear)
}
}
}
how about something like this, change the color border just for the desired image name:
import SwiftUI
struct ContentView: View {
#State var borderColor = Color.blue
#State var imageName = "xyz"
var body: some View {
VStack {
Button(action: {
self.borderColor = Color.red
self.imageName = "person.3"
}){
Text("Change Image border")
}
Image(systemName: "person")
.resizable()
.frame(width: 200, height: 200)
.border(self.imageName == "person" ? borderColor : Color.blue)
Image(systemName: "person.3")
.resizable()
.frame(width: 200, height: 200)
.border(self.imageName == "person.3" ? borderColor : Color.blue)
}
}
}
I am trying to add some filter options to sit at the top of my view, above the NavigationView. I wrote the following code that mostly does what I want, however it disabled the ability to click on the rows to get to the detailed view. I assume this is because my filter buttons are on top of the ZStack, but I'm not sure how else to get this to work.
Here is the code I wrote:
import SwiftUI
struct BonusList: View {
var bonuses = sampleBonusData
#State var showSettings = false
#State var showBonuses = false
#State var bonusEarned = true
#State var showStatePicker = false
#State var showCategoryPicker = false
var body: some View {
ZStack {
NavigationView {
List(bonuses) { item in
NavigationLink(destination: BonusDetail(bonusName: item.bonusName, bonusCode: item.bonusCode, city: item.city, sampleImage: item.sampleImage)) {
HStack(spacing: 12.0) {
Image(item.sampleImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 60, height: 60)
.background(Color.white)
.cornerRadius(15)
VStack(alignment: .leading) {
HStack {
Text(item.bonusName)
.font(.headline)
Spacer()
Image(systemName: "checkmark.shield")
.opacity(self.bonusEarned ? 100 : 0)
}
Text("\(item.city), \(item.state)")
.font(.subheadline)
.frame(height: 25.0)
HStack {
Text(item.bonusCategory)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
.padding(.top, 4)
Spacer()
Text(item.bonusCode)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
.padding(.top, 4)
}
}
}
}
}
.navigationBarTitle(Text("Bonuses"))
// .navigationBarHidden(true)
}
.saturation(self.bonusEarned ? 0 : 1)
HStack {
FilterByCategory(showCategoryPicker: $showCategoryPicker)
Spacer()
FilterByState(showStatePicker: $showStatePicker)
}
StatePicker(showStatePicker: $showStatePicker)
CategoryPicker(showCategoryPicker: $showCategoryPicker)
}
}
}
This is what it looks like when I run it:
If I'm understanding correctly, you have a view or two which sit higher in the ZStack that are off canvas and come in when those buttons are tapped?
You could consider using a modal and setting the view you want to show for each button as the view for the modal. This will keep your views off screen and still allow interaction with your list. Here's what I've done...
On the main view
import SwiftUI
struct MainView: View {
#State private var isPresented = false
var body: some View {
NavigationView {
VStack {
//...
}
//Modal
.sheet(isPresented: $isPresented, content: {
AddItem(showModal: self.$isPresented)
})
}
}
}
The modal's view
import SwiftUI
struct AddItem: View {
#Binding var showModal: Bool
var body: some View {
VStack {
Button(action: {
self.showModal = false
}, label: {
Text("Cancel")
})
}
}
}