I have a UIImageView that should animate an array of images called capturedImages. I have the animation set up like so:
imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(0, 48, 320, 520);
imageView.animationImages = capturedImages;
imageView.animationDuration = 3.0;
imageView.animationRepeatCount = 0; //animate forever
[imageView startAnimating];
[self.view addSubview:imageView];
The images in capturedImages are taken with the phone/camera view upright. However, when the imageView displays them, they animate properly but are rotated 90 degrees counterclockwise. Is there a way to change the orientation of animationImages, or do I have to set each image's orientation individually?
The simplest solution may be to just rotate the UIImageView itself.
You can use the transform property of UIView to do this:
[imageView setTransform:CGAffineTransformMakeRotation(M_PI_2)];
Be aware of the fact that this will break if you start displaying images which are already in the correct orientation. These will be rotated 90 degrees clockwise as well.
Setting the image property for the UIImageView to the first image in the list of images fixes the problem. For example in my view controller (swift):
override func viewDidLoad() {
super.viewDidLoad()
if let images = self.images {
if images.count > 0 {
self.animation_view.image = images[0]
}
self.animation_view.animationImages = images
self.animation_view.animationRepeatCount = 0
self.animation_view.animationDuration = 1.0
}
}
override func viewWillAppear(animated: Bool) {
self.animation_view.startAnimating()
}
Related
So I have a UICollectionView with different number of UIImageViews and each has a custom size and position. On device rotate to landscape it seems kind of jerky, as it removes all the views and adds them again in CellForItem
What I am doing currently:
func updateUI() {
for item in allItems { item.removeFromSuperview() }
allItems = []
for (index, imageData) in imageDataArray.enumerated() {
let imageView = UIImageView(image: image)
contentView.addSubview(imageView)
imageView.frame = ...
imageView.center = ...
allItems.append(imageView)
}
}
What could I change to make rotation make less calculations or at least don't look glitchy if there's no other way. Thanks!
Sorry for the header, I just did not know how to call it.
I want to make my scrollView able to scroll from top or bottom until the circle in the center, like LinkedIn does it:
So there you can scroll your image until the circle in the center. How can I improve my code, to achieve this?
My code is:
scrollView!.delegate = self
imageView.frame = CGRectMake(0, 0, (scrollView?.frame.width)!, (scrollView?.frame.height)!)
if let validImage = self.avatarImage {
self.imageView.image = validImage
imageView.contentMode = .ScaleAspectFill
imageView.frame = avatarImageFrame!
}
imageView.userInteractionEnabled = true
scrollView?.addSubview(imageView)
scrollView?.contentSize = (avatarImage?.size)!
let scrollViewFrame = scrollView?.frame
let scaleWidth = (scrollViewFrame?.size.width)! / (scrollView?.contentSize.width)!
let scaleHeight = (scrollViewFrame?.size.height)! / (scrollView?.contentSize.height)!
let minScale = min(scaleHeight, scaleWidth)
scrollView?.minimumZoomScale = minScale
scrollView?.maximumZoomScale = 1
scrollView?.zoomScale = minScale
centerScrollViewContents()
}
func centerScrollViewContents() {
let boundsSize = scrollView?.bounds.size
var contentsFrame = imageView.frame
if contentsFrame.size.width < boundsSize?.width {
contentsFrame.origin.x = ((boundsSize?.width)! - contentsFrame.size.width) / 2
} else {
contentsFrame.origin.x = 0
}
if contentsFrame.size.height < boundsSize?.height {
contentsFrame.origin.y = ((boundsSize?.height)! - contentsFrame.size.height) / 2
} else {
contentsFrame.origin.y = 0
}
contentsFrame.size.height = UIScreen.mainScreen().bounds.height
imageView.frame = contentsFrame
}
func scrollViewDidZoom(scrollView: UIScrollView) {
centerScrollViewContents()
}
There are many ways to achieve this. Probably what would work best with the scroll view is to set the frame of the scroll view the same as is the frame of the circle. The content size should still be the same as the background (or rather the image in your case) and when you first enter the screen the content offset should be set so that the image is in center.
So till now you can imagine a small scroll view just behind the circle but the rest of the background is missing. To fix this all you need to do is disable bound clipping on the scroll view which is set to true by default. So set "clip subviews" to false.
Now you can already see the whole image and bouncing is correct to always keep the image inside the circle but one more thing is missing. Since the scroll view is actually quite small you can see you may not interact with it outside its frame. This is a natural behavior which can be changed by overriding a method called hitTest. This method will return a view which should collect the interaction. So we need to subclass the superview of the scroll view:
Regardless of where you do this in the interface builder or in the code I expect you have some view (will call it background) which contains a scroll view (the small one) and an overlay (the one with the circle). The background must be subclassed and have a reference to the scroll view. Then simply override the hit test method like so:
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
var myFrame = frame
myFrame.origin = CGPointZero // maybe this should be commented out
if CGRectContainsPoint(myFrame, point) {
return scrollView
} else {
return super.hitTest(point, withEvent: event)
}
}
By doing this the scroll view is interactable from anywhere within the background, whole image is visible on the background, the image will always be within the circle.
Good luck.
I'm writing a SpriteKit game and faced a problem with blurred view, which lies on the SKView. It is supposed to slide from the right when game is paused and it should blur the content of it's parent view (SKView) just like control center panel in iOS 7. Here is the desired appearance:
What I actually get is:
In fact the view on the left is not totally black, you can see how highlights from the superview are slightly struggling through almost opaque subview, but no blur is applied. Is it an iOS 8 bug/feature, or is it my mistake/misunderstanding
Here is my UIVisualEffectView subclass's essensials:
class OptionsView: UIVisualEffectView {
//...
init(size: CGSize) {
buttons = [UIButton]()
super.init(effect: UIBlurEffect(style: .Dark))
frame = CGRectMake(-size.width, 0, size.width, size.height)
addButtons()
clipsToBounds = true
}
func show() {
UIView.animateWithDuration(0.3, animations: {
self.frame.origin.x = 0
})
}
func hide() {
UIView.animateWithDuration(0.3, animations: {
self.frame.origin.x = -self.frame.size.width
})
}
Then in GameScene class:
in initializer:
optionsView = OptionsView(size: CGSizeMake(130, size.height))
in didMoveToView(view: SKView):
view.addSubview(optionsView)
on pressing pause button:
self.optionsView.show()
P.S. Though I know two another ways to implement blur view, I thought this one was the easiest, since my app is going to support iOS8 only
Render a blurred static image from superview ->
put UIImageView on the OptionsView, with clipsToBounds = true ->
animate UIImageView position while animating optionsView position, so that blur stays still relatively to the superview
Forget about UIView, UIVisualEffectView and UIBlurView and use SKEffectNode together with SKCropNode.
Ok, I have managed to get the desired effect using SKEffectNode instead of UIVisualEffectView.
Here is the code for someone facing the same issue
class BlurCropNode: SKCropNode {
var blurNode: BlurNode
var size: CGSize
init(size: CGSize) {
self.size = size
blurNode = BlurNode(radius: 10)
super.init()
addChild(blurNode)
let mask = SKSpriteNode (color: UIColor.blackColor(), size: size)
mask.anchorPoint = CGPoint.zeroPoint
maskNode = mask
}
}
class BlurNode: SKEffectNode {
var sprite: SKSpriteNode
var texture: SKTexture {
get { return sprite.texture }
set {
sprite.texture = newValue
let scale = UIScreen.mainScreen().scale
let textureSize = newValue.size()
sprite.size = CGSizeMake(textureSize.width/scale, textureSize.height/scale)
}
}
init(radius: CGFloat) {
sprite = SKSpriteNode()
super.init()
sprite.anchorPoint = CGPointMake(0, 0)
addChild(sprite)
filter = CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius": radius])
shouldEnableEffects = true
shouldRasterize = true
}
}
Result:
There are several issues though
Cropping doesn't work with SKEffectNode until it's shouldRasterize property is set to true. I get the whole screen blurred. So I still don't know how to properly implement realtime blur.
Animation on the BlurCropNode is not smooth enough. There is a lag at the beginning because of capturing texture and setting it to the effectNode's sprite child. Even dispatch_async doesn't help.
It would be very much appreciated if anyone could help to solve at least one of the problems
I know I'm probably a bit late but I was having the same problem and found a solution to creating a realtime blur on part of the screen. It's based on this tutorial: http://www.youtube.com/watch?v=eYHId0zgkdE where he used a shader to blur a static sprite. I extended his tutorial to capture of the part of the screen and then apply the blur to that. For your problem you could capture under that sidebar.
Firstly, you create an SKSpriteNode to hold the captured texture. Then in didMoveToView() you add your blur shader to that sprite. (You can find the blur.fsh file on GitHub, there's a link at the bottom of the youtube video.)
override func didMoveToView(view: SKView) {
blurNode.shader = SKShader(fileNamed: "blur")
self.addChild(blurNode)
}
Then you have to capture the section of the view you want to blur and apply the SKTexture to, in my case, blurNode.
override func update(currentTime: CFTimeInterval) {
// Hide the blurNode to avoid it be captured too.
blurNode.hidden = true
blurNode.texture = self.view!.textureFromNode(self, crop: blurNode.frame)
blurNode.hidden = false
}
And that should be it. On my iPad mini, with a blur of 1/3 of the width of the screen, the fps was 58-59. Blurring the whole screen the fps was down to about 22 so it's obviously not ideal for some things but hopefully it helps.
I tried to use this code under in my app delegate in order to add a PNG image as a view controller's background :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[self window] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]]];
return YES;
}
but I have no luck with it... the view controller still has a white background. What's wrong with that code?
The accepted answer and Michael's answer will work, however, proper way is to use a UIImageView instead. It gives more control over resizing, scaling etc according to different screen sizes on devices. Here is the example;
First create a UIImage.
UIImage *backgroundImage = [UIImage imageNamed:#"iphone_skyline3.jpg"];
Second create a UIImageView. Set the frame size to the parent's (self) frame size. This is important as the frame size will vary on different devices. Stretching will occur depending on the image size. Next assign the image to the view.
UIImageView *backgroundImageView=[[UIImageView alloc]initWithFrame:self.view.frame];
backgroundImageView.image=backgroundImage;
Finally, to keep the image behind all controls do the following. It is important if you are setting the image as a background for your app.
[self.view insertSubview:backgroundImageView atIndex:0];
You need to set the background for your ViewController's view
In your ViewController init or viewDidLoad:
[self.view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]]];
Here is how it is in swift:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "background.png"))
}
Swift 4 version of the #hadaytullah answer with some improvements in image adjustments:
override func viewDidLoad() {
super.viewDidLoad()
let backgroundImage = UIImage.init(named: "yourImageNameHere")
let backgroundImageView = UIImageView.init(frame: self.view.frame)
backgroundImageView.image = backgroundImage
backgroundImageView.contentMode = .scaleAspectFill
backgroundImageView.alpha = 0.1
self.view.insertSubview(backgroundImageView, at: 0)
}
You could also write extension to UIViewController to use in multiple places
extension UIViewController {
func setBackgroundImage(imageName: String) {
let backgroundImage = UIImage(named: imageName)
let backgroundImageView = UIImageView(frame: self.view.frame)
backgroundImageView.image = backgroundImage
self.view.insertSubview(backgroundImageView, at: 0)
}
}
In viewDidLoad, I use:
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"yourImageString.png"]];
Alternatively, if you want to do it in appDelegate, I think its possible to
[self.window setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"yourImageString.png"]]];
Then in viewDidLoad set background to [UIColor clearColor] ?
If your view controller is having tableView/collection view the below code will suitable for you.
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"yourImage.png"]];
}
you may consider the following solution i use in swift 3.0 and tested in xcode 8
// init and image with your pattern image
var bgUIImage : UIImage = UIImage(named: "yourIamgeName")!
let myInsets : UIEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
bgUIImage = bgUIImage.resizableImage(withCapInsets: myInsets)
self.view.backgroundColor = UIColor.init(patternImage:bgUIImage)
the result will be the following image
You can do it from the storyboard.
Add UIImageView and just set your background image for the Image property in the Attribute Inspector.
I'd like to call
[self.view setContentMode:UIViewContentModeScaleAspectFit | UIViewContentModeCenter];
where self is an instance of UIViewController. This doesn't seem to work; what are the direct alternatives, if any?
The contentMode is not a mask; you can't use | to combine values, you'll have to pick one. UIViewContentModeScaleAspectFit should center the content if it doesn't fit the view.
You will need to set contentMode once when the view loads and then center it in viewWillLayoutSubviews which is called upon device rotation.
override func viewDidLoad() {
super.viewDidLoad()
//additional code to instantiate and setup image
imageView.contentMode = .ScaleAspectFit
self.view.addSubview(profileImageView)
}
override func viewWillLayoutSubviews() {
imageView.center.x = view.center.x
//or imageView.center = view.center
//or imageView.center.y = view.center.y
}