Cannot Assign Value of Type 'Menuview' to Type 'some View'

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 Views 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 store ObservableObject.
  • @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



Leave a reply



Submit