Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS autolayout-move a view located inside a tableviewcell to the center of the screen

I have a tableview with cells containing text views as well as imageviews. My project is currently using AutoLayout. My goal is to get the imageview to display in fullscreen when it is tapped. One option is to use a modal view controller, but I want to have this work sort of like the way tapping on images in the facebook app works, the app centers the image and fades the background.

Since I'm using autolayout, I cannot simply set the frame of the imageview to fill the screen. Instead, I need to use autolayout constraints. My image view has 5 constraints, a constraint setting a distance from the bottom of the cell, as well as the left an right sides, and one controlling the image height. The last is a vertical space constraint between the textview above the image view and the top of the image. While this would appear to conflict with the height and bottom constraints, for some reason interface builder forces me to have this. To avoid problems, I set this constraint's priority to be less than 1000 (the image should never overlap the textview anyways, since the tableview cell height is set so everything will fit perfectly).

To center the image, I set the distance from the left and right to be zero and remove the vertical space constraint. In order to center the image, I replace the bottom space constraint with a center y alignment constraint to the UIWindow as opposed to the tableviewcell. I want to have it be in the center of the screen, not the cell.

To get the main window I use this:

AppDelegate* myDelegate = (((AppDelegate*) [UIApplication sharedApplication].delegate));
//access main window using myDelegate.window

Then, to set the constraint:

//currently sets the distance from the bottom of the cell to 14
//changing it...
[cellselected removeConstraint:cellselected.imagebottomspace];
cellselected.imagebottomspace = [NSLayoutConstraint constraintWithItem:cellselected.viewimage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:myDelegate.window attribute:NSLayoutAttributeCenterY multiplier:0 constant:0];
[cellselected addConstraint:cellselected.imagebottomspace];

However, this doesn't work. The changes in the width and height of the image view apply just fine. However, when readding the imagebottomspace constraint, I get an unsatisfiable layout--apparently the constraint conflicts with another constraint which sets the distance between the bottom and the image view to 14, the very constraint I just removed. So it seems that it isn't actually removing the constraint.

When I proceed and let the app break a constraint, the imageview moves, but to the wrong place. It isn't centering in the screen. It moves way up and off the screen.

Obviously what I'm doing isn't right. What am I doing wrong?

like image 261
benjih555 Avatar asked Mar 23 '23 07:03

benjih555


1 Answers

So I guess you want something like this:

zooming image view demo

First, you need to know that as of Xcode 4.6.3, the nib editor (“Interface Builder”) has a bug when setting up constraints in a table view cell. It should create the constraints between the subviews and the cell's content view, but instead it creates the constraints between the subviews and the cell itself. This tends to screw up layout at runtime. (This bug is fixed in Xcode 5 and later.)

The consequence of this is that you should either remove all of the constraints that were in the nib and recreate them in code, or just get rid of the nib and create the cell's entire view hierarchy in code.

Second, there's an easier way to do the image zooming. Here's the basic procedure when a cell is selected:

  1. Convert the selected cell's image view bounds to a CGRect in the top-level view's coordinate system.
  2. Create a new image view just for zooming and set its frame to that CGRect. Set its userInteractionEnabled to YES. Set its autoresizingMask to flexible width and height. Add a tap gesture recognizer.
  3. Add the new image view as a subview of the top-level view.
  4. Set the cell's image view's hidden property to YES.
  5. In an animation block, set the new image view's frame to the top-level view's bounds.
  6. Disable the table view's panGestureRecognizer.

When the new image view is tapped, reverse the procedure:

  1. Convert the selected cell's image view bounds to a CGRect in the top-level view's coordinate system.
  2. In an animation block, set the zoomed image view's frame to that CGRect.
  3. In the animation completion block:
    1. Remove the zoomed image view from its superview.
    2. Set the cell's image view's hidden property to NO.
    3. Enable the table view's panGestureRecognizer.

Since you're not moving the original image view, you don't have to mess with its constraints. Hidden views still participate in layout.

Since you're creating the new image view in code, it will have translatesAutoresizingMaskIntoConstraints set to YES by default. This means that you can just set its frame. Auto layout will automatically turn the frame into constraints.

You can find the full source code in this github repository.

like image 161
rob mayoff Avatar answered Apr 26 '23 04:04

rob mayoff