How do I share a UIImage between two ViewControllers programmatically? - ios

I'm using this custom collectionView transition:
When a cell is selected, the UIImage in the cell is animated to transition seamlessly into the UIImageView in the detailViewController ,as seen in the GIF in this link.
However the issue is, the UIImage in the detailViewController's UIImageView is hard coded in, and will be the same for every selected cell from the UICollectionView. I have different images within my collectionViewCell's and this would obviously be a problem, so I need to somehow programmatically make my detailViewController's UIImageView Image to equal that of the selected collectionViewCell's UIImageView Image when the transition is completed.
Here's the code I used to try to achieve this:
class DetailViewController: UIViewController, ARNImageTransitionZoomable {
#IBOutlet weak var imageView: UIImageView!
var selectedCell = MasterCollectionViewController()
deinit {
println("deinit DetailViewController")
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.layer.cornerRadius = 3.0
imageView.clipsToBounds = true
}
// MARK: - ARNImageTransitionZoomable
func createTransitionImageView() -> UIImageView {
var imageView = UIImageView(image: self.imageView.image)
imageView.contentMode = self.imageView.contentMode
imageView.clipsToBounds = true
imageView.userInteractionEnabled = false
imageView.frame = self.imageView!.frame
return imageView
}
func presentationBeforeAction() {
self.imageView.hidden = true
}
func presentationCompletionAction(completeTransition: Bool) {
self.imageView.hidden = false
self.imageView.image = selectedCell.selectedImageView?.image
}
func dismissalBeforeAction() {
self.imageView.hidden = true
}
func dismissalCompletionAction(completeTransition: Bool) {
if !completeTransition {
self.imageView.hidden = false
}
}
}
I added a variable "selectedCell" that is of type MasterCollectionViewController(), giving me reference to everything in that class.
Then in the animation/transitions completion, I attempted to set the selected cell's UIImage to that of my detailViewController's UIImageView Image with the line
func presentationCompletionAction(completeTransition: Bool) {
self.imageView.hidden = false
self.imageView.image = selectedCell.selectedImageView?.image
}
This didn't work, when the transition is complete, the UIImageView is just white with no image, just as it is on my storyboard. Somebody know any method I can implement?

Related

make UIImage fill the entire navigationBar

I want to insert an image inside a ui navigation bar and make it look as an aspect fit image looks inside an imageView.
i am doing it as
navigationController?.navigationBar.compactAppearance?.backgroundImageContentMode = .scaleToFill
navigationController?.navigationBar.setBackgroundImage(image, for: .default)
But it is giving me the output as :
How can i make it perfect.
The simplest way to use the UIImageView here with scaleAspectFit image property. Try the following working code block.
func setNavigation() {
let imageView = UIImageView(image: UIImage(named: "bankselected"))
imageView.frame = navigationController!.navigationBar.frame
imageView.backgroundColor = .lightGray
imageView.contentMode = .scaleAspectFit
navigationController?.navigationBar.addSubview(imageView)
}
You can use this Protocol to add image in your navigationBar
protocol CustomizableNavigationBar {
var navigationBar: UINavigationBar? { get }
}
extension CustomizableNavigationBar {
func setNavBarLogo() {
let imageView = UIImageView(image: UIImage(named: "artistAvatar1"))
imageView.frame = navigationBar!.frame
imageView.contentMode = .scaleToFill
navigationBar?.addSubview(imageView)
}
}
Use it like This
class SearchViewController: UIViewController,CustomizableNavigationBar {
var navigationBar: UINavigationBar?
override func viewDidLoad() {
super.viewDidLoad()
navigationBar = navigationController?.navigationBar
setNavBarLogo()
}
}

How to implement a CollectionViewCell that can either display an image or a custom UIView provided as input property?

I have a collectionView cell that should either display an image or an icon that is generated as a custom UIView (lets say IconView).
Currently, I implemented this by adding an UIImageView and an IconView as subviews to a container view.
When an image is provided, the image property of UIImageView is simply updated. When a new IconView is provided it is currently always added as a subview to the container view. Therefore, before adding, it is first checked whether an IconView has already been added, and if so it is removed.
Although this implementation works, it is not very elegant and seems not efficient since it results in scrolling issues when the number of rows increase.
Would there be a better (more efficient) way to implement this for a single CollectionViewCell?
class CustomCell: UICollectionViewCell {
internal var image: UIImage? {
didSet {
self.imageView.image = image!
}
}
internal var iconView: IconView? {
didSet {
if !(self.iconContainerView.subviews.flatMap{ $0 as? IconView}.isEmpty) {
self.iconView!.removeFromSuperview()
}
self.iconView!.translatesAutoresizingMaskIntoConstraints = false
self.iconContainerView.addSubview(self.iconView!)
self.image = nil
}
}
fileprivate var imageView: UIImageView!
fileprivate var iconContainerView: UIView!
fileprivate var layoutConstraints = [NSLayoutConstraint]()
override init(frame: CGRect) {
super.init(frame: frame)
// ContainerView
self.iconContainerView = UIView()
self.iconContainerView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.iconContainerView)
// ImageView
self.imageView = UIImageView()
self.imageView.translatesAutoresizingMaskIntoConstraints = false
self.iconContainerView.addSubview(self.imageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
self.iconContainerView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor).isActive = true
self.iconContainerView.widthAnchor.constraint(equalToConstant: 60).isActive = true
self.iconContainerView.heightAnchor.constraint(equalToConstant: 60).isActive = true
self.iconContainerView.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor).isActive = true
// Deactivate non-reusable constraints
_ = self.layoutConstraints.map { $0.isActive = false }
self.layoutConstraints = [NSLayoutConstraint]()
if let iconView = self.iconView {
self.imageView.isHidden = true
self.layoutConstraints.append(iconView.centerYAnchor.constraint(equalTo: self.iconContainerView.centerYAnchor))
self.layoutConstraints.append(iconView.centerXAnchor.constraint(equalTo: self.iconContainerView.centerXAnchor))
self.layoutConstraints.append(iconView.heightAnchor.constraint(equalToConstant: 40))
self.layoutConstraints.append(iconView.widthAnchor.constraint(equalToConstant: 40))
} else {
self.imageView.isHidden = false
self.iconView?.isHidden = true
self.layoutConstraints.append(self.imageView.leadingAnchor.constraint(equalTo: self.iconContainerView.leadingAnchor))
self.layoutConstraints.append(self.imageView.trailingAnchor.constraint(equalTo: self.iconContainerView.trailingAnchor))
self.layoutConstraints.append(self.imageView.topAnchor.constraint(equalTo: self.iconContainerView.topAnchor))
self.layoutConstraints.append(self.imageView.bottomAnchor.constraint(equalTo: self.iconContainerView.bottomAnchor))
}
_ = self.layoutConstraints.map {$0.isActive = true}
}
}
Don't ad and remove the IconView when setting. Add both in the same spot and change the isHidden, alpha, or opacity or bringSubviewToFront. This is much less main thread intensive.

change page Indicator Image [SMPageControl] / EAIntroView in swift

I'm trying to change the indicator image , following the example in EAIntroView
here is the objective-c code from EAIntroView
SMPageControl *pageControl = [[SMPageControl alloc] init];
pageControl.pageIndicatorImage = [UIImage imageNamed:#"pageDot"];
pageControl.currentPageIndicatorImage = [UIImage imageNamed:#"selectedPageDot"];
[pageControl sizeToFit];
intro.pageControl = (UIPageControl *)pageControl;
intro.pageControlY = 130.f;
and here is the swift code I'm trying to implement
// SMPageControl
pageControl = SMPageControl()
pageControl.pageIndicatorImage = UIImage(named: "pageDot")
pageControl.currentPageIndicatorImage = UIImage(named: "selectedPageDot")
pageControl.sizeToFit()
pageControl.backgroundColor = UIColor.clearColor()
intro.pageControl = pageControl as? UIPageControl
swift code has a warning here
intro.pageControl = pageControl as? UIPageControl
the warning is :
Cast from 'SMPageControl!' to unrelated type 'UIPageControl' always fails
any help ?
For changing page Indicator Image [SMPageControl] / EAIntroView in swift I have created custom class of UIPageControl like below:
import UIKit
class CustomPageControl: UIPageControl {
let activePage: UIImage = UIImage(named: "icon-selected-dot")!
let inActivePage: UIImage = UIImage(named: "icon-dot")!
override var numberOfPages: Int {
didSet {
updateDots()
}
}
override var currentPage: Int {
didSet {
updateDots()
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.pageIndicatorTintColor = UIColor.clear
self.currentPageIndicatorTintColor = UIColor.clear
self.clipsToBounds = false
}
func updateDots() {
var i = 0
for view in self.subviews {
var imageView = self.imageView(forSubview: view)
if imageView == nil {
if i == self.currentPage {
imageView = UIImageView(image: activePage)
} else {
imageView = UIImageView(image: inActivePage)
}
imageView!.center = view.center
view.addSubview(imageView!)
view.clipsToBounds = false
}
if i == self.currentPage {
imageView!.alpha = 1.0
imageView?.image = activePage
} else {
imageView!.alpha = 0.5
imageView?.image = inActivePage
}
i += 1
}
}
fileprivate func imageView(forSubview view: UIView) -> UIImageView? {
var dot: UIImageView?
if let dotImageView = view as? UIImageView {
dot = dotImageView
} else {
for foundView in view.subviews {
if let imageView = foundView as? UIImageView {
dot = imageView
break
}
}
}
return dot
}
}
then in your class just add these lines and you can use custom images for dot
//Custom page Control
let pageControl = CustomPageControl()
pageControl.updateDots()
intro.pageControl = pageControl
Hope it will work for you! #ynamao
You can see from the source code of SMPageControl that it isn't a subclass of UIPageControl. Which means the error is expected: UIPageControl is a completely unrelated type, to which the value cannot be cast.
The Objective-C you pointed to might work, but it's bad and wrong: inline cast to UIPageControl achieves nothing here and can cause internal inconsistencies.
This is exactly the kind of sloppiness that Swift compiler is designed to prevent, and it's doing its job well.
Your best bet is to forgo using this library in Swift code.

UIImage created with animatedImageWithImages have bugs?

Recently I found sometimes my gif image not shown. So I write a test code for it:
import UIKit
import ImageIO
extension UIImage {
static func gifImageArray(data: NSData) -> [UIImage] {
let source = CGImageSourceCreateWithData(data, nil)!
let count = CGImageSourceGetCount(source)
if count <= 1 {
return [UIImage(data: data)!]
} else {
var images = [UIImage](); images.reserveCapacity(count)
for i in 0..<count {
let image = CGImageSourceCreateImageAtIndex(source, i, nil)!
images.append( UIImage(CGImage: image) )
}
return images;
}
}
static func gifImage(data: NSData) -> UIImage? {
let gif = gifImageArray(data)
if gif.count <= 1 {
return gif[0]
} else {
return UIImage.animatedImageWithImages(gif, duration: NSTimeInterval(gif.count) * 0.1)
}
}
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let _gifData : NSData = NSData(contentsOfURL: NSURL(string: "https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif")!)!
lazy var _gifImageArray : [UIImage] = UIImage.gifImageArray(self._gifData)
lazy var _gifImage : UIImage = UIImage.gifImage(self._gifData)!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let table = UITableView(frame: self.view.bounds, style: .Plain)
table.dataSource = self
table.delegate = self
self.view.addSubview(table)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1000;
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "cell"
var cell : UITableViewCell! = tableView.dequeueReusableCellWithIdentifier(identifier);
if cell == nil {
cell = UITableViewCell(style: .Default, reuseIdentifier: identifier)
}
if let imageView = cell.imageView {
/** 1. use the same UIImage object created by animatedImageWithImages
the image disappear when reuse, and when touching cell, it reappear. */
imageView.image = self._gifImage
/** 2. create different UIImage by using same image array. this still not work */
// imageView.image = UIImage.animatedImageWithImages(self._gifImageArray, duration: NSTimeInterval(self._gifImageArray.count) * 0.1)
/** 3. create different UIImage from data, this seems work
but use a lot of memories. and seems it has performance issue. */
// imageView.image = UIImage.gifImage(self._gifData)
/** 4. use same image array as imageView's animationImages.
this kind works, but have different api than just set image.
and when click on cell, the animation stops. */
// imageView.image = self._gifImageArray[0]
// imageView.animationImages = self._gifImageArray
// imageView.startAnimating()
}
return cell
}
}
Notice in the cellForRowAtIndexPath: method, I tried different way to set imageView.
when I po object in lldb, I notice the animated imageView have a CAKeyframeAnimation. does this makes a tip?
How can I make the gif shown perfectly? Any suggestion would be helpful.
Here is a preview: after scroll, gif disappear, and reappear when touch
After I tried many times, I have finally figured out that I need to change:
imageView.image = self._gifImage
to:
imageView.image = nil // this is the magical!
imageView.image = self._gifImage
just set image to nil before set to new image, and the animation work!! It's just like a magical!
This is definitely apple's bug.
try by replacing imageView with myImageview or other name because cell have default imageView property so when you call cell.imageView then it returns cell's default imageview i think. so change your cell's imageview's variable name. hope this will help :)
maybe image class need SDAnimatedImage instead of UIImage

Stretch Background for View in Swift

I am using adding Background in iOS Swift App using:
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)
However, it does not cover the Screen till bottom. I searched Other questions:
var backImage = UIImage(named: "background")
var resizablebackImage = backImage?.resizableImageWithCapInsets(UIEdgeInsets(top:10,left:0,bottom:10,right:0))
self.view.backgroundColor = UIColor(patternImage:resizablebackImage!)
That does not work. Any ideas?
If your intention is to set it as the background image, don't make image as pattern color and fill it as background color. Instead create an UIImageView set your image as it's image and add it to your UIView.
var bgImage = UIImage(named: "background");
var imageView = UIImageView(frame: self.view.bounds);
imageView.image = bgImage
self.view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
For Swift 1.x & Swift 2 plus Device Rotation Detection
Please see my code below. Just set bgImageName to the name of your image and call setBackgroundImage(). I added an auto-reload in case of a device rotation.
var bgImage = UIImage()
var bgImageView = UIImageView()
var bgImageName = ""
override func viewDidLoad() {
super.viewDidLoad()
bgImageName = "bg-orange" // or whatever your image is called
setBackgroundImage()
}
func setBackgroundImage() {
if bgImageName > "" {
bgImageView.removeFromSuperview()
bgImage = UIImage(named: bgImageName)!
bgImageView = UIImageView(frame: self.view.bounds)
bgImageView.image = bgImage
self.view.addSubview(bgImageView)
self.view.sendSubviewToBack(bgImageView)
}
}
// detect device orientation changes
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("rotated device to landscape")
setBackgroundImage()
} else {
print("rotated device to portrait")
setBackgroundImage()
}
}

Resources