how to set frame dynamically in swift? - ios

i am trying to set imageview as subview for scrollview.for that i am setting different frame depends upon the screensize.
This is my code
let screensize:CGRect=UIScreen.mainScreen().bounds
let screenwidth=screensize.width
var frames:CGRect
for var index=0 ;index < arrBirds.count ;index++
{
if(screenwidth==320)
{
frames.origin.x = CGFloat(index) * (self.view.frame.size.width);
frames.origin.y = 0;
frames.size=scrollview.frame.size;
}
else if(screenwidth==375)
{
frames.origin.x = CGFloat(index) * (self.view.frame.size.width);
frames.origin.y=0;
frames.size=scrollview.frame.size;
}
else
{
frames.origin.x = CGFloat(index) * (self.view.frame.size.width);
frames.origin.y=0;
frames.size=scrollview.frame.size;
}
imageView=UIImageView(frame:frames)
imageView.image=UIImage(named: arrBirds[index] as! String)
scrollview .addSubview(imageView)
But i am getting error this line
frames.origin.x = CGFloat(index) * (self.view.frame.size.width);//struct frame must be completely initialised before a member is stored to.

You have not yet created an instance of the struct CGRect yet. Before accessing / setting any members on it you you need to create a instance first and only after that set the different members of it:
Change the line var frames:CGRect to:
var frames = CGRectZero

According to Apple Docs :
Classes and structures must set all of their stored properties to an
appropriate initial value by the time an instance of that class or
structure is created.
Your frames object isn't initialized, instead you should write :
var frames = CGRectZero

Related

Avoid redundant dereferencing in iOS

Suppose I want to change size of an uiView: UIView to w,h. I can do it like that:
uiView.frame.size.width = w
uiView.frame.size.height = h
In another system I can avoid replication of dereferencing (which means waste of both size and performance) by keeping a reference in a variable (using Swift syntax):
let ref = uiView.frame.size
ref.width = v
ref.height = h
This however doesn't work in iOS, where CGSize is a structure and therefore is copied when assigned to another value.
Is there a way to avoid redundant dereferencing (something like with(uiView.frame.size){...} available in some languages)
I don't think there is a way to do it exactly because the frame is a value-copied structure. You could set the frame directly as Reiner Melian suggests, but to me that seems even longer and uses dereferencing at least the same amount of time as your approach.
There is a way how to make it simpler this using extensions, but behind the scenes it will again be using dereferencing:
extension UIView {
var width: CGFloat {
get {
return self.frame.size.width
}
set {
self.frame.size.width = newValue
}
}
var height: CGFloat {
get {
return self.frame.size.height
}
set {
self.frame.size.height = newValue
}
}
}
And then you could use:
uiView.width = w
uiView.height = h
on any UIView instance.
This is even simpler:
uiView.frame.size = CGSize(width: w, height: h)
As I understand it, RHS is a temporary value released as soon as the content has been copied to frame structure.

swift: cannot assign value of type UIView to type CGRect

In the for loop I am trying to place images from arrayOfImages in rectangles that I've created with CGRect.
But after that I want to use class MyClassView which inherits UIView, because I have there additional functions that I want to apply on my rectangle images that I've just created, but I am getting the error
cannot assign value of type UIView to type CGRect
let widthRect = 50
func createMyRects(){
let insetSize = CGRectInset(self.view.bounds, CGFloat(Int(widthRect)), CGFloat(Int(widthRect))).size
for i in 0...arrayOfImages.count-1{
let pointX = CGFloat(UInt(arc4random() % UInt32(UInt(insetSize.width))))
let pointY = CGFloat(UInt(arc4random() % UInt32(UInt(insetSize.height))))
let showImages = UIImageView(image: arrayOfImages[i])
let newFrame = CGRect(x: pointX, y: pointY, width: CGFloat(widthRect), height: CGFloat(widthRect))
//showImages.frame = newFrame
let newFrame2 = MyClassView(frame: newFrame)
showImages.frame = newFrame2 //here it says: cannot assign value of type UIView view to type CGRect
view.addSubview(showImages)
}
}
To fix the error you need to assign the frame of your UIView subclass to the frame.
showImages.frame = newFrame2.frame
Your variable names are a bit misleading.
Justin gave an answer that would let your code compile, but it still doesn't make sense. I assume that the MyClassView(frame: newFrame) bit is an intializer for a MyClassView object? Why in the world would you create a new view object only to take it's frame and assign it to another view, and then discard the newly created view?
Why do you need to create a MyClassView object at all? My guess is that you don't, and that you shouldn't. Get rid of the line that creates a MyClassView object entirely and just use the code you have commented out? (showImages.frame = newFrame).
Finally I've solved it. Just wanted to post the answer if someone else comes up with same problem. Previously i tried to assign images, which i made from one picture with function that sliced original picture, to bunch of rectangles that i created. But it didn't work because i didn't correctly make my class MojView. It inherited UIView, now it inherits UIImageView. Besides, i made a change in one line of code and the result is - rectangles are assigned with images and all of them can be dragged which was my intention when i created MojClass. Here is the code for both MojClass and the rest of app. MojClass: https://github.com/Vukovi/Ne-to/blob/master/README.md && Rest: https://github.com/Vukovi/ostatak/blob/master/README.md

How to declare properties with a for loop in Xcode

I have about 80 CALayer properties I need to add to a UIViewController and I'm wondering if anyone knows a way to do this with a for loop as opposed to me copying and pasting 80 lines of code like this:
var colorButton1 = CALayer()
var colorButton2 = CALayer()
var colorButton1 = CALayer()
var colorButton2 = CALayer()
var colorButton1 = CALayer()
var colorButton2 = CALayer()
........(colorbuttons go to 60)
I know how to make the objects with a for loop in the viewDidLoad method, like this:
let colorLayers = 60
var colorLayer = CALayer()
var buttonYPosition:CGFloat = 0.0
for colorNum in 1...60 {
buttonYPosition = buttonYPosition + 50
colorLayer.contents = UIImage(contentsOfFile:NSBundle.mainBundle().resourcePath!.stringByAppendingPathComponent("color\(colorNum).png"))!.CGImage
colorLayer.frame = CGRectMake(device.x/2, buttonYPosition, worldScale * 380, worldScale * 180)
colorLayer.zPosition = 6.0
self.view.layer.addSublayer(colorLayer)
}
but these are not properties.
So how can I put something like this in the top of my script so it creates 60 properties with 60 different indexed names, as opposed to 60 objects with the same name?
I'm not even sure this is possible, I'm just hoping to condense my code.
When dealing with many objects of the same type, rather than declaring all of them separately, you should make an array of that object type. In the case of CALayer, you can initialize an array of 60 objects using the count:repeatedValue initializer like so:
var layers = [CALayer](count: 60, repeatedValue: CALayer())
override func viewDidLoad() {
super.viewDidLoad()
// Access all layers
for layer in layers {
// Do something
}
// Access an individual layer
layers[0].frame = CGRectZero
}
Notice you access individual layers using subscript notation, which is cleaner than doing layer1, layer2, layer3, etc...
Use an array of CALayers:
var colorLayers = [CALayer]()

How to create a variable number of UIImageViews in swift

My problem is that based on the number of groups a person has I want to dynamically create that many UIImageView and assign them to the view. I know how to create a single UIImageView and put it onto the view but how can I create a variable number of them since creating another with the same name seems to just overwrite the original? I tried sending the UIImageView into an Array but got an optional error.
circleView = UIImageView(frame:CGRectMake(125, y, 75, 75))
y+=150
circleView.image = UIImage(named:"circle.png")
circleView.tag = i
self.view.addSubview(circleView)
circleArray[i] = circleView
The problem is that you keep reusing the same circleView instance. When you add it to the array, you are just adding a reference to it. You then reinitialize it, which wipes it out. I also don't see where you are incrementing i. Try something like this:
var circleArray = Array<UIImageView>()
var y : CGFloat = 0.0
var i = 0
circleArray.append(UIImageView(frame:CGRectMake(125, y, 75, 75)))
var circleView = circleArray[i]
circleView.image = UIImage(named:"circle.png")
circleView.tag = i
self.view.addSubview(circleView)
y+=150
i += 1
You need to use circleArray.append(circleView)

Update position of UIImageView Swift

I'm trying to make a draggable image (monkey) takes the place of another draggable image (banana) when I'm pushing a button.
So far, I've been able to get the coordinates of the banana, and store them as the new x,y coordinates of the monkey. But, the view is not updating and the monkey does not moves to it's new place.
I'm sure that I need to update the view, but can't figure it out.
I've tried to add a new subview (self.view.addSubview(monkey)) but when I do that, it's the entire view that is reset and both monkey and banana are going back to their original coordinates.
Here's the code of the action button :
#IBAction func getCoordinates (sender : AnyObject) {
var bananax = banana.frame.origin.x
var bananay = banana.frame.origin.y
var monkeyx = monkey.frame.origin.x
var monkeyy = monkey.frame.origin.y
println("Banana : \(bananax) et \(bananay)")
println("Monkey's default coordinates : \(monkeyx) et \(monkeyy)")
monkeyx = bananax
monkeyy = bananay
println("Monkey's new coordinates : \(monkeyx) et \(monkeyy)")
}
Any idea on how to update only the monkey and not reseting the entire view ?
Thanks :)
These values are just thrown away when you set monkeyx and monkeyy below.
var monkeyx = monkey.frame.origin.x
var monkeyy = monkey.frame.origin.y
Assigning the values below just assigns the values from one local variable to another. It does not actually change the coordinates for monkey.
monkeyx = bananax
monkeyy = bananay
You must set the new coordinates on monkey by constructing a new CGRect and assigning monkey's frame:
monkey.frame = CGRect(x: bananax, y: bananay, width: monkey.frame.size.width, height: monkey.frame.size.height)
As you are just setting monkey's origin to banana's origin, you can remove all the var declarations and reduce this to one line by constructing monkey's new frame with monkey's size and banana's origin:
monkey.frame = CGRect(origin: banana.frame.origin, size: monkey.frame.size)
Hi create this extends if you want. For Swift
Create File Extends.Swift and add this code
/**
Extension UIView
by DaRk-_-D0G
*/
extension UIView {
/**
Set x Position
:param: x CGFloat
by DaRk-_-D0G
*/
func setX(#x:CGFloat) {
var frame:CGRect = self.frame
frame.origin.x = x
self.frame = frame
}
/**
Set y Position
:param: y CGFloat
by DaRk-_-D0G
*/
func setY(#y:CGFloat) {
var frame:CGRect = self.frame
frame.origin.y = y
self.frame = frame
}
/**
Set Width
:param: width CGFloat
by DaRk-_-D0G
*/
func setWidth(#width:CGFloat) {
var frame:CGRect = self.frame
frame.size.width = width
self.frame = frame
}
/**
Set Height
:param: height CGFloat
by DaRk-_-D0G
*/
func setHeight(#height:CGFloat) {
var frame:CGRect = self.frame
frame.size.height = height
self.frame = frame
}
}
For Use (inherits Of UIView)
inheritsOfUIView.setX(x: 100)
button.setX(x: 100)
view.setY(y: 100)
Now you can do
monkey.frame.origin = banana.frame.origin
If you are using a UIImageView for monkey and banana, you can simplify this by doing the following
monkey.center = banana.center
Understand that there is a difference between origin and center. See more here:
UIView's frame, bounds, center, origin, when to use what?
but based on question, I think center should work fine and it is simpler.

Resources