Sorry for the novice question.
But just as the title says, I can't seem to use these functions in Swift 3. I have tried by importing the CoreGraphics library, but to no avail.
Does anyone know why?
Thanks in advance.
The functions are working fine, but their names have changed (a bit):
let frame = CGRect.zero
let x = frame.integral
frame.insetBy(dx: 0, dy: 0)
import CoreGraphics
let rect = CGRect()
let rectIntegral = rect.integral
Thanks:)
Actually you don't need to import CoreGraphics.
In Swift 3 Objective-C function
CGRect CGRectIntegral(CGRect rect)
has become
var integral: CGRect { get }
and
CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy);
has become
func insetBy(dx: CGFloat, dy: CGFloat) -> CGRect
Both API have to be called on the CGRect instance for example
let newFrame = view.frame.insetBy(dx: 10.0, dy:10.0)
A hint to find out yourself
Press ⇧⌘0
Type CGRectIn in the search field
In the popup menu set the language to Objective C
Select one of the functions
Set the language to Swift
Related
It's easy to blur a portion of the view, keeping in mind that if the contents of views behind change, the blur changes too in realtime.
My questions
How to make an invert effect, and you can put it over a view and the contents behind would have inverted colors
How to add an effect that would know the average color of the pixels behind?
In general, How to access the pixels and manipulate them?
My question is not about UIImageView, asking about UIView in general..
there are libraries that does something similar, but they are so slow and don't run as smooth as blur!
Thanks.
If you know how to code a CIColorKernel, you'll have what you need.
Core Image has several blur filters, all of which use the GPU, which will give you the performance you need.
The CIAreaAverage will give you the average color for a specified rectangular area.
Core Image Filters
Here is about the simplest CIColorKernel you can write. It swaps the red and green value for every pixel in an image (note the "grba" instead of "rgba"):
kernel vec4 swapRedAndGreenAmount(__sample s) {
return s.grba;
}
To put this into a CIColorKernel, just use this line of code:
let swapKernel = CIKernel(string:
"kernel vec4 swapRedAndGreenAmount(__sample s) {" +
"return s.grba;" +
"}"
#tww003 has good code to convert a view's layer into a UIImage. Assuming you call your image myUiImage, to execute this swapKernel, you can:
let myInputCi = CIImage(image: myUiImage)
let myOutputCi = swapKernel.apply(withExtent: myInputCi, arguments: myInputCi)
Let myNewImage = UIImage(ciImage: myOutputCi)
That's about it. You can do alot more (including using CoreGraphics, etc.) but this is a good start.
One last note, you can chain individual filters (including hand-written color, warp, and general kernels). If you want, you can chain your color average over the underlying view with a blur and do whatever kind of inversion you wish as a single filter/effect.
I don't think I can fully answer your question, but maybe I can point you in the right direction.
Apple has some documentation on accessing the pixels data from CGImages, but of course that requires that you have an image to work with in the first place. Fortunately, you can create an image from a UIView like this:
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
From this image you created, you'll be able to manipulate the pixel data how you want to. It may not be the cleanest way to solve your problem, but maybe it's something worth exploring.
Unfortunately, the link I provided is written in Objective-C and is a few years old, but maybe you can figure out how to make good use of it.
1st I will recommend you to extend UIImageView for this purpose. ref
Good ref by Joe
You have to override drawRect method
import UIKit
#IBDesignable class PortholeView: UIView {
#IBInspectable var innerCornerRadius: CGFloat = 10.0
#IBInspectable var inset: CGFloat = 20.0
#IBInspectable var fillColor: UIColor = UIColor.grayColor()
#IBInspectable var strokeWidth: CGFloat = 5.0
#IBInspectable var strokeColor: UIColor = UIColor.blackColor()
override func drawRect(rect: CGRect) {
super.drawRect(rect:rect)
// Prep constants
let roundRectWidth = rect.width - (2 * inset)
let roundRectHeight = rect.height - (2 * inset)
// Use EvenOdd rule to subtract portalRect from outerFill
// (See https://stackoverflow.com/questions/14141081/uiview-drawrect-draw-the-inverted-pixels-make-a-hole-a-window-negative-space)
let outterFill = UIBezierPath(rect: rect)
let portalRect = CGRectMake(
rect.origin.x + inset,
rect.origin.y + inset,
roundRectWidth,
roundRectHeight)
fillColor.setFill()
let portal = UIBezierPath(roundedRect: portalRect, cornerRadius: innerCornerRadius)
outterFill.appendPath(portal)
outterFill.usesEvenOddFillRule = true
outterFill.fill()
strokeColor.setStroke()
portal.lineWidth = strokeWidth
portal.stroke()
}
}
Your answer is here
As CGRectMake is not available in swift 3.0 and migrator did not convert it i need to manually replace it and it is used more than 300 times in my code so can anyone help me in this to develop regular expression so i can find and replace code. What i want to do is to convert
CGRectMake(a,a,a,a) here a is some value.
to
CGRect(x: a, y: a, w: a, h: a)
Find by this:
CGRectMake\(([^,]*),([^,]*),([^,]*),([^,]*)\)
and Replace by this:
CGRect\(x:\1, y:\2, w:\3, h:\4\)
Tried it in notepad++
EDIT - With Regex:
CGRectMake\(([^,]*),([^,]*),([^,]*),([a-z|0-9|.|A-Z]*)\)
and replace with
CGRect\(x:\1, y:\2, width:\3, height:\4\)
Using regex we can not get the value of x,y,width,height dynamically.
So Alternative solution to above is,
Replace all the CGRectMake( with
appdelegateobject.CGRectMakeWrapper("
At the end add " only.
Means in your case you will replace CGRectMake(a,a,a,a) to appdelegateobject.CGRectMakeWrapper("a,a,a,a"
where appdelegateobject is the appdelegate shared instance object where you will define CGRectMakeWrapper function having string parameter as shown below :
func CGRectMakeWrapper(str: String) -> CGRect {
var rect = CGRectZero
if(str.characters.count > 0)
{
var arr = str.componentsSeparatedByString(",")
if(arr.count == 4)
{
rect = CGRect(x: CGFloat((arr[0] as NSString).doubleValue), y: CGFloat((arr[1] as NSString).doubleValue), width: CGFloat((arr[2] as NSString).doubleValue), height: CGFloat((arr[3] as NSString).doubleValue))
}
}
return rect
}
var rect = "10.0,10.0,100,100" //String
var rect1 = CGRectMakeWrapper(rect) //CGRect
I have shown sample string as rect and passed to CGRectMakeWrapper function which will return a rect. You can define this CGRectMakeWrapper function in common class which is accessible to all classes(e.g Appdelegate file).
I have one different way to solve this problem.
Step 1
In the following line
CGRectMake(a,a,a,a)
Just replace CGRectMake with CGRectMakeCustom so all will look like
CGRectMakeCustom(a,a,a,a)
Step 2
Create new Global function in the project
as follows
func CGRectMakeCustom(x: Double, y: Double, width: Double, height: Double) -> CGRect
{
return CGRect(x: x, y: y, width: width, height: height)
}
In this way it will be easy for you to start woking on Swift3
You can change mode to regular expression while searching and search for:
CGRectMake\(([^,]*),([^,]*),([^,]*),([^,]*)\)
which should be replaced by
CGRect\(x:\1, y:\2, w:\3, h:\4\)
Now that CGRectMake , CGPointMake, CGSizeMake, etc. has been removed in Swift 3.0, is there any way to automatically update all initializations like from CGRectMake(0,0,w,h) to CGRect(x:0,y:0,width:w,height:h). Manual process is.. quite a pain.
Not sure why Apple don't auto convert this when I convert the code to Current Swift Syntax...
The simplest solution is probably just to redefine the functions Apple took away. Example:
func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
return CGRect(x: x, y: y, width: width, height: height)
}
Put that in your module and all calls to CGRectMake will work again.
Short answer: don't do it. Don't let Apple boss you around. I hate CGRect(x:y:width:height:). I've filed a bug on it. I think the initializer should be CGRect(_:_:_:_:), just like CGRectMake. I've defined an extension on CGRect that supplies it, and plop that extension into every single project the instant I start.
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
That way, all I have to do is change "CGRectMake" to "CGRect" everywhere, and I'm done.
Apple actually does provide this feature. All you have to do is go to:
Edit > Convert > To Latest Swift Syntax...
And then follow the onscreen prompts.
This will solve your syntax issues and you won't have to make new functions for all of the various removed functions.
This question is inspired by Andrew Carter's comment on a previous question about the new CGSize initializer in Swift.
The Apple Docs for CGGeometry say:
... your applications
should avoid directly reading and writing the data stored in the
CGRect data structure. Instead, use the functions described here to
manipulate rectangles and to retrieve their characteristics.
Is Apple's recommendation to not directly access the data in a CGRect still valid with Swift? Why should CGRectGetMidX, CGRectGetWidth, etc. be used in place of accessing the values of a CGRect struct directly, when these properties are now exposed with Swift's new extension on CGRect?
Consider a non-standard CGRect with a negative width and height:
var rect = CGRect(x: 0.0, y: 0.0, width: -10.0, height: -10.0)
This is a valid rectangle according to the Apple docs, as "a rectangle with an origin of [0.0, 0.0] and a size of [10.0, 10.0] is exactly equivalent to a rectangle with an origin of [10.0, 10.0] and a size of [-10.0, -10.0]."
You can standardize this CGRect by calling the legacy inline CGRectStandardize method like in Objective-C, or any of the new methods provided on the Swift extension of CGRect:
CGRectStandardize(rect) // {x -10 y -10 w 10 h 10}
rect.standardized // {x -10 y -10 w 10 h 10}
rect.standardizeInPlace() // {x -10 y -10 w 10 h 10}
But wait! This will reposition your rect on the coordinate plane, not only making your width and height positive, but making your origin negative to reflect the initial position of the rect with its negative width and height.
The inline CGRectGet functions provide an interface to normalize a specific value of your rect, without changing its origin. Swift provides an extension on CGRect so you can access the normalized values directly, rather than using the legacy C methods provided by CGGeometry:
var rect = CGRect(x: 0.0, y: 0.0, width: -10.0, height: -10.0)
rect.size.width // non-normalized, returns -10
CGRectGetWidth(rect) // bridged C function, normalized, returns 10
rect.width // new from Swift extension on CGRect, normalized, returns 10
The new interfaces:
extension CGRect {
// ...
public var width: CGFloat { get }
public var height: CGFloat { get }
public var minX: CGFloat { get }
public var midX: CGFloat { get }
public var maxX: CGFloat { get }
public var minY: CGFloat { get }
public var midY: CGFloat { get }
public var maxY: CGFloat { get }
// ...
}
So the answer is yes, the same rules for CGRect in Objective-C apply in Swift as well. The only difference here is that Swift provides an extension on some CGGeometry structs which allow you to move away from the old inline C functions bridged from the CGGeometry headers.
In Swift 3, it looks like CGRectGetWidth() is replaced by CGRect.width.
For an App I'm making i need to use variables to change the size and position of objects (Labels). I've tried var example = CGRectMake(0, 0, 0, 100), hoping it would ignore the zeros (Not really thinking it would though). I then tried:
var example = 100
Label1.frame = CGRectMake(20, 20, 50, example)
I changed the syntax a bit, adding "" and replacing the CGRectMake with CGRect etc, but nothing worked... I don't get what I'm doing wrong here... Help!
Below is the new syntax used since Swift 3.
CGRect(x: 0, y: 0, width: 100, height: 100)
CGRectMake takes CGFloats for all of its arguments. Your sample code should work fine if you specify that example is supposed to be a CGFloat, using a type identifier:
// v~~~~ add this...
var example: CGFloat = 100
Label1.frame = CGRectMake(20, 20, 50, example)
Otherwise, swift infers the type of example to be Int, and the call to CGRectMake fails, cuz it can't take an Int as a parameter...
So, there is many ways to skin the cat. It all depends what your needs and requirements are (maybe you could elaborate a bit on what you are trying to achieve?). But one way to do it could be to set a variable when something happens, and then update the frame of the label. If you added a tap gesture recognizer to your view, and updated your label like so:
let myLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
let tapGestRecog = UITapGestureRecognizer(target: self, action: "handleTap:")
self.view.addGestureRecognizer(tapGestRecog)
}
func handleTap(sender:UIGestureRecognizer) {
let newXposition = sender.locationInView(self.view).x
let newYposition = sender.locationInView(self.view).y
myLabel.frame = CGRectMake(newXposition, newYposition, 200, 200)
}
This is just an example, and a very crude way of doing it. There are many other ways of doing it, but it hopefully gives you an idea of how to achieve it.
Swift allows syntax that Objective-C does not:
var example = 100
label.frame.size.height = example
In objective-C you would have to do it differently:
CGRect frame = label.frame; //Create a temporary rect to hold the frame value
frame.size.height = example;
label.frame = frame;