Represent 'stack' of photos with XCode - ios

I'm trying to make a larger representation of the image like the one next to 'Camera Roll' where it shows the user that there are multiple images.
In the 'old' days you would probably have tried to show it like a stack of polaroid images however that isn't really the cool thing to do now.
I've taken a look around and can't think of anything and can't see any 3rd party libraries.
Any help would be appreciated :)

You would do this by simply by creating UIImageViews, altering them a bit, and then adding them to the superview. Here is an example with images called "0", "1", and "2".
let buffer = 10
for idx in 0...2 {
let newImageView = UIImageView(frame: CGRectMake(self.view.frame.minX + self.view.frame.width/4 - CGFloat(idx*buffer/4), self.view.frame.minY + self.view.frame.height/4 + CGFloat(idx*buffer/2), 100 + CGFloat(idx*buffer/2), 100 + CGFloat(idx*buffer/2)))
newImageView.clipsToBounds = true
newImageView.contentMode = .ScaleAspectFill
newImageView.layer.borderColor = UIColor.whiteColor().CGColor
newImageView.layer.borderWidth = 1
newImageView.image = UIImage(named: idx.description)
self.view.addSubview(newImageView)
}
}
I hope this can help you with your design!

Related

iOS 11 animated gif display in UIImageView

I thought iOS 11 was supposed to bring, at long last, native support for animated gifs? But I tried this, and I didn't see any animation:
let im = UIImage(named:"wireframe.gif")!
let iv = UIImageView(image:im)
iv.animationImages = [im] // didn't help
iv.frame.origin = CGPoint(0,100)
iv.frame.size = im.size
self.view.addSubview(iv)
delay(2) {
iv.startAnimating() // nope
}
How is this supposed to work?
iOS 11 does bring a native understanding of animated gifs, but that understanding, infuriatingly, is not built into UIImageView. It is still up to you to translate the animated gif into a sequence of UIImages. Apple now provides sample code, in terms of the ImageIO framework:
https://developer.apple.com/library/content/samplecode/UsingPhotosFramework/Listings/Shared_AnimatedImage_swift.html
That code implements an AnimatedImage class, which is essentially a collection of CGImages extracted from the original animated gif. Thus, using that class, we can display and animate the animated gif in a UIImageView as follows:
let url = Bundle.main.url(forResource: "wireframe", withExtension: "gif")!
let anim = AnimatedImage(url: url)!
var arr = [CGImage]()
for ix in 0..<anim.frameCount {
arr.append(anim.imageAtIndex(index: ix)!)
}
var arr2 = arr.map {UIImage(cgImage:$0)}
let iv = UIImageView()
iv.animationImages = arr2
iv.animationDuration = anim.duration
iv.frame.origin = CGPoint(0,100)
iv.frame.size = arr2[0].size
self.view.addSubview(iv)
delay(2) {
iv.startAnimating()
}
Unfortunately, the inter-frame timing of a GIF can vary between frames, so answers that use ImageIO to load the frames and then set them as the animatedImages on a UIImageView need to properly extract the timings and take them into account.
I recommend Flipboard's FLAnimatedImage, which handles GIFs correctly.
https://github.com/Flipboard/FLAnimatedImage.

What can i do whether add images to assets or in folder in ios

I'm building an ios app in which i have many images to show in many ViewController's ImageView. Thats why i have to add many images to the project.
Please tell me the best practice to add images in project. Whether i add in assets or in some other folder of my project.
If adding in some folder is best approach then how can i access those images.
Is this possible to add all images in a folder of the project and fetch those images and show in ImageViews and their name in UILabels one by one? If it is possible then please tell me the way to do this.
Obviously the best apporach is to add images in xcassets. Import images by clicking on the blue folder called "Images.xcassets" then click on the small "+" plus sign at the bottom of the window that appears. Now choose "Import" to put images in there.It's really helpful because you'll only see 1 image name instead of duplicate names with extensions like "#2x" and "#3x".
Why this approach benefits
This is the best way you can organize images. The concept of App slicing applies here.
Refer, in case if you have no idea about what app thinning concept is:
App thinning appcoda
How do I need to load images
You can take those image names in JSON file read from that (Recommended). Or else take an array and put all your image names into that and load (Not recommended).
Use below code in case if you are reading from JSON file
if let path = Bundle.main.path(forResource: "assets/test", ofType: "json") {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
let jsonObj = JSON(data: data)
}
the best and simple approach is to add all images in Assets.catalog .Now in you ViewController Create a Array of Strings [String] containing name of all images.Now using for-in loop access each element of and print name and image.Now creating programmically label and image and whenever xPosition exceeds width of Screen
SWIFT example
let imageArray:[String] = ["image1","image2","image3","image4"]
let xPosition = 20
let yPosition = 20
for item in imageArray{
let imageView = UIImageView(image: UIImage(named: item)!)
if (xPosition < (self.view.frame.width - 200)){
imageView.frame = CGRect(x: xPosition, y: yPosition, width: 80, height: 80)
var label = UILabel(frame: CGRectMake(xPosition,yPosition + 90, 20, 20))
label.text = item
xPosition += 100
}else{
yPosition += 100
xPosition = 20
imageView.frame = CGRect(x: xPosition, y: yPosition, width: 80, height: 80)
var label = UILabel(frame: CGRectMake(xPosition, yPosition + 90, 20, 20))
label.text = item
}
self.view.addSubview(imageView)
self.view.addSubview(label)
}
}

Enumerate through UIImageView

In SpriteKit you are able to enumerate through each node with a specific name. Say I have 10 sprites with the name property set to "foo" I can then run the code below and it will move each "food" node up 5 pixels every time the function is called.
enumerateChildNodesWithName("foo"){node, stop in
let sprite:SKSpriteNode = node as! SKSpriteNode
sprite.position.x += 5
}
Now, I would like to do this with UIImageView (if possible).
Here's my current setup
In my app I have code that runs every second. It is supposed to add a UIImageView using the following code
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
Finally, I have a for loop that doesn't seem to be targeting each specific view. But it should be moving each individual image view in a circle. Currently it only looks like a single image is moving even while I think I've added more image views.
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = mView.center
mView.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
I feel like what I'm doing is really wrong :( Is it possible for me to do what I am trying to do? I would like to do this so that I do not have to use SpriteKit. I want to try and create graphics at a lower level framework. Can I go lower then this even? How can I most efficiently render these 10 moving images?
I assume all the two peaces are consecutive.
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = view.center
view.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
If got you correct this should work.

Why are SKSpriteNodes only partially rendering?

I've coded a basic layout of "cards" for level selection in a game using Swift and SpriteKit. It's basically just 6 level selection cards side by side that have a picture of the level that the user can select. To create them I am running a for-loop and placing the first one in the center of the screen, a padding, then the second one, then padding etc. Each card is an SKSpriteNode from a png image. Each card is approx a 3rd of the device wide and about a 3rd of the devices height.
I create all six of them and then created an action that moves all 6 cards left or right to select which on the player would like. The one in the center is the one that is selected.
Everything works great on iphone simulators (tested on iPhone 6, iPhone 6 plus, iPhone 7 Plus and iPhone 5... all work great). On iPad simulators the first and last card have a portion of the image that doesn't render at all. The first card has about 1/4 of it lost on the left side, the last card has about 1/4 or it lost on the far right side. I tried running it on a physical iPad as well and it has the same issue. When I run it on an iPad Pro 12.7 it gets worse... it cuts off more of the image.
If I choose only to display 5 of the 6 cards they all render great.
If I choose to shrink them down to about 1/4 of the device width and 1/4 of the device height and lessen the padding they render fine.
I tried playing with the Scene and View sizes and scales and didn't have any improvement.
I've tried using different images and there is no changes at all.
I've double checked all zPositions and found no improvement.
I've tried systematically removing all other objects in the scene and still have the problem.
I've put them on their own "layer" which is an SKEffectNode named cardNode. (it's an SKEffectNode because I choose to later blur it when an alert screen comes up in front of it). I thought that putting them onto their own layer might help but it didn't.
I've put physics bodies on the cards just to make sure that they are still "there" and the physics bodies appear in the correct places. If I click on part of the node that isn't rendered it still does behave properly as though it was still rendered in that area.
I can't figure out where to go from here to fix this. Ideally I would like to add more cards yet in the future but getting stuck on this problem.
Here is the code that I have for creating the cards.
let cardNode = SKEffectNode()
let levelCardArray: [String] = [
"BlackBoxLevelCard.png"
,"FruitLevelCard.png"
,"SportsLevelCard.png"
,"BarnLevelCard.png"
,"SeaLevelCard.png"
,"SpaceLevelCard.png"
]
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
let w10 = screenWidth * 0.10
let w40 = screenWidth * 0.40
let w50 = screenWidth * 0.50
let w60 = screenWidth * 0.60
let h50 = screenHeight * 0.50
let cardMargin = w10
let cardSize = CGSize(width: w40, height: w60)
let startPosition = CGPoint(x: w50, y: h50)
override func didMove(to view: SKView) {
let scene = levelSelectionScene(size: view.bounds.size)
scene.backgroundColor = UIColor.black
let skView = view as SKView
skView.ignoresSiblingOrder = true
cardNode.zPosition = 100
self.addChild(cardNode)
for i in 1...levelCardArray.count {
let currentArrayValue = i - 1
let cardSprite = SKSpriteNode(imageNamed: levelCardArray[currentArrayValue])
cardSprite.size = cardSize
cardSprite.position = CGPoint(x: startPosition.x + (CGFloat(currentArrayValue) * (cardSize.width + cardMargin)), y: startPosition.y)
cardSprite.zPosition = cardNode.zPosition
cardSprite.name = "levelCardObject"
cardNode.addChild(cardSprite)
}
Any help or insight would be greatly appreciated. Thanks guys!
I tried all day today to try to find a way to make this work through resizing the scenes and views and haven't had any luck with it at all.
My solution is to check for the device type and if it's an iPad I am reducing the image sizes and buffer between images until it doesn't cut them off. I don't consider this a very good solution, really just a work around until I can find a better way to do it. Thank you guys for your thoughts though. I definitely appreciate it!

Random images to (many) Image Views

Sadly, I've got 36 UIImages and need to set a random image to each one.
My 6 images are named;
"Owl1"
"Owl2"
"Owl3"
"Owl4"
"Owl5"
"Owl6"
So, I want to set one random image to my 36 different UIImages. What is the best way to do this? An array? Here's my "try" so far.
var images: [UIImage] = [
UIImage(named: "Owl1")!,
UIImage(named: "Owl2")!,
UIImage(named: "Owl3")!,
UIImage(named: "Owl4")!,
UIImage(named: "Owl5")!,
UIImage(named: "Owl6")!
]
var randomUIImage = [Image1, Image2, Image3, Image4, Image5...]
randomUIImage.shuffleInPlace()
randomUIImage[0].image = images[0]
randomUIImage[1].image = images[1]
But I realized this will not work, and I can't make this code for all 36 images... Anyone got a better idea? ;-)
Tip: you can use a range + map to create an array of your images.
let images = (1...6).map { UIImage(named: "Owl\($0)") }
(1...6) produces a collection of Ints, from 1 to 6 (including 6), and with map we create a new instance of UIImage for each Int, using them for the naming - since you named your images in order, it's convenient. It's like doing a loop and appending a new intance of UIImage to an array inside the loop, using an index for the naming: "Owl1", "Owl2", etc.
If you also have your UIImageViews in an array, you can assign the images with a loop.
Here's an example (I didn't verify on Xcode but it should be close to what you need):
for view in imageViewsArray { // the array with the 36 imageViews
// a random index for the array of 6 images
let randomIndex = Int(arc4random_uniform(UInt32(images.count))
// assign the randomly chosen image to the image view
view.image = images[randomIndex]
}
You can have an array of image names, and an array of images to hold them..
var imageNames:[String] = ["Owl1", "Owl2"....etc]
var owlImages:[UIImage] = []
Then randomly append the images
for index in 0...imageNames.count - 1 {
var randomInt = Int(arc4random_uniform(UInt32(imageNames.count)) //a random int from 0 to the size of your array
owlImages.append(UIImage(named: imageNames[randomInt] //add the random image to the array
}

Resources