简体   繁体   English

iOS自动布局 - 将位于tableviewcell内的视图移动到屏幕中心

[英]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. 我有一个包含文本视图和图像视图的单元格的tableview。 My project is currently using AutoLayout. 我的项目目前正在使用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. 一个选项是使用模态视图控制器,但我想让这项工作有点像在Facebook应用程序中点击图像的方式工作,应用程序使图像居中并淡化背景。

Since I'm using autolayout, I cannot simply set the frame of the imageview to fill the screen. 由于我使用autolayout,我不能简单地设置imageview的框架来填充屏幕。 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. 我的图像视图有5个约束,约束设置距单元格底部的距离,以及左侧和右侧,以及控制图像高度的约束。 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). 为了避免出现问题,我将此约束的优先级设置为小于1000(无论如何,图像永远不会与textview重叠,因为tableview单元格高度设置为所有内容都完全适合)。

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. 为了使图像居中,我将带有中心y对齐约束的底部空间约束替换为UIWindow而不是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. 然而,当读取imagebottomspace约束时,我得到一个不可满足的布局 - 显然约束与另一个约束冲突,该约束将底部和图像视图之间的距离设置为14,这是我刚刚删除的约束。 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. 当我继续让app破坏约束时,imageview会移动,但会移动到错误的位置。 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? 我究竟做错了什么?

So I guess you want something like this: 所以我想你想要这样的东西:

缩放图像视图演示

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. 首先,您需要知道从Xcode 4.6.3开始,在表视图单元格中设置约束时,nib编辑器(“Interface Builder”)存在错误。 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.) (此错误在Xcode 5及更高版本中得到修复。)

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. 这样做的结果是你应该删除nib中的所有约束并在代码中重新创建它们,或者只是去除nib并在代码中创建单元格的整个视图层次结构。

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. 将选定单元格的图像视图边界转换为顶级视图坐标系中的CGRect
  2. Create a new image view just for zooming and set its frame to that CGRect . 创建一个新的图像视图只是为了缩放,并将其框架设置为该CGRect Set its userInteractionEnabled to YES . 将其userInteractionEnabled设置为YES Set its autoresizingMask to flexible width and height. 将其autoresizingMask设置为灵活的宽度和高度。 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 . 将单元格的图像视图的hidden属性设置为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 . 禁用表视图的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. 将选定单元格的图像视图边界转换为顶级视图坐标系中的CGRect
  2. In an animation block, set the zoomed image view's frame to that CGRect . 在动画块中,将缩放图像视图的帧设置为该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 . 将单元格的图像视图的hidden属性设置为NO
    3. Enable the table view's panGestureRecognizer . 启用表视图的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. 既然你在代码中创建的新的图像视,它将有translatesAutoresizingMaskIntoConstraints设置为YES默认。 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 . 您可以在此github存储库中找到完整的源代码。

I've just come across a similar issue. 我刚遇到类似的问题。 I think that the reason for these problems are that the views embedded in UIScrollViews exist in a different bounds system to those of the views outside it. 我认为这些问题的原因是UIScrollViews中嵌入的视图存在于与其外部视图不同的边界系统中。 This is effectively how scrolling works in the first place, think of it as just applying a variable offset to the views it contains. 这实际上是滚动首先如何工作,将其视为仅将变量偏移应用于它包含的视图。 Autolayout doesn't know how to translate between these different coordinate systems so any constraints that bridge across aren't going to be applied the way you expect. Autolayout不知道如何在这些不同的坐标系之间进行转换,因此任何桥接的约束都不会以您期望的方式应用。

To quote from Erica Sadun's excellent book iOS Auto Layout Demystified (from the section 'Constraints, Hierarchies, and Bounds Systems'): 引用Erica Sadun的优秀书籍iOS Auto Layout Demystified(来自“约束,层次结构和边界系统”一节):

"Be aware of bounds systems. You should not relate a button on some view, for example, with a text field inside a separate collection view. If there's some sort of content view with its own bounds system (such as collection views, scroll views, and table views), don't hop out of that to an entirely different bounds system in another view." “请注意边界系统。您不应该将某个视图上的按钮与单独的集合视图中的文本字段相关联。如果某种内容视图具有自己的边界系统(例如集合视图,滚动视图) ,和表视图),不要跳到另一个视图中完全不同的边界系统。“

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM