Callback from onTapGesture Through Framework

I've found a simple example at YouTube (https://www.youtube.com/watch?v=ddp1jwkDwr8) as to create a framework.

The following example does NOT use a framework.

import SwiftUI

struct ContentView: View {
    @State private var selectedColor: Color = .clear
    
    var body: some View {
        VStack {
            ColorSelectorView(selectedColor: $selectedColor) { color in
                print("**** \(color)")
            }
        }
    }
}
import SwiftUI

struct ColorSelectorView: View {
    @Binding var selectedColor: Color
    @State var callBack: ((Color) -> Void)?
    let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]

    var body: some View {
        HStack {
            ForEach(colors, id: \.self) { color in
                Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
                    .foregroundColor(color)
                    .onTapGesture {
                        selectedColor = color
                        callBack?(color)
                    }
            }
        }
    }
}

#Preview {
    ColorSelectorView(selectedColor: .constant(.red))
}

If I select a color, ContentView will receive a call back as to which color has been selected. So far, so good...

Now, I want to make the ColorSelectorView part a framework. ContentView doesn't change. The following is the framework part.

import SwiftUI

public struct ColorSelectorView: View {
	@Binding var selectedColor: Color
	@State var callBack: ((Color) -> Void)?
	let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]

	public init(selectedColor: Binding<Color>, callBack: ((Color) -> Void)? = nil) {
		self._selectedColor = selectedColor
		self.callBack = callBack
	}
	
	public var body: some View {
		HStack {
			ForEach(colors, id: \.self) { color in
				Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
					.foregroundColor(color)
					.onTapGesture {
						selectedColor = color
						callBack?(color)
					}
			}
		}
	}
}

struct ColorSelectorView_Previews: PreviewProvider {
	static var previews: some View {
		ColorSelectorView(selectedColor: .constant(.red))
	}
}

Running ContentView with a framework, it doesn't receive a call back. What am I doing wrong? Muchos thankos.

Accepted Reply

I've removed the optional part in the framework as follows. And it works. I don't know why the callBack guy can't be optional, though, in the framework.

import SwiftUI

public struct ColorSelectorView: View {
	@Binding var selectedColor: Color
	@State var callBack: ((Color) -> Void)
	let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]

	public init(selectedColor: Binding<Color>, callBack: @escaping ((Color) -> Void)) {
		self._selectedColor = selectedColor
		self.callBack = callBack
	}
	
	public var body: some View {
		HStack {
			ForEach(colors, id: \.self) { color in
				Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
					.foregroundColor(color)
					.onTapGesture {
						selectedColor = color
						callBack(color)
					}
			}
		}
	}
}

Replies

I've removed the optional part in the framework as follows. And it works. I don't know why the callBack guy can't be optional, though, in the framework.

import SwiftUI

public struct ColorSelectorView: View {
	@Binding var selectedColor: Color
	@State var callBack: ((Color) -> Void)
	let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]

	public init(selectedColor: Binding<Color>, callBack: @escaping ((Color) -> Void)) {
		self._selectedColor = selectedColor
		self.callBack = callBack
	}
	
	public var body: some View {
		HStack {
			ForEach(colors, id: \.self) { color in
				Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
					.foregroundColor(color)
					.onTapGesture {
						selectedColor = color
						callBack(color)
					}
			}
		}
	}
}