Reuse Identifier on iCarousel - ios

I am trying to build a carousel on my app based on this project, https://github.com/nicklockwood/iCarousel, only I am writing it in swift. I have it working correctly, where you can scroll through and tap on the item at index correctly here:
func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
let tempView = UIView(frame: CGRect(x: 0, y: 130, width: 295, height: 300))
let object = self.imageFilesArray.object(at: index) as! PFObject
let imageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0 , width: 295, height: 295)
imageView.layer.cornerRadius = 15
imageView.layer.masksToBounds = true
let imageFile = object.object(forKey: "Image") as! PFFile
imageFile.getDataInBackground{
(data, error) -> Void in
if error == nil {
}
imageView.image = UIImage(data: data!)
tempView.addSubview(imageView)
}
return tempView
}
func carousel(_ carousel: iCarousel, didSelectItemAt index: Int) {
let cell = carouselView.itemView(at: index)
let object = self.imageFilesArray[index] as! PFObject
if cell?.tag == 0 {
print("open cell")
let moveImg = CGAffineTransform(translationX: 0, y: -100)
UIView.animate(withDuration: 0.4, delay: 0.1, options: [], animations: {
//cell.imageView.transform = moveImg
}, completion: nil)
cell?.tag = 1
} else if cell?.tag == 1 {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "EventDetailViewController") as! EventDetailViewController
self.present(nextViewController, animated:false, completion:nil)
}
However, what I am trying to do is when I tap the item at index, the imageView transitions on the screen. My issue is that I cannot access that particular cells imageView in order to move it. Does anyone know what I need to change?

You could give your imageView a tag like this:
let imageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0 , width: 295, height: 295)
imageView.layer.cornerRadius = 15
imageView.layer.masksToBounds = true
imageView.tag = 2
Then you can retrieve the imageView from the cell like this:
if let imageView = cell.viewWithTag(2) as? UIImageView {
imageView.transform = moveImg
}
OR
You could filter through the subviews of the cell and find the first subview that can be cast to a UIImageView. Although this isn't very robust, consider creating a Class and XIB for this cell.
cell.subviews.flatMap { $0 as? UIImageView }.first?.transform = moveImg

Related

MXSegmentedPager overlaps with TableView

Segmented Pager Adapter is overlapping with my TableView when creating it manually
Using following library
https://github.com/maxep/MXSegmentedPager
Following is my code
let tabVC = AppStrings.appStoryBoard.instantiateViewController(withIdentifier:
"aboutReviewViewControllerID") as! AboutReviewViewController
viewControllerArray.append(tabVC)
segmentedPager = MXSegmentedPager(frame: CGRect(x: 0, y: 0, width:
self.view.frame.width, height: view.frame.height))
view.addSubview(segmentedPager)
segmentedPager.dataSource = self
segmentedPager.delegate = self
segmentedPager.backgroundColor = .clear
segmentedPager.parallaxHeader.view = topBGView
segmentedPager.parallaxHeader.mode = .fill
segmentedPager.parallaxHeader.height = topBGView.frame.height
segmentedPager.parallaxHeader.minimumHeight = 10
segmentedPager.parallaxHeader.delegate = self
segmentedPager.reloadData()
[![enter image description here][1]][1]func segmentedPager(_ segmentedPager: MXSegmentedPager, viewForPageAt index: Int) -> UIView {
return viewControllerArray[index].view
}
func segmentedPager(_ segmentedPager: MXSegmentedPager, segueIdentifierForPageAt index: Int) -> String {
return ""
}

Tapping a UIImage while it's being animated

