UIView子类化的适当做法?(Proper practice for subclassing UIView?)

编程入门 行业动态 更新时间:2024-10-15 14:17:29
UIView子类化的适当做法?(Proper practice for subclassing UIView?)

我正在开发一些基于UIView的自定义输入控件,我正在努力确定设置视图的正确做法。 当使用UIViewController时,使用loadView和相关的viewWill , viewDid方法是相当简单的,但是当子类化UIView时,最近的methosds是`awakeFromNib , drawRect和layoutSubviews 。 (我正在考虑安装和拆卸回调。)在我的情况下,我在layoutSubviews设置我的框架和内部视图,但我没有看到任何屏幕上。

确保我的观点具有正确的高度和宽度,我想要的最好的方式是什么? (我的问题适用,无论我是否使用autolayout,虽然可能有两个答案。)什么是适当的“最佳实践”?

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"?

最满意答案

苹果定义很清楚如何在文档UIView类化UIView 。

看看下面的列表,特别是看看initWithFrame:和layoutSubviews 。 前者旨在设置您的UIView的框架,而后者旨在设置框架和其子视图的布局。

还要记住,只有当您以编程方式实例化UIView才调用initWithFrame: 如果从nib文件(或故事板)加载,将使用initWithCoder: 而在initWithCoder:框架尚未计算,因此您无法修改在Interface Builder中设置的框架。 如本答案中所提到的,您可能会想到从initWithCoder:调用initWithFrame:为了设置帧。

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

从NSNibAwaking的文件

对其他对象的消息可以从awakeFromNib中安全地发送 - 在那个时候,可以确保所有对象都被取消存档和初始化(当然不一定被唤醒)

还有一点值得注意的是,使用autolayout你不应该明确地设置你的视图的框架。 相反,您应该指定一组足够的约束,以便框架由布局引擎自动计算。

直接从文档 :

覆盖方法

初始化

initWithFrame:建议您实现此方法。 您还可以实现自定义初始化方法,除此之外,也可以替代该方法。

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

layerClass仅当您希望视图为其后备存储使用不同的Core Animation图层layerClass实现此方法。 例如,如果您使用OpenGL ES来绘制图形,则需要覆盖此方法并返回CAEAGLLayer类。

绘图和印刷

drawRect:如果您的视图绘制自定义内容,则执行此方法。 如果您的视图不执行任何自定义绘图,请避免覆盖此方法。

drawRect:forViewPrintFormatter:仅当您希望在打印期间绘制视图的内容时,才能实现此方法。

约束

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

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

alignmentRectForFrame:frameForAlignmentRect:实现这些方法来覆盖视图如何与其他视图对齐。

布局

sizeThatFits:如果您希望视图具有与调整大小操作期间通常不同的默认大小,请执行此方法。 例如,您可以使用此方法来阻止视图缩小到无法正确显示子视图的位置。

layoutSubviews如果需要对子视图的布局进行更精确的控制,而不是约束或自动调整行为提供,则实施此方法。

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

willMoveToSuperview: didMoveToSuperview根据需要实现这些方法来跟踪视图层次结构中当前视图的移动。

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

事件处理:

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

gestureRecognizerShouldBegin:如果您的视图直接处理触摸事件,并且可能希望阻止附加的手势识别器触发其他操作,请执行此方法。

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

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.

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.

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.

From the doc of NSNibAwaking (now superseded by the doc of 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.

Straight from the documentation:

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: Implement this method if you load your view from an Interface Builder nib file and your view requires custom initialization.

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.

Drawing and printing

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: Implement this method only if you want to draw your view’s content differently during printing.

Constraints

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

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

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

Layout

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 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: Implement these methods as needed to track the additions and removals of subviews.

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

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

Event Handling:

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: Implement this method if your view handles touch events directly and might want to prevent attached gesture recognizers from triggering additional actions.

更多推荐

本文发布于:2023-08-07 00:21:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1459438.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:子类   做法   UIView   subclassing   practice

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!