Can't resize view with matchedGeometryEffect - swiftui

I'm having problems with resizing the same view when applying to it .matchedGeometryEffect. As expected first you apply .matchedGeometryEffect and after it a .frame() view modifier and it has no effect whatsoever. I'm using iOS 16 and Xcode 14. How to overcome this?
Here's code:
import SwiftUI
struct ContentView: View {
let colors: [Color] = [.red, .purple, .yellow, .green, .blue, .mint, .orange]
#State private var colums = Array(repeating: GridItem(), count: 2)
#State private var showNewView = false
#State private var viewNumber = 0
#Namespace private var colorNamespace
var body: some View {
ScrollView {
LazyVGrid(columns: colums) {
ForEach(1..<101) { number in
colors[number % colors.count]
.matchedGeometryEffect(id: number, in: colorNamespace)
.frame(height: 200)
.overlay(Text("\(number)").font(.title2.bold()).foregroundColor(.white))
.onTapGesture {
withAnimation(.spring()) {
viewNumber = number
showNewView.toggle()
}
}
}
}
}
.opacity(showNewView ? 0 : 1)
if showNewView {
colors[viewNumber % colors.count]
.matchedGeometryEffect(id: viewNumber, in: colorNamespace, anchor: .center)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay(Text("\(viewNumber)").font(.title2.bold()).foregroundColor(.white))
.onTapGesture(count: 2) {
withAnimation(.spring()) {
showNewView = false
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Related

How to have a Navigation link open a different view?

I keep trying to have the navigation links in the surveys list in contentView to open detailView when selected. I keep getting errors Missing argument for parameter 'newsurvey' in call Insert 'newsurvey: <#Survey#>'
Here's the home view
struct ContentView: View {
#State var surveys: [Survey] = []
#State var isPresented = false
#State var selectedTab: Int = 0
#State private var path = [String]()
let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
return formatter
}()
var body: some View {
ZStack {
VStack{
NavigationView {
VStack {
Text("")
.frame(height: 0)
.navigationBarTitleDisplayMode(.inline)
//reduces navbartitle height
.toolbar {
ToolbarItem(placement: .principal) {
Image("RR_Logo_Primary_Full_Color")
.resizable()
.frame(width: 275.0, height: 55.0)
}
}
List(surveys) { survey in
NavigationLink(destination: DetailView(newsurvey: survey)) //must be within navigationview
{
HStack{
ZStack {
Rectangle()
.frame(width: 400, height: 100.0)
.foregroundColor(.white)
.cornerRadius(4)
HStack (alignment: .top) {
VStack (alignment: .leading) {
Text(survey.customerName)
.offset(x: -60, y: -2)
.font(.custom("Roboto-Light", size: 24))
Text(survey.lineName)
.offset(x: -60, y: -5)
.font(.custom("Roboto-Light", size: 18))
Text("# of conveyors")
.offset(x: -60)
}
VStack {
Text(dateFormatter.string(from: survey.date))
.font(.custom("Roboto-Light", size: 18))
.offset(x: 60)
}
}
}
}
}
}
.listRowInsets(EdgeInsets())
}
}
.environment(\.defaultMinListHeaderHeight, 1)
CustomTabBar(surveys: $surveys, isPresented: $isPresented)
.frame(height: 60, alignment: .bottom)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I tried the following code below but I keep getting not in scope error.
#State var newsurvey: Survey
#State var surveys: [Survey] = []
#State private var conveyorName = ""
#State private var masterTag = ""
#State private var showAddConveyorSheet = false
#State private var conveyors: [Conveyor] = []
var body: some View {
NavigationView {
VStack {
List {
ForEach(conveyors, id: \.name) { conveyor in
NavigationLink(destination: ConveyorTrack(conveyor: conveyor)) {
Text(conveyor.name)
}
}
}
Button(action: {
self.showAddConveyorSheet = true
}) {
Text("Add Conveyor")
}
}
.navigationBarTitle("Conveyors", displayMode: .inline)
.sheet(isPresented: $showAddConveyorSheet) {
VStack {
HStack {
TextField("Conveyor Name", text: $conveyorName)
TextField("Master Tag", text: $masterTag)
.onTapGesture {
// open camera and scan text here
}
}
Button(action: {
self.conveyors.append(Conveyor(id: self.conveyorName, name: self.conveyorName, masterTag: self.masterTag))
self.conveyorName = ""
self.masterTag = ""
self.showAddConveyorSheet = false
}) {
Text("Save")
}
}
}
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(newsurvey: survey)
}
}

How I can add a drawing function in SwiftUI?

I can't draw. Unfortunately I don't know where the problem is, colour selection works and the canva is also created, only the drawing doesn't work. I have also checked that the size of the canva is correct and that the path is defined correctly. here is my code:
//
import SwiftUI
struct ContentView: View {
#State private var lines: [Line] = []
#State private var strokeColor: Color = Color.black
var body: some View {
ZStack {
Color.white
.edgesIgnoringSafeArea(.all)
VStack {
Canvas(lines: $lines, strokeColor: $strokeColor)
HStack {
Button(action: clearDrawing) {
Text("Clear")
}
ColorPicker("Stroke Color", selection: $strokeColor)
}
.padding()
}
}
}
func clearDrawing() {
lines.removeAll()
}
}
//
Here I have created the Canva and the button to delete the drawing
//
struct Canvas: View {
#Binding var lines: [Line]
#Binding var strokeColor: Color
var body: some View {
GeometryReader { geometry in
Path { path in
for line in self.lines {
path.move(to: line.points[0])
path.addLines(line.points)
}
}
.stroke(self.strokeColor, lineWidth: 3)
.frame(width: geometry.size.width, height: geometry.size.height)
.gesture(
DragGesture(minimumDistance: 0.1)
.onChanged({ value in
var lastLine = self.lines.last!
let currentPoint = value.location
lastLine.points.append(currentPoint)
})
.onEnded({ value in
self.lines.append(Line())
})
)
}
}
}
struct Line: Identifiable {
var id: UUID = UUID()
var points: [CGPoint] = []
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
//
And here I have made it so that you should actually draw by touch, and that there is a colour selection

SwiftUI Binding Test for Button And Picker

I would like to make a test with SwiftUI binding.
Aim was changing Picker selection with a button and with an other Picker.
In following code ContentView2's Picker selection will be changed with button in ContentView and Picker in ContentView1.
Button can change ContentView2 picker selection but ContentView1 Picker does not.
I can not find the reason.
You can copy paste code to test.
import SwiftUI
struct ContentView: View {
#State private var index1 = 0
#State private var index2 = 1
var body: some View {
GeometryReader { mainView in
HStack {
Button(action: {
if index2 == 0 {
index2 = 1
} else {
index2 = 0
}
}) {
Text("Button")
}
ContentView1(pickerIndex: $index1)
ContentView2(pickerIndex: $index2)
}
}
}
}
struct ContentView1: View {
#State var pickerData = ["Data1", "Data2"]
#Binding var pickerIndex: Int
#State var pickerIndex2 = 0
var customLabel0: some View{
HStack {
VStack(spacing: 10) {
Text("Picker One")
.foregroundColor(.black)
Text(pickerData[pickerIndex])
.multilineTextAlignment(.center)
}
.foregroundColor(.white)
}
.frame(width: (UIScreen.main.bounds.width - (2.5 * 8 )) * 0.6 * 0.5, height: 100)
.background(Color.gray)
.cornerRadius(5)
}
#State private var testIndex = 1
var body: some View {
Menu {
Picker("", selection: self.$pickerIndex) {
ForEach(0..<pickerData.count, id: \.self) {index in
Text(pickerData[index])
}
}
} label: {
customLabel0
}
.onChange(of: pickerIndex, perform: {_ in
ContentView2(pickerIndex: $pickerIndex)
})
}
}
struct ContentView2: View {
#State var pickerData = ["Data1", "Data2"]
#Binding var pickerIndex: Int
var customLabel0: some View{
HStack {
VStack(spacing: 10) {
Text("Picker Two")
.foregroundColor(.black)
Text(pickerData[pickerIndex])
.multilineTextAlignment(.center)
}
.foregroundColor(.white)
}
.frame(width: (UIScreen.main.bounds.width - (2.5 * 8 )) * 0.6 * 0.5, height: 100)
.background(Color.gray)
.cornerRadius(5)
}
var body: some View {
Menu {
Picker("", selection: $pickerIndex) {
ForEach(0..<pickerData.count, id: \.self) {index in
Text(pickerData[index])
}
}
} label: {
customLabel0
}
.onChange(of: pickerIndex, perform: {_ in
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

TabView causing preview to crash

I am currently trying to make a featured games section in my app. I am using the TabView in SwiftUI to do this, but am running into an issue where the preview crashes from it. I am not getting any errors and also am unable to run it live. Below is the code of the view causing the preview crash.
import SwiftUI
struct FeaturedGamesView: View {
var numberOfImages: Int
#ObservedObject var featuredGames: GameQuery
#State private var currentIndex: Int = 0
private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
var body: some View {
VStack(alignment: .leading) {
Text("Featured")
.font(.headline)
.padding(.leading, 15)
.padding(.top, 1)
HStack(alignment: .top, spacing: 0) {
TabView() {
ForEach(featuredGames.games.results) { game in
NavigationLink(destination: NavigationLazyView(GameDetailsView(gameDetailsQuery: GameQuery(gameName: game.slug)))){
GameItem(game: game)
}
}
}
.offset(x: (CGFloat(self.currentIndex) * -185), y: 0)
.animation(.spring())
.onReceive(self.timer) { _ in
self.currentIndex = (self.currentIndex + 1) % 19
}
}
.frame(height: 200)
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}
struct FeaturedGamesView_Previews: PreviewProvider {
static var previews: some View {
FeaturedGamesView(numberOfImages: 3, featuredGames: GameQuery(gameCategory: GameCategory.featured))
}
}
From some of my experimentation it seems to either not like the observable object I am using to get an array of data to populate the tabview. Any help would be greatly appreciated.
Update: I created a simpler example which still produces the error. In this case everything is generic except the array being used which is an observable object. Switching out the data structure used in the ForEach fixes it, but am looking to understand why my observable object does not work here.
import SwiftUI
struct Test: View {
#State private var selection = 0
#ObservedObject var featuredGames: GameQuery
var body: some View {
VStack(alignment: .leading) {
Text("Featured")
.font(.headline)
.padding(.leading, 15)
.padding(.top, 1)
HStack {
TabView() {
ForEach(featuredGames.games.results) { game in
Text("Hi")
}
}.frame(height: 170)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .automatic))
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: some View {
Test(featuredGames: GameQuery(gameCategory: GameCategory.featured))
}
}
Please see below code.
I fixed below part to simple then it works.
Maybe this has a problem.
ForEach(featuredGames.games.results) { game in
NavigationLink(destination: NavigationLazyView(GameDetailsView(gameDetailsQuery: GameQuery(gameName: game.slug)))){
GameItem(game: game)
}
}
Working code (I made my self simple GameQuery observableObject)
import SwiftUI
struct FeaturedGamesView: View {
var numberOfImages: Int
#ObservedObject var featuredGames: GameQuery
#State private var currentIndex: Int = 0
private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
var body: some View {
VStack(alignment: .leading) {
Text("Featured")
.font(.headline)
.padding(.leading, 15)
.padding(.top, 1)
HStack(alignment: .top, spacing: 0) {
TabView() {
ForEach(featuredGames.results, id:\.self) { game in
NavigationLink(destination: VStack {}){
Text("Hello")
}
}
}
.offset(x: (CGFloat(self.currentIndex) * -185), y: 0)
.animation(.spring())
.onReceive(self.timer) { _ in
self.currentIndex = (self.currentIndex + 1) % 19
}
}
.frame(height: 200)
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}
final class GameQuery: ObservableObject {
var gameCagetory: Int = 0
var results: [Int] = [1,2,3]
}
struct FeaturedGamesView_Previews: PreviewProvider {
static var previews: some View {
FeaturedGamesView(numberOfImages: 3, featuredGames: GameQuery())
}
}

SwiftUI TabView not working, it just shows text off screen

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?