I've been trying to be able to tap a UIImage as it animates to the top of my screen and print("Image Tapped"), yet to no success.
override func viewDidLoad() {
super.viewDidLoad()
redBalloon.image = UIImage(named: "redBalloon")
redBalloon.contentMode = .scaleAspectFit
redBalloon.frame = CGRect(x: Int(xOrigin), y: 667, width: Int(redBalloon.frame.size.width), height: Int(redBalloon.frame.size.height))
UIView.animate(withDuration: 5, delay: 0, options: UIImageView.AnimationOptions.allowUserInteraction, animations: {
self.redBalloon.frame = CGRect(x: Int(self.xEnding), y: -192, width: 166, height: 192)
}, completion: {(finished:Bool) in
self.endGame()
})
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
redBalloon.isUserInteractionEnabled = true
redBalloon.addGestureRecognizer(imageTap)
}
#objc func imageTapped(_ sender: UITapGestureRecognizer) {
// do something when image tapped
print("image tapped")
}
The problem is that the image view is not in the spot where you see it during animation (it's at the endpoint of the animation). So you are not tapping on the image view at the point where it is, and thus the tap is not detected.
Therefore, either you must hit-test the presentation layer or, if you don't want to do that, you must use a UIViewPropertyAnimator instead of calling UIView.animate.
As an example of the first approach, I'll subclass UIImageView. Make your UIImageView an instance of this subclass:
class TouchableImageView : UIImageView {
override func hitTest(_ point: CGPoint, with e: UIEvent?) -> UIView? {
let pres = self.layer.presentation()!
let suppt = self.convert(point, to: self.superview!)
let prespt = self.superview!.layer.convert(suppt, to: pres)
return super.hitTest(prespt, with: e)
}
}
However, personally I think it's a lot simpler to use UIViewPropertyAnimator. In that case, do not make your UIImageView a TouchableImageView! You don't want to do extra hit-test munging. Just let the property animator do all the work:
redBalloon.image = UIImage(named: "redBalloon")
redBalloon.contentMode = .scaleAspectFit
redBalloon.frame = CGRect(x: Int(xOrigin), y: 667, width: Int(redBalloon.frame.size.width), height: Int(redBalloon.frame.size.height))
let anim = UIViewPropertyAnimator(duration: 5, timingParameters: UICubicTimingParameters(animationCurve: .easeInOut))
anim.addAnimations {
self.redBalloon.frame = CGRect(x: Int(xEnding), y: -192, width: 166, height: 192)
}
anim.addCompletion { _ in
self.endGame()
}
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
redBalloon.isUserInteractionEnabled = true
redBalloon.addGestureRecognizer(imageTap)
anim.startAnimation()

UIScrollView Crashing after ReloadData

i have ScrollView in every row of tableView. i am assigning different tag to it.
it works perfectly for the first time. when change data in array and make ReloadData App Crashes.
Error is like
fatal error: unexpectedly found nil while unwrapping an Optional value
Piece of code
cell = tableView.dequeueReusableCell(withIdentifier: "ContentCell", for: indexPath)
let lblName = (cell.viewWithTag(31)! as! UILabel)
let lblSubmited = (cell.viewWithTag(32)! as! UILabel)
let lblFrom = (cell.viewWithTag(33)! as! UILabel)
let lblTo = (cell.viewWithTag(34)! as! UILabel)
let lblTotalHours = (cell.viewWithTag(35)! as! UILabel)
let lblapprove = (cell.viewWithTag(36)! as! UILabel)
lblName.text = dict.object(forKey: "name") as? String
lblSubmited.text = dict.object(forKey: "submitted") as? String
lblFrom.text = dict.object(forKey: "from") as? String
lblTo.text = dict.object(forKey: "to") as? String
lblTotalHours.text = dict.object(forKey: "tot") as? String
lblapprove.text = "Pending"
let scrollView:UIScrollView!
if(flag.object(at: indexPath.row) as! String == "0"){
scrollView = (cell.viewWithTag(3)! as! UIScrollView)
scrollView.tag = ((100 * indexPath.row)+1)
flag.replaceObject(at: indexPath.row, with: "1")
}
else{
scrollView = (cell.viewWithTag(((100 * indexPath.row)+1))! as! UIScrollView)
}
scrollView.delegate = self
scrollView.showsHorizontalScrollIndicator = false
let viewContent = (cell.viewWithTag(1000)!)
let btApprove = UIButton(frame: CGRect(x: 704.0, y: 10.0, width: 40.0, height: 40.0))
let btReject = UIButton(frame: CGRect(x: 788.0, y: 10.0, width: 40.0, height: 40.0))
let btDetail = UIButton(frame: CGRect(x: 860.0, y: 10.0, width: 40.0, height: 40.0))
btApprove.addTarget(self, action: #selector(self.approvePressedAction), for: .touchUpInside)
btReject.addTarget(self, action: #selector(self.rejectPressedAction), for: .touchUpInside)
btDetail.addTarget(self, action: #selector(self.detailPressedAction), for: .touchUpInside)
viewContent.addSubview(btApprove)
viewContent.addSubview(btReject)
viewContent.addSubview(btDetail)
return cell
error comes in
scrollView = (cell.viewWithTag(3)! as! UIScrollView)
line and crashes after reloadData. Any Solution?
Seems like you are forcing a lot of optionals to un-wrap, maybe check them first before trying to use them.
I have no idea what your logic is doing, but to run some checks on the specific line that crashes try something like this.
var scrollView:UIScrollView!
if(flag.object(at: indexPath.row) as! String == "0"){
if let view = cell.viewWithTag(3) {
if let sv = view as? UIScrollView {
scrollView = sv
scrollView.tag = ((100 * indexPath.row)+1)
flag.replaceObject(at: indexPath.row, with: "1")
} else {
print("view found with tag 3 but it's not a scrollview")
}
} else {
print("no view found with tag 3")
}
} else {
scrollView = (cell.viewWithTag(((100 * indexPath.row)+1))! as! UIScrollView)
}

UICollectionViewCell UIImage Lag even with dispatch_async

Symptom lag appears upon rendering a cell in collection view cell, I've recorded it here https://youtu.be/2utKOpHMshs
I'm not quite sure how the lag is happening and starting to suspect it has something to do with the recipe name element else rather than the UIImage since it's on another thread.
Async function
func asyncLoadImage(data: NSData, imageView: UIImageView) {
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
var image: UIImage!
NSLog("loading image")
image = UIImage(data: data)
dispatch_async(dispatch_get_main_queue()) {
imageView.image = image
NSLog("render image")
}
}
}
RecipeListViewController
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Storyboard.CellIdentifier, forIndexPath: indexPath) as!RecipeListCollectionViewCell
let recipe = recipes[indexPath.item] as! Recipe
cell.recipeName?.text = recipe.name?.uppercaseString
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale
if (recipe.photo != nil) {
asyncLoadImage(recipe.photo!, imageView: cell.recipeImageView)
}
return cell
}
UICollectionViewCell:init
recipeImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height-100))
recipeImageView.contentMode = UIViewContentMode.ScaleAspectFill
recipeImageView.clipsToBounds = true
self.addSubview(recipeImageView)
recipeName = UILabel(frame: CGRect(x: 0, y: frame.size.height-100, width: frame.size.width, height: 50))
recipeName.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1)
recipeName.textColor = UIColor.blackColor()
recipeName.textAlignment = NSTextAlignment.Center
recipeName.font = UIFont.boldSystemFontOfSize(18.00)
self.addSubview(recipeName)
The issue resolved by removing the following code
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale

UIView split transition

There is a good chance that I am just using the wrong terminology for this, but I have been looking to see if there is an iOS UIView transition that splits a view (BLUE) and any subview controls to reveal another view (RED) and its controls. I have found a couple of posts that mention something similar from 2011 but nothing recent, so was wondering if anything new had been added now we are upto iOS 8. Any pointers would be much appreciated.
If you are trying to do such split transition, I have created a animation controller for view controller transition. If you look at the code, you will find that there can be two different ways to transit, opening from view from the middle or the toview comes and collapses on the top of the from view.
Here is a small gif of how the code below works;
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
let presenting: Bool
init(presenting: Bool) {
self.presenting = presenting
}
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 1.0
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
animateOutImagesWithContext(transitionContext)
//animateInImagesWithContext(transitionContext)
}
func snapshotView(view: UIView!) -> UIImage {
UIGraphicsBeginImageContext(view.bounds.size)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return snapshotImage
}
func animateOutImagesWithContext(transitionContext:UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
let fromView = fromViewController!.view
let toView = toViewController!.view
containerView.addSubview(toView)
let snapshotImage = snapshotView(fromView)
fromView.removeFromSuperview()
let imageViews = animatingOutImageViews(snapshotImage)
containerView.addSubview(imageViews.firstImageView)
containerView.addSubview(imageViews.secondImageView)
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
let firstImageView = imageViews.firstImageView
let secondImageView = imageViews.secondImageView
if self.presenting {
firstImageView.frame = CGRectOffset(firstImageView.frame, -CGRectGetWidth(firstImageView.frame), 0)
secondImageView.frame = CGRectOffset(secondImageView.frame, CGRectGetWidth(secondImageView.frame), 0)
} else {
firstImageView.frame = CGRectOffset(firstImageView.frame, 0, -CGRectGetHeight(firstImageView.frame))
secondImageView.frame = CGRectOffset(secondImageView.frame, 0, CGRectGetHeight(secondImageView.frame))
}
}) { (completed: Bool) -> Void in
imageViews.firstImageView.removeFromSuperview()
imageViews.secondImageView.removeFromSuperview()
transitionContext.completeTransition(true)
}
}
func animateInImagesWithContext(transitionContext:UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
let fromView = fromViewController!.view
let toView = toViewController!.view
containerView.insertSubview(toView, belowSubview: fromView)
let snapshotImage = snapshotView(toView)
let imageViews = animatingInImageViews(snapshotImage)
containerView.addSubview(imageViews.firstImageView)
containerView.addSubview(imageViews.secondImageView)
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
let firstImageView = imageViews.firstImageView
let secondImageView = imageViews.secondImageView
if self.presenting {
firstImageView.frame = CGRectOffset(firstImageView.frame, 0, CGRectGetHeight(firstImageView.frame))
secondImageView.frame = CGRectOffset(secondImageView.frame, 0, -CGRectGetHeight(secondImageView.frame))
} else {
firstImageView.frame = CGRectOffset(firstImageView.frame, CGRectGetWidth(firstImageView.frame), 0)
secondImageView.frame = CGRectOffset(secondImageView.frame, -CGRectGetWidth(secondImageView.frame),0)
}
}) { (completed: Bool) -> Void in
fromView.removeFromSuperview()
imageViews.firstImageView.removeFromSuperview()
imageViews.secondImageView.removeFromSuperview()
transitionContext.completeTransition(true)
}
}
func animatingOutImageViews(snapshotImage: UIImage) -> (firstImageView: UIImageView!, secondImageView: UIImageView!)
{
let imageSize = snapshotImage.size
var firstPartFrame: CGRect
var secondPartFrame: CGRect
if presenting {
firstPartFrame = CGRectMake(0, 0, imageSize.width * 0.5, imageSize.height)
secondPartFrame = CGRectOffset(firstPartFrame, CGRectGetWidth(firstPartFrame), 0)
} else {
firstPartFrame = CGRectMake(0, 0, imageSize.width, imageSize.height * 0.5)
secondPartFrame = CGRectOffset(firstPartFrame, 0, CGRectGetHeight(firstPartFrame))
}
let firstImage = getImage(snapshotImage, insideRect: firstPartFrame)
let secondImage = getImage(snapshotImage, insideRect: secondPartFrame)
let firstImageView = UIImageView(frame: firstPartFrame)
firstImageView.image = firstImage
let secondImageView = UIImageView(frame: secondPartFrame)
secondImageView.image = secondImage
return (firstImageView, secondImageView)
}
func animatingInImageViews(snapshotImage: UIImage) -> (firstImageView: UIImageView!, secondImageView: UIImageView!)
{
let imageSize = snapshotImage.size
var firstPartFrame: CGRect
var secondPartFrame: CGRect
if presenting {
firstPartFrame = CGRectMake(0, 0, imageSize.width, imageSize.height * 0.5)
secondPartFrame = CGRectOffset(firstPartFrame, 0, CGRectGetHeight(firstPartFrame))
} else {
firstPartFrame = CGRectMake(0, 0, imageSize.width * 0.5, imageSize.height)
secondPartFrame = CGRectOffset(firstPartFrame, CGRectGetWidth(firstPartFrame), 0)
}
let firstImage = getImage(snapshotImage, insideRect: firstPartFrame)
let secondImage = getImage(snapshotImage, insideRect: secondPartFrame)
let firstImageView = UIImageView(image: firstImage)
let secondImageView = UIImageView(image: secondImage)
if presenting {
firstImageView.frame = CGRectOffset(firstPartFrame, 0, -CGRectGetHeight(firstPartFrame))
secondImageView.frame = CGRectOffset(secondPartFrame, 0, CGRectGetHeight(secondPartFrame))
} else {
firstImageView.frame = CGRectOffset(firstPartFrame, -CGRectGetWidth(firstPartFrame), 0)
secondImageView.frame = CGRectOffset(secondPartFrame, CGRectGetWidth(secondPartFrame), 0)
}
return (firstImageView, secondImageView)
}
func getImage(image: UIImage, insideRect rect:CGRect) -> UIImage {
let image = CGImageCreateWithImageInRect(image.CGImage, rect)!
return UIImage(CGImage: image)!
}
}
class SecondViewController: UIViewController, UIViewControllerTransitioningDelegate {
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init() {
super.init(nibName: nil, bundle: nil)
self.transitioningDelegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
let view1 = UIView(frame: CGRectZero)
view1.backgroundColor = UIColor.purpleColor()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
let view2 = UIView(frame: CGRectZero)
view2.backgroundColor = UIColor.cyanColor()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(view1)
view.addSubview(view2)
let views = [
"view1": view1,
"view2": view2
]
let vFormat = "V:|[view1][view2(==view1)]|"
let hFormat = "H:|[view1]|"
let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(hFormat,
options: .allZeros,
metrics: nil,
views: views)
let vConstraints = NSLayoutConstraint.constraintsWithVisualFormat(vFormat,
options: .AlignAllLeft | .AlignAllRight,
metrics: nil,
views: views)
view.addConstraints(hConstraints)
view.addConstraints(vConstraints)
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: "tapped")
view.addGestureRecognizer(tapGestureRecognizer)
}
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AnimationController(presenting: true)
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AnimationController(presenting: false)
}
func tapped() {
let nextViewController = NextViewController()
dismissViewControllerAnimated(true, completion: nil)
}
}
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view1 = UIView(frame: CGRectZero)
view1.backgroundColor = UIColor.redColor()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
let view2 = UIView(frame: CGRectZero)
view2.backgroundColor = UIColor.greenColor()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(view1)
view.addSubview(view2)
let views = [
"view1": view1,
"view2": view2
]
let hFormat = "H:|[view1][view2(==view1)]|"
let vFormat = "V:|[view1]|"
let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(hFormat,
options: .AlignAllTop | .AlignAllBottom,
metrics: nil,
views: views)
let vConstraints = NSLayoutConstraint.constraintsWithVisualFormat(vFormat,
options: .allZeros,
metrics: nil,
views: views)
view.addConstraints(hConstraints)
view.addConstraints(vConstraints)
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: "tapped")
view.addGestureRecognizer(tapGestureRecognizer)
}
func tapped() {
let secondViewController = SecondViewController()
presentViewController(secondViewController, animated: true, completion: nil)
}
}
The code might be little longer but has to be easy to understand. Tune up a little if you want.
There is no such built in transition in iOS. You have to make it yourself. One way to do this would be by using the UIViewControllerAnimatedTransitioning protocol, and doing a custom presentation. The animation steps that would be carried out by the custom animator object would be something like this,
1) create two half images of the blue view, and add them to the transitionContext's containerView (you can't split a UIView in half, so you need to use an image of it instead)
2) add the red controller's view to the transitionContext's containerView underneath the half images.
3) remove the blue view
4) slide the two half images off the screen by animating their constraint constant values.
You could use something like:
UIView *redView = [[UIView alloc]initWithFrame:CGRectMake(self.view.frame.size.width / 2, 0, 1, self.view.frame.size.height)];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
[UIView animateWithDuration:1 animations:^{
redView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
} completion:^(BOOL finished) {
UIViewController2 *viewController = [UIViewController2 new];
[self presentViewController:viewController animated:NO completion:^{
[redView removeFromSuperview];
}];
}];
on button click.

Resources