40
votes

I am trying to implement a animation for a rectangle to perform modal vertical swipe.However, when I try to compile the code I get the following error "Swift 4 Expression type '@value CGRect' is ambiguous without more context". I have isolated the issue to the arguments that is being passed to the CGRect init value, but according the Apple's iOS documentation these parameters should be enough to specify the 'frame' view that I need to animate.

Here is my code:

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    guard
        let fromView = transitionContext.viewController(forKey: .from),
        let toView = transitionContext.viewController(forKey: .to)

    else {
            return
    }
    let containerView = transitionContext.containerView
    containerView.insertSubview((toView.view)!, belowSubview: (fromView.view)!)

    let toFrame = transitionContext.finalFrame(for: toView)

    let screenBounds = UIScreen.main.bounds

    let bottomLeftCorner = CGPoint(x: 0, y: screenBounds.height)

    let finalFrameForVC = CGRect(origin: bottomLeftCorner, size: screenBounds.size)

    UIView.animate(withDuration: 2, delay: 1,
                   options: [], (using: transitionContext.finalFrame(for: fromView)),
        animations: {
            fromView.view.frame = finalFrameForVC
    },
        completion: { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    })
}
13
This problem belongs to data type, I tried to subtract value between CGFloat and Int types, later I converted both in to same type Ex: width: Int((filterView?.filterTblView.frame.width)!)-Int(width!) - iOS

13 Answers

44
votes

I had the same error when I tried to multiply view.frame.height by a Double. If you are doing any math on screenBounds properties, make sure the types match.

40
votes

My problem was that I was trying to perform an operation between a CGFloat variable and Double variable.

Fix: Convert the Double variable to CGFloat. Check your variable types.

I hope it helps! :)

15
votes

I got here looking for an answer to what was causing the error "Expression type '@lvalue CGRect' is ambiguous without more context", and while nothing here answered this for me I did find the solution to the problem so I'll leave it here for anyone else who stumbles on this question via Google. When creating your CGRect make sure to explicitly cast any ambiguous values to CGFloats (e.g. var width = CGFloat(100)) instead of relying on the compiler to infer the correct type/cast for you.

9
votes

This is a bug in XCode 10.1 which I am about to report.

let myHeight = CGFloat(100)

myHeight -= myView.frame.height

This produces the error:

"Expression type '@lvalue CGRect' is ambiguous without more context"

The error is wrong, the problem is that myHeight is a constant.

5
votes

For me, I was putting Int as CGRect height.

Xcode was mistakenly pointing to y with this error

Expression type '@value CGRect' is ambiguous without more context

enter image description here

Solution

Just implicitly define the height as CGFloat

let height:CGFloat = 100
4
votes

It's not your finalFrameForVC which rise the exception "'@value CGRect' is ambiguous without more context" but it's fromView.view.frame.

Fix it by declaring fromView.view explicitly as UIView :

UIView.animate(withDuration: 2, delay: 1, options: [], animations: {
      let view: UIView = fromView.view
      view.frame = finalFrameForVC as! CGRect
    }) { _ in
      transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    }
2
votes

The problem is your animation call which

  1. is incorrectly written
  2. the method does not exist

Reformatted:

UIView.animate(
   withDuration: 2,
   delay: 1,
   options: [],
   (using: transitionContext.finalFrame(for: fromView)),
   animations: {
     fromView.view.frame = finalFrameForVC
   },
   completion: { _ in            
     transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
   }
)

Note the (using: transitionContext.finalFrame(for: fromView)),. You cannot wrap a part of the method in parentheses including one of the external parameter names, it would have to be:

UIView.animate(
   withDuration: 2,
   delay: 1,
   options: [],
   using: transitionContext.finalFrame(for: fromView),
   animations: {
     fromView.view.frame = finalFrameForVC
   },
   completion: { _ in            
     transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
   }
)

That is what is causing the error. However, there is also no animation method with using: part, therefore I suppose it's just a copy-paste error and you actually want just:

UIView.animate(
   withDuration: 2,
   delay: 1,
   options: [],
   animations: {
     fromView.view.frame = finalFrameForVC
   },
   completion: { _ in            
     transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
   }
)
1
votes

I had the same problem just now. and i fix it like this:

enter image description here

and like the example above that: self.view must be assigned to another variable, ant the view should be force cast: view!, and then compile will work successfully.

1
votes

Really silly n00b answer,I had the same issue

"Expression type '@lvalue CGRect' is ambiguous without more context"

It was cause because I pressed return before CGFloat. Check to make sure it's on the same line. Hope this helps somebody.

0
votes

I received this error when I tried to create a CGRect and forgot to add .constant to the end of a variable name for an NSLayoutConstraint

0
votes

Like Rory Prior wrote above I got this error trying to make a CGPoint and I needed to specify that the parameters were CGFloat but I also needed to label the parameters x: and y: going into CGPoint so that CGPoint knew to expect CGFloat. Here's the code:

let topRight = CGPoint(x:CGFloat(cellTitleLabel.frame.maxX),y:CGFloat(cellTitleLabel.frame.minY))
0
votes

The example

myView.frame = CGRect(x: 0, y: 0, width: CGFloat(videoImaView.frame.width * CGFloat(0.4)), height: height)
0
votes

Explicitly declare a copy of the variable you want to change then assign it back.

func clickButton() {
    UIView.animateWithDuration(animationDuration, animations: {
        let buttonFrame = self.button.frame
        buttonFrame.origin.y = buttonFrame.origin.y - 1.0
        self.button.frame = buttonFrame
    }
}

credit to Rishi's answer here: https://stackoverflow.com/a/32133196/11683453