子类化 UIView 的正确做法? [英] Proper practice for subclassing UIView?

查看:20
本文介绍了子类化 UIView 的正确做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一些基于 UIView 的自定义输入控件,我正在尝试确定设置视图的正确做法.使用 UIViewController 时,使用 loadView 和相关的 viewWillviewDid 方法相当简单,但是当继承 UIView 时,最接近的方法我有 `awakeFromNibdrawRectlayoutSubviews.(我正在考虑设置和拆卸回调.)就我而言,我正在 layoutSubviews 中设置我的框架和内部视图,但我在屏幕上看不到任何内容.

I'm working on some custom UIView-based input controls, and I'm trying to ascertain proper practice for setting up the view. When working with a UIViewController, it's fairly simple to use the loadView and related viewWill, viewDid methods, but when subclassing a UIView, the closest methosds I have are `awakeFromNib, drawRect, and layoutSubviews. (I'm thinking in terms of setup and teardown callbacks.) In my case, I'm setting up my frame and internal views in layoutSubviews, but I'm not seeing anything onscreen.

确保我的视图具有我想要的正确高度和宽度的最佳方法是什么?(无论我是否使用自动布局,我的问题都适用,尽管可能有两个答案.)正确的最佳实践"是什么?

What is the best way to ensure that my view has the correct height and width that I want it to have? (My question applies regardless of if I'm using autolayout, although there might be two answers.) What's the proper "best practice"?

推荐答案

Apple 在文档中非常清楚地定义了如何对 UIView 进行子类化.

Apple defined pretty clearly how to subclass UIView in the doc.

查看下面的列表,尤其是查看initWithFrame:layoutSubviews.前者用于设置 UIView 的框架,而后者用于设置框架及其子视图的布局.

Check out the list below, especially take a look at initWithFrame: and layoutSubviews. The former is intended to setup the frame of your UIView whereas the latter is intended to setup the frame and the layout of its subviews.

还请记住,只有当您以编程方式实例化 UIView 时,才会调用 initWithFrame:.如果您从 nib 文件(或故事板)加载它,将使用 initWithCoder:.而在 initWithCoder: 中,框架还没有计算出来,所以你不能修改你在 Interface Builder 中设置的框架.正如在此答案中建议的 ,您可能会考虑调用 initWithFrame: 来自 initWithCoder: 以设置框架.

Also remember that initWithFrame: is called only if you are instantiating your UIView programmatically. If you are loading it from a nib file (or a storyboard), initWithCoder: will be used. And in initWithCoder: the frame hasn't been calculated yet, so you cannot modify the frame you set up in Interface Builder. As suggested in this answer you may think of calling initWithFrame: from initWithCoder: in order to setup the frame.

最后,如果你从一个笔尖(或故事板)加载你的 UIView,你还有 awakeFromNib 机会来执行自定义框架和布局初始化,因为当 awakeFromNib 被调用以保证层次结构中的每个视图都已取消归档和初始化.

Finally, if you load your UIView from a nib (or a storyboard), you also have the awakeFromNib opportunity to perform custom frame and layout initializations, since when awakeFromNib is called it's guaranteed that every view in the hierarchy has been unarchived and initialized.

来自NSNibAwaking(现在被 awakeFromNib):

可以从awakeFromNib 中安全地向其他对象发送消息——届时可以确保所有对象都已取消归档和初始化(当然,虽然不一定被唤醒)

Messages to other objects can be sent safely from within awakeFromNib—by which time it’s assured that all the objects are unarchived and initialized (though not necessarily awakened, of course)

还值得注意的是,使用自动布局,您不应显式设置视图的框架.相反,您应该指定一组足够的约束,以便布局引擎自动计算框架.

It's also worth noting that with autolayout you shouldn't explicitly set the frame of your view. Instead you are supposed to specify a set of sufficient constraints, so that the frame is automatically calculated by the layout engine.

直接来自文档:

  • initWithFrame: 建议您实现此方法.此外,您还可以实现自定义初始化方法,或者代替这种方法.

Methods to Override

Initialization

  • initWithFrame: It is recommended that you implement this method. You can also implement custom initialization methods in addition to, or instead of, this method.

initWithCoder: 如果您从 Interface Builder nib 文件加载视图并且您的视图需要自定义,请实现此方法初始化.

initWithCoder: Implement this method if you load your view from an Interface Builder nib file and your view requires custom initialization.

layerClass 仅当您希望视图为其后备存储使用不同的核心动画层时才实现此方法.例如,如果您使用 OpenGL ES 进行绘图,您会想要覆盖此方法并返回 CAEAGLLayer 类.

layerClass Implement this method only if you want your view to use a different Core Animation layer for its backing store. For example, if you are using OpenGL ES to do your drawing, you would want to override this method and return the CAEAGLLayer class.

  • drawRect: 如果您的视图绘制自定义内容,请实现此方法.如果您的视图没有进行任何自定义绘图,请避免覆盖它方法.

  • drawRect: Implement this method if your view draws custom content. If your view does not do any custom drawing, avoid overriding this method.

drawRect:forViewPrintFormatter: 仅当您想在打印期间以不同方式绘制视图内容时才实现此方法.

drawRect:forViewPrintFormatter: Implement this method only if you want to draw your view’s content differently during printing.

  • requiresConstraintBasedLayout 如果您的视图类需要约束才能正常工作,请实现此类方法.

  • requiresConstraintBasedLayout Implement this class method if your view class requires constraints to work properly.

updateConstraints 如果您的视图需要在子视图之间创建自定义约束,请实现此方法.

updateConstraints Implement this method if your view needs to create custom constraints between your subviews.

alignmentRectForFrame:, frameForAlignmentRect: 实现这些方法来覆盖你的视图对齐方式其他视图.

alignmentRectForFrame:, frameForAlignmentRect: Implement these methods to override how your views are aligned to other views.

  • sizeThatFits: 如果您希望视图的默认大小与调整大小时通常不同,请实现此方法操作.例如,您可以使用此方法来防止您的视图从缩小到无法显示子视图的地步正确.

  • sizeThatFits: Implement this method if you want your view to have a different default size than it normally would during resizing operations. For example, you might use this method to prevent your view from shrinking to the point where subviews cannot be displayed correctly.

layoutSubviews 如果您需要比约束或提供自动调整大小的行为.

layoutSubviews Implement this method if you need more precise control over the layout of your subviews than either the constraint or autoresizing behaviors provide.

didAddSubview:, willRemoveSubview: 根据需要实现这些方法来跟踪添加和删除子视图.

didAddSubview:, willRemoveSubview: Implement these methods as needed to track the additions and removals of subviews.

willMoveToSuperview:, didMoveToSuperview 根据需要实现这些方法来跟踪当前的移动在你看来层次结构.

willMoveToSuperview:, didMoveToSuperview Implement these methods as needed to track the movement of the current view in your view hierarchy.

willMoveToWindow:, didMoveToWindow 根据需要实现这些方法来跟踪视图的移动到另一个窗口.

willMoveToWindow:, didMoveToWindow Implement these methods as needed to track the movement of your view to a different window.

  • touchesBegan:withEvent:touchesMoved:withEvent:touchesEnded:withEvent:, touchesCancelled:withEvent: 实现如果您需要直接处理触摸事件,请使用这些方法.(为了基于手势的输入,使用手势识别器.)

  • touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, touchesCancelled:withEvent: Implement these methods if you need to handle touch events directly. (For gesture-based input, use gesture recognizers.)

gestureRecognizerShouldBegin: 如果您的视图直接处理触摸事件并且可能想要防止附加手势识别器触发其他操作.

gestureRecognizerShouldBegin: Implement this method if your view handles touch events directly and might want to prevent attached gesture recognizers from triggering additional actions.

这篇关于子类化 UIView 的正确做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