Cannot assign value of type 'MenuView' to type 'some View'
The solution was to use AnyView
:
@State private var popover: AnyView
Then it can be assigned as:
self.popover = AnyView(CreateChannelView(showing: self.$showPopover))
Cannot assign value of type 'some View' to type 'some View'
Instead of
var result = p.fill(Color.red)
result = result.frame(width: 100, height: 100)
use directly combined view as
return p.fill(Color.red).frame(width: 100, height: 100)
The some View
means some opaque concrete view type but to use assignment the type must be the same however modifiers .fill
and .frame
produce different concrete types, that's why your assignment generated error.
Cannot assign value of type 'V' to type some 'Protocol'
var contentView: some MyProtocol = MyView()
So the type of contentView
is "some specific, secret (opaque) type, unknown to anything but the compiler, that conforms to MyProtocol, and also happens to be exactly MyView, even though nothing can know that." It's not "something that conforms to MyProtocol" which it seems maybe you're thinking it is. If you mean that, the syntax is:
var contentView: MyProtocol = MyView()
The point of some
is that the type is statically known at compile-time by the compiler, but not known to the caller, or by anything else.
For example, even this would fail:
var contentView: some MyProtocol = MyView()
contentView = MyView() // Cannot assign value of type 'MyView' to type 'some MyProtocol'
The compiler will not prove that MyView is exactly the secret type that contentView
used. (For most errors of this type I'd say the compiler "cannot prove," but in this case, it's an active decision to forbid proving the fact because that's what some
does.)
That "secret" type is carried along, however, and is well defined, it's just opaque. For example, the following is fine:
var contentView: some MyProtocol = MyView()
let otherView = contentView // otherView is definitely the same as as contentView
contentView = otherView // so it can be assigned
At first pass, I expect the code you want is just the above var contentView: MyProtocol
, but it's very possible you have a deeper misunderstanding about SwiftUI. You cannot just swap in arbitrary Views in SwiftUI. As a rule, everything should be decided at compile-time, not runtime. There are tools like AnyView to work around this, but generally should not be your first choice. I expect there's a deeper design problem here that isn't in your question.
For more details of opaque types, see SE-244.
How to pass one SwiftUI View as a variable to another View struct
To sum up everything I read here and the solution which worked for me:
struct ContainerView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
}
}
This not only allows you to put simple View
s inside, but also, thanks to @ViewBuilder
, use if-else
and switch-case
blocks:
struct SimpleView: View {
var body: some View {
ContainerView {
Text("SimpleView Text")
}
}
}
struct IfElseView: View {
var flag = true
var body: some View {
ContainerView {
if flag {
Text("True text")
} else {
Text("False text")
}
}
}
}
struct SwitchCaseView: View {
var condition = 1
var body: some View {
ContainerView {
switch condition {
case 1:
Text("One")
case 2:
Text("Two")
default:
Text("Default")
}
}
}
}
Bonus:
If you want a greedy container, which will claim all the possible space (in contrary to the container above which claims only the space needed for its subviews) here it is:
struct GreedyContainerView<Content: View>: View {
@ViewBuilder let content: Content
var body: some View {
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
If you need an initializer in your view then you can use @ViewBuilder
for the parameter too. Even for multiple parameters if you will:
init(@ViewBuilder content: () -> Content) {…}
How do you assign a String?-type object to a String-type variable?
You'll have to first make sure that the variable doesn't in fact contain nil
. You can do that in a number of ways -- might be good to read:
- Swift: Testing optionals for nil
- https://www.hackingwithswift.com/articles/136/the-complete-guide-to-optionals-in-swift
- https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html
One way is by optional binding:
if let myVariable = myDictionary["key"] {
Text(myVariable)
}
Another is to provide an default value:
Text("My result: \(myDictionary["key"] ?? "default value")
There are other possibilities, but these, plus the links above, should get you started.
SwiftUI binding boolean if statement (Cannot convert value of type 'BindingBool' to expected condition type 'Bool')
Found a way around it. Embedded the NavigationView
in a VStack
and added the menuView
to the end of it.
struct ContentView: View {
@State private var menuActivated = false
var body: some View {
ZStack {
NavigationView {
... // view code
}
if menuActivated {
menuView()
}
}
}
}
Swift, value not updated
@State
is used for changes inside within view@ObservedObject
is used to storeObservableObject
.@Published
publishes when@Published var
changes itself.
with this knowledge, here is the answer.
import SwiftUI
struct ContentView: View {
@State private var selectedTab = 0
let numTabs = 2
let minDragTranslationForSwipe: CGFloat = 50
var body: some View {
TabView(selection: $selectedTab){
NavigationView{
MenuView()
.navigationBarTitle("Settings")
}
.tabItem {
Image("map")
Text("Map")
}.tag(0)
.highPriorityGesture(DragGesture().onEnded({
self.handleSwipe(translation: $0.translation.width)
}))
NavigationView{
MenuView()
.navigationBarTitle("Settings")
}
.tabItem {
Image("navigation")
Text("Navigation")
}.tag(1)
.highPriorityGesture(DragGesture().onEnded({
self.handleSwipe(translation: $0.translation.width)
}))
}
}
private func handleSwipe(translation: CGFloat) {
if translation > minDragTranslationForSwipe && selectedTab > 0 {
selectedTab -= 1
} else if translation < -minDragTranslationForSwipe && selectedTab < numTabs-1 {
selectedTab += 1
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct MenuView : View {
@ObservedObject var myMaze = Maze()
@State private var isEditing1 = false
@State private var isEditing2 = false
//@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body : some View {
HStack(alignment: VerticalAlignment.top) {
VStack(alignment: .leading) {
Text("Number of rooms (horizontally): \(myMaze.widthDouble, specifier: "%.0f")")
.foregroundColor(isEditing1 ? .red : .black)
Slider(value: $myMaze.widthDouble, in: 3...33, step: 1,
onEditingChanged: { editing in isEditing1 = editing })
Divider()
// format: "Angle: %.0f", angle
Text("Number of rooms (vertically): \(myMaze.heightDouble, specifier: "%.0f")")
.foregroundColor(isEditing2 ? .red : .black)
Slider(value: $myMaze.heightDouble, in: 3...33, step: 1,
onEditingChanged: { editing in isEditing2 = editing })
Divider()
Toggle("One way", isOn: $myMaze.oneWay)
Button(action: { action() }) { Text("Build maze with updated values") }
} .padding()
}
}
func action() {
}
}
import Foundation
import SwiftUI
let wall = (North: 1, East: 2, South: 4, West: 8) // 15 means all walls
let exit = (toNorth: 16, toEast: 32, toSouth: 64, toWest: 128) // 0 means no exit
struct Room {
var x: Int
var y: Int
var roomsToExit: Int
}
class Maze: ObservableObject {
@Published var height = 12
@Published var widthDouble = 9.0 {
didSet {
setMezData(height: Int(heightDouble), width: Int(widthDouble))
}
}
@Published var heightDouble = 12.0 {
didSet {
setMezData(height: Int(heightDouble), width: Int(widthDouble))
}
}
@Published var oneWay = true
@Published var exitRoom = Room(x: 0, y: 0, roomsToExit: 0)
@Published var farestRoom = Room(x: 0, y: 0, roomsToExit: 0)
@Published var mazeData = [[Int]]() {
didSet {
print(mazeData)
}
}
var numberOfRooms: Int { return Int(heightDouble) * Int(widthDouble) }
func setMezData(height: Int, width: Int) {
mazeData = Array(repeating: Array(repeating: 15, count: height), count: width)
}
}
Make variables not reset when switching to a different view controller, and keep the variable like that when app is quit
You could implemente a Singleton, that's a class that has only 1 instance and is meant to be kept in memory for different uses. You can implement it like this:
class MetricManager {
static let sharedInstance = MetricManager()
var currentUnit: String = "imperial"
private init() {
}
}
After that you can simply assign a value on Settings VC like this
@IBAction func unitSwitcherMetric(_ sender: UIButton) {
MetricManager.sharedInstance.currentUnit = "metric"
}
And then on Menu or wherever you want to get the current unit value, you just consult it on:
MetricManager.sharedInstance.currentUnit
Error with custom transition on loading UIView in Swift
DetailedView is not a ViewController but you are forcing it to be one.
Change the !
in as! DetailedView
to as? DetailedView
and the rest should speak for themselves.
here's the code
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView()
// create a tuple of our screens
let screens : (from:UIViewController, to:UIViewController) = (transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!, transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!)
// assign references to our menu view controller and the 'bottom' view controller from the tuple
// remember that our menuViewController will alternate between the from and to view controller depending if we're presenting or dismissing
//Changed the ! to ?
let menuViewController = !self.presenting ? screens.from as? DetailedView : screens.to as? DetailedView
let topViewController = !self.presenting ? screens.to as UIViewController : screens.from as UIViewController
let menuView = menuViewController?.view
let topView = topViewController.view
// prepare menu items to slide in
if (self.presenting){
//self.offStageMenuControllerInteractive(menuViewController) // offstage for interactive
}
// add the both views to our view controller
container.addSubview(menuView!)
container.addSubview(topView)
//THROWS unexpected nil value while unwrapping.
//container.addSubview(self.statusBarBackground)
let duration = self.transitionDuration(transitionContext)
// perform the animation!
UIView.animateWithDuration(duration, delay: 0.0, options: .CurveEaseInOut , animations: {
if (self.presenting){
self.onStageMenuController(menuViewController!) // onstage items: slide in
topView.transform = CGAffineTransformMakeTranslation(-container.frame.width, 0)
}
else {
topView.transform = CGAffineTransformIdentity
self.offStageMenuControllerInteractive(menuViewController!)
}
}, completion: { finished in
// tell our transitionContext object that we've finished animating
if(transitionContext.transitionWasCancelled()){
transitionContext.completeTransition(false)
// bug: we have to manually add our 'to view' back http://openradar.appspot.com/radar?id=5320103646199808
UIApplication.sharedApplication().keyWindow!.addSubview(screens.from.view)
}
else {
transitionContext.completeTransition(true)
// bug: we have to manually add our 'to view' back http://openradar.appspot.com/radar?id=5320103646199808
UIApplication.sharedApplication().keyWindow!.addSubview(screens.to.view)
}
//THROWS unexpected nil value while unwrapping.
// UIApplication.sharedApplication().keyWindow!.addSubview(self.statusBarBackground)
})
}
Related Topics
Swift Compound Arithmetic Operation Error
Osx/Swift: Call Function at a Specific Date/Time
Automatic Select a Date in Datepicker in Swift Language
Using a Swiftui List Sidebar in a UIsplitviewcontroller
Swift - Rotate Gesture and Rotation Increments of 90 Degrees
Animate Line Under One Button to Another
Adding a UIvisualeffectview to Button
How to Determine Whether a Double Is an Integer
Uibutton State Changing While Scrolling The Tableview with Multiple Sections - Swift
Swift: Gradient Splits on Rotation
Cllocationmanager and Tvos - Requestwheninuseauthorization() Not Prompting
How to Get Parallax Effect on UIbutton in Tvos
Nsnumber/Nsdecimalnumber Bizarre Behavior
Spritekit Skscene Not Resizing Correctly to Fit iPhone 12