Ric*_*ich 6 parent call subview swiftui
我有一个子视图/子视图,它是父视图内实例的模板。该子视图 a 是可由用户在屏幕上移动的圆形。该圆圈的初始拖动应该调用父视图中的函数,该函数会附加子视图的新实例。基本上,最初将圆从其起始位置移动会在该起始位置创建一个新圆。然后,当您最初移动刚刚创建的新圆时,会在该起始位置再次创建另一个新圆,等等......
如何从子视图调用 ContentView 中的 addChild() 函数?
谢谢,我很感激任何帮助。
import SwiftUI
struct ContentView: View {
@State var childInstances: [Child] = [Child(stateBinding: .constant(.zero))]
@State var childInstanceData: [CGSize] = [.zero]
@State var childIndex = 0
func addChild() {
self.childInstanceData.append(.zero)
self.childInstances.append(Child(stateBinding: $childInstanceData[childIndex]))
self.childIndex += 1
}
var body: some View {
ZStack {
ForEach(childInstances.indices, id: \.self) { index in
self.childInstances[index]
}
ForEach(childInstanceData.indices, id: \.self) { index in
Text("y: \(self.childInstanceData[index].height) : x: \(self.childInstanceData[index].width)")
.offset(y: CGFloat((index * 20) - 300))
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Run Code Online (Sandbox Code Playgroud)
import SwiftUI
struct Child: View {
@Binding var stateBinding: CGSize
@State var isInitalDrag = true
@State var isOnce = true
@State var currentPosition: CGSize = .zero
@State var newPosition: CGSize = .zero
var body: some View {
Circle()
.frame(width: 50, height: 50)
.foregroundColor(.blue)
.offset(self.currentPosition)
.gesture(
DragGesture()
.onChanged { value in
if self.isInitalDrag && self.isOnce {
// Call function in ContentView here... How do I do it?
ContentView().addChild()
self.isOnce = false
}
self.currentPosition = CGSize(
width: CGFloat(value.translation.width + self.newPosition.width),
height: CGFloat(value.translation.height + self.newPosition.height)
)
self.stateBinding = self.currentPosition
}
.onEnded { value in
self.newPosition = self.currentPosition
self.isOnce = true
self.isInitalDrag = false
}
)
}
}
struct Child_Previews: PreviewProvider {
static var previews: some View {
Child(stateBinding: .constant(.zero))
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我要做的,我将在第二个视图中创建一个函数并在任何情况下调用它,比如当按下第二个视图中的按钮时调用此函数。我会在主视图中传递函数的回调。
这是一个代码来演示我的意思。
import SwiftUI
struct StackOverflow23: View {
var body: some View {
VStack {
Text("First View")
Divider()
// Note I am presenting my second view here and calling its function ".onAdd"
SecondView()
// Whenever this function is invoked inside `SecondView` then it will run the code in between these brackets.
.onAdd {
print("Run any function you want here")
}
}
}
}
struct StackOverflow23_Previews: PreviewProvider {
static var previews: some View {
StackOverflow23()
}
}
struct SecondView: View {
// Define a variable and give it default value
var onAdd = {}
var body: some View {
Button(action: {
// This button will invoke the callback stored in the variable, this can be invoked really from any other function. For example, onDrag call self.onAdd (its really up to you when to call this).
self.onAdd()
}) {
Text("Add from a second view")
}
}
// Create a function with the same name to keep things clean which returns a view (Read note 1 as why it returns view)
// It takes one argument which is a callback that will come from the main view and it will pass it down to the SecondView
func onAdd(_ callback: @escaping () -> ()) -> some View {
SecondView(onAdd: callback)
}
}
Run Code Online (Sandbox Code Playgroud)
注意 1:我们的函数返回视图的原因onAdd是因为请记住 swiftui 仅基于视图,并且每个修饰符都会返回一个视图本身。例如,当您有一个Text("test")然后添加.foregroundColor(Color.white)到它时,本质上您所做的是不修改文本的颜色,而是使用Text自定义foregroundColor值创建一个新的颜色。
这正是我们正在做的,我们正在创建一个可以在调用时初始化的变量SecondView,但我们不是在初始化程序中调用它,而是将其创建为函数修饰符,它将返回一个SecondView带有自定义值的新实例给我们的变量。
我希望这是有道理的。如果您有任何疑问,请随时询问。
这是修改后的代码:
内容视图.swift
import SwiftUI
struct ContentView: View {
@State var childInstances: [Child] = [Child(stateBinding: .constant(.zero))]
@State var childInstanceData: [CGSize] = [.zero]
@State var childIndex = 0
func addChild() {
self.childInstanceData.append(.zero)
self.childInstances.append(Child(stateBinding: $childInstanceData[childIndex]))
self.childIndex += 1
}
var body: some View {
ZStack {
ForEach(childInstances.indices, id: \.self) { index in
self.childInstances[index]
.onAddChild {
self.addChild()
}
}
ForEach(childInstanceData.indices, id: \.self) { index in
Text("y: \(self.childInstanceData[index].height) : x: \(self.childInstanceData[index].width)")
.offset(y: CGFloat((index * 20) - 300))
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Run Code Online (Sandbox Code Playgroud)
儿童.swift
import SwiftUI
struct Child: View {
@Binding var stateBinding: CGSize
@State var isInitalDrag = true
@State var isOnce = true
@State var currentPosition: CGSize = .zero
@State var newPosition: CGSize = .zero
var onAddChild = {} // <- The variable to hold our callback
var body: some View {
Circle()
.frame(width: 50, height: 50)
.foregroundColor(.blue)
.offset(self.currentPosition)
.gesture(
DragGesture()
.onChanged { value in
if self.isInitalDrag && self.isOnce {
// Call function in ContentView here... How do I do it?
self.onAddChild() <- // Here is your solution
self.isOnce = false
}
self.currentPosition = CGSize(
width: CGFloat(value.translation.width + self.newPosition.width),
height: CGFloat(value.translation.height + self.newPosition.height)
)
self.stateBinding = self.currentPosition
}
.onEnded { value in
self.newPosition = self.currentPosition
self.isOnce = true
self.isInitalDrag = false
}
)
}
// Our function which will initialize our variable to store the callback
func onAddChild(_ callaback: @escaping () -> ()) -> some View {
Child(stateBinding: self.$stateBinding, isInitalDrag: self.isInitalDrag, isOnce: self.isOnce, currentPosition: self.currentPosition, newPosition: self.newPosition, onAddChild: callaback)
}
}
struct Child_Previews: PreviewProvider {
static var previews: some View {
Child(stateBinding: .constant(.zero))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3916 次 |
| 最近记录: |