Directorio de artículos
- kit de interfaz de usuario
- CALayer y UIView
- UITableView
- Ciclo de vida de ViewController
- UIViewController y UIResponder
- marco和límites
kit de interfaz de usuario
#import <UIKit/UIKit.h>
El marco UIKit proporciona la infraestructura necesaria para una aplicación iOS o tvOS. Proporciona la arquitectura de ventana y vista para implementar la interfaz, la infraestructura de manejo de eventos para proporcionar entrada multitáctil y otros tipos de entrada a la aplicación, y el ciclo de ejecución principal necesario para administrar la interacción entre el usuario, el sistema y el aplicación Otras características proporcionadas por el marco incluyen soporte de animación, soporte de documentos, soporte de dibujo e impresión, información sobre el dispositivo actual, administración y visualización de texto, soporte de búsqueda, soporte de accesibilidad, soporte de extensión de aplicaciones y administración de recursos.
Componentes de UIKit de uso común
- UIView y sus subclases, incluidas UIScrollView (UITableView, UICollectionView, UITextView), UILabel, UIControl (UIButton, UITextField), UIPickerView, etc.;
- Configuración y control de gráficos, dibujos, impresiones, texto, etc. que están relacionados con los controles pero que las personas no pueden ver de manera intuitiva, incluidos UIViewController, UIImage, etc.
Ventajas de la carga diferida
Lazy loading (lazy loading) retrasa al máximo la instanciación de los objetos, es decir, el recurso no se carga cuando se inicia la aplicación, y solo se carga cuando se utiliza en tiempo de ejecución (on-demand loading).
Por ejemplo, si se carga una gran cantidad de recursos de datos, imágenes, audio y video al mismo tiempo después de iniciar la aplicación, la memoria del dispositivo móvil puede agotarse. En este momento, se puede utilizar la tecnología de carga diferida. Específicamente, reescriba el método getter del atributo, primero juzgue si el atributo es nulo y ejecútelo si está vacío; de lo contrario, devuelva el atributo directamente.
Las ventajas de la carga diferida son: no es necesario escribir todo el código para crear objetos en el método viewDidLoad y el código es más legible; cada control es responsable de su propio procesamiento de creación de instancias y el acoplamiento de código es bajo; es No es necesario cargar todos los objetos en la fase de inicialización. Datos, guardar memoria, es decir, se reducirá el uso de memoria del sistema; reducir la presión del lado del servidor.
CALayer y UIView
la diferencia
UIView
Heredado de UIResponder
, principalmente responsable de la transmisión de eventos, respuesta de eventos, pertenece al UIKit
marco basado
CALayer
en NSObject
, responsable de la representación de imágenes, animación y visualización de vistas, pertenece al QuartzCore
marco
Estos dos contenidos se ajustan al principio de culpabilidad única,
aunque CALayer
no tenemos la capacidad de responder a las incidencias, podemos
hitTest
convert
Dos métodos para determinar si el evento está activado layer
, para agregar un evento de clic al evento
relación
- Todos los elementos de la interfaz heredan de
UIView
. La parte de dibujo real esCALayer
manejada por la clase.UIView
Es más como unCALayer
administrador, acceder a sus atributos relacionados con el dibujo y las coordenadas, comoframe
y,bounds
etc., en realidad está accediendoCALayer
a los atributos relacionados que contiene internamente. UIView
Hay unalayer
propiedad que devuelve suCALayer
instancia principal.UIView
Hay unlayerClass
método que devuelvelayer
la clase utilizada por el principal (el valor predeterminado es[CALayer class]
),UIView
y las subclases se pueden mostrarUIView
de manera diferente al sobrecargar este métodoCALayer
.UIView
La estructura de subárbolCALayer
similar de , también puede agregarle subárboles para completar algunas representaciones especialesUIView
view
layer
layer
UIView *firstView = [[UIView alloc] init];
firstView.frame = CGRectMake(200, 200, 200, 200);
firstView.backgroundColor = [UIColor redColor];
[self.view addSubview:firstView];
CALayer *layer = [[CALayer alloc] init];
layer.backgroundColor = [[UIColor greenColor] CGColor];
layer.position = CGPointMake(100,100); //中心点
layer.bounds = CGRectMake(100,100,80,80);
[firstView.layer addSublayer:layer];
No se agrega una nueva capa, pero se agrega una nueva capa a la vista original, que no es lo mismo que addsubview:
CALayer
Se le puede agregarUIView
una estructura de subárbol similar a la estructura de vista , similar a agregar hacia arriba , para completar algunas representaciones especiales.view
layer
子layer
View
View
UIVIew
Lalayer
estructura de árbol está dentro del sistema y es mantenida por el sistema.三份copy
-
- La primera,
逻辑树
en ella se puede operar el código, por ejemplo,【比如frame\bounds】
en esta se puede operar cambiando las propiedades de la capa a través del código
- La primera,
-
- La segunda parte,
动画树
, es una capa intermedia, donde el sistema cambia los atributos y realiza varias operaciones de renderizado.
- La segunda parte,
-
- El tercero,
显示树
es el contenido del árbol que se muestra actualmente en la pantalla.
- El tercero,
UITableView
Los dos delegados seguidos por UITableView y los métodos que deben implementarse
UITableView
Se necesita una fuente de datos (dataSource
) para mostrar los datos, yUITableView
se le preguntará a la fuente de datos cuántas filas de datos hay y qué datos se muestran en cada fila, etc. Es solo un caparazón vacío sin configurar la fuente de datosUITableView
. CualquierUITableViewDataSource
objeto OC que cumpla con el protocolo puede serUITableView
una fuente de datos.- También necesitamos
UITableView
configurar el objeto proxy (delegate
) paraUITableView
el procesamiento correspondiente cuando se activan ciertos eventos, como seleccionar una fila determinada. Cualquier objeto OC que cumpla conUITableViewDelegate
el acuerdo. Ambos pueden serUITableView
objetos proxy y , en general, permiten que el controlador actúeUITableView
como un objeto proxy, y la implementación se realiza implementando manualmente algunos métodos en el protocolo.dataSource
delegate
tableView
fuente de datos :
//返回组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
//返回每组里的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
//cell的实现
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
delegado :
//返回每行高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
//不必须实现,cell点击事件
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Los cuatro anteriores deben implementar el orden de ejecución del método.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(@"numberOfSectionsInTableView");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(@"numberOfRowsInSection");
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
NSLog(@"cellForRowAtIndexPath");
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"heightForRowAtIndexPath");
return 20;
}
resultado:
- numberOfSectionsInTableView
- numeroDeFilasEnLaSeccion
- cellForRowAtIndexPath
- heightForRowAtIndexPath
Orden de ejecución de otros métodos:
La primera ronda:
1. numberOfSectionsInTableView: Si la sección=2, esta función solo se ejecuta una vez, si la sección=0, la función no se ejecuta, el valor predeterminado es 1
2, heightForHeaderInSection, se ejecuta dos veces, el número de ejecuciones de esta función es número de sección
3, heightForFooterInSection, las propiedades de la función son las mismas que las anteriores, se ejecutan dos veces
4, numberOfRowsInSection, este método se ejecuta una vez
5, heightForHeaderInSection, este método se ejecuta dos veces, en realidad estoy un poco confundido por qué se llama este método aquí
6, heightForFooterInSection, este método se ejecuta dos veces,
7, numberOfRowsInSection , ejecutar una vez
8, heightForRowAtIndexPath, altura de fila, primero ejecutar sección=0, la fila correspondiente multiplicada por la
segunda ronda:
1, numberOfSectionsInTableView, una vez
2, heightForHeaderInSection, sección multiplicada por
3, heightForFooterInSection, sección veces
4, numberOfRowsInSection, una vez
5, heightForHeaderInSection, ejecutar sección veces
6, heightForFooterInSection, ejecutar sección veces
7, numberOfRowsInSection, ejecutar una vez
8. heightForRowAtIndexPath, altura de fila, ejecutar primero una vez
9. cellForRowAtIndexPath
10, willDisplayCell
y luego ejecutar 8, 9, 10 en secuencia hasta que se dibujen todas las celdas
La diferencia entre UICollectionView y UITableView
- Cada fila puede mostrar diseños múltiples y más diversos
- Dado que una fila puede mostrar varias vistas, la fila no se puede expresar con precisión, por lo que se introduce el elemento
- Solo nosotros podemos implementar todas las vistas (debemos implementar celdas personalizadas)
En lo que respecta a los estilos personalizados, hay un atributo en Layout llamado UICollectionViewLayoutAttributes
@property (nonatomic) CGRect frame;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGSize size;
@property (nonatomic) CATransform3D transform3D;
@property (nonatomic) CGRect bounds API_AVAILABLE(ios(7.0));
@property (nonatomic) CGAffineTransform transform API_AVAILABLE(ios(7.0));
@property (nonatomic) CGFloat alpha;
@property (nonatomic) NSInteger zIndex; // default is 0
@property (nonatomic, getter=isHidden) BOOL hidden; // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES
@property (nonatomic, strong) NSIndexPath *indexPath;
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
@property (nonatomic, readonly, nullable) NSString *representedElementKind; // nil when
Los ejemplos que se pueden ver UICollectionViewLayoutAttributes
incluyen información como el borde, el punto central, el tamaño, la forma, la transparencia, la relación jerárquica, si ocultar, etc.
Cada celda corresponderá a una Attributes
. La lógica general, al establecer el valor predeterminado layout
, layout
establece el correspondiente a cada celda y luego asigna Attributes
el todo a .layout
collectionView
La diferencia entre UICollectionViewFlowLayout y UICollectionViewLayout
UICollectionViewLayout
Es una clase abstracta La clase abstracta solo define algunos atributos y comportamientos comunes de las subclases, que no se pueden usar directamente.UICollectionViewFlowLayout
Es un diseño de flujo, y los controles de la interfaz de usuario serán como agua de flujo, una fila está llena y la siguiente fila se llena automáticamente.
El método que se reescribirá cuando se personalice UICollectionViewFlowLayout
-(void)prepareLayout
prepare方法被自动调用,以保证layout实例的正确。
-(CGSize)collectionViewContentSize
返回collectionView的内容的尺寸
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
1. 返回rect中的所有的元素的布局属性
2. 返回的是包含UICollectionViewLayoutAttributes的NSArray
3. UICollectionViewLayoutAttributes可以是cell,追加视图或装饰视图的信息,通过不同的UICollectionViewLayoutAttributes初始化方法可以得到不同类型的UICollectionViewLayoutAttributes:
1)layoutAttributesForCellWithIndexPath:
2)layoutAttributesForSupplementaryViewOfKind:withIndexPath:
3)layoutAttributesForDecorationViewOfKind:withIndexPath:
-(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
返回对应于indexPath的位置的cell的布局属性
-(UICollectionViewLayoutAttributes )layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath
返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载
-(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath )indexPath
返回对应于indexPath的位置的装饰视图的布局属性,如果没有装饰视图可不重载
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。
Secuencia de llamadas:
1)-(void)prepareLayout
a. collection view 只会在第一次layout的时候调用一次`-prepareLayout`,作为第一次通知layout实例对象的消息
b. collection view 会在 layout 对象 invalidated 之后并且requerying之前再次调用
c. 继承自UICollectionViewLayout都需要重写这个方法,一般都是在这个方法里面准备好`layoutAttributesForElements(in:)`这个方法要使用到的`UICollectionViewLayoutAttributes`数组。
2) -(CGSize) collectionViewContentSize
a. 确定collectionView的所有内容的尺寸
b. 每一次移动collection view时都会调用这个方法,并且这个方法会被调用多次
3)-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
初始的layout的外观将由该方法返回的UICollectionViewLayoutAttributes来决定。
4)在需要更新layout时,需要给当前layout发送
1)-invalidateLayout, 该消息会立即返回,并且预约在下一个loop的时候刷新当前layout
2)-prepareLayout,
3)依次再调用-collectionViewContentSize和-layoutAttributesForElementsInRect来生成更新后的布局。
Dos formas de calcular la altura de la fila manualmente
- tamaño para ajustar
- delimitandoRectConTamaño
La diferencia entre sizeToFit y sizeThatFit:
-(CGSize)sizeThatFits:(CGSize)size;
Devolverá el tamaño más adecuado, pero no cambiará el tamaño del marco de la vista original-(void)sizeToFit;
Se llamará internamente al método - (CGSize)sizeThatFits:(CGSize)size; para obtener el tamaño más adecuado y usar este tamaño para ajustar el tamaño del marco de la vista actual.
En pocas palabras: - (CGSize)sizeThatFits:(CGSize)size;
y - (void)sizeToFit;
ambos u obtener el Tamaño más adecuado, pero - (CGSize)sizeThatFits:(CGSize)size;
no cambiará el marco de la imagen original, solo devolverá un tamaño, pero - (void)sizeToFit;
calculará el Tamaño más adecuado para usted y ajustará su tamaño actual de acuerdo con este Tamaño El marco de la vista
delimitandoRectConTamaño
Devuelve el espacio rectangular que ocupa el dibujo del texto.
CGRect rect=[(NSString *)obj boundingRectWithSize:CGSizeMake(1000, FONTHEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{
NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.width;
Los parámetros internos son los siguientes:
obj
Hace referencia a la cadena que se va a calcular y mostrarboundingRectWithSize
Indica las restricciones calculadas de ancho y alto- Al calcular la altura, el ancho debe ser fijo:
CGSizeMake(1000, CGFLOAT_MAX)
- El 1000 aquí también se puede reemplazar por el ancho del control que se ha determinado
self.label.width
- El resultado del cálculo indica que cuando el ancho es como máximo 1000 y la altura es ilimitada, la altura requerida para mostrar la cadena completa
- Al calcular el ancho, la altura debe ser fija:
CGSizeMake(CGFLOAT_MAX, 200)
- Del mismo modo, 200 también se puede reemplazar con una altura conocida:
self.label.height
- El resultado del cálculo indica que cuando la altura no supera los 200, el ancho requerido para realizar la cuerda dada es completamente requerido
options
es una opción adicional para el dibujo de texto yNSStringDrawingUsesLineFragmentOrigin
es la línea de base predeterminadaattributes
Formato de diccionario, que restringe el estilo de visualización de las cadenas y, en general, restringe más fuentes, como:@{NSFontAttributeName:[UIFont systemFontOfSize:16]}
context
Incluye información sobre cómo ajustar el espaciado entre palabras y la escala. En última instancia, este objeto contiene información que se utilizará para dibujar texto. Generalmente escribe cero.
Ciclo de vida de ViewController
[iOS] - Ciclo de vida de ViewController
loadView
: vista de carga. En este método, la vista se carga oficialmente y la vista del controlador se carga mediante carga diferida, es decir, se carga cuando se usa. En el proceso de carga de la vista, primero se llamará al método loadView, y algunas tareas clave de inicialización de la vista se completan principalmente en este método.viewWillAppear
: la vista mostraráviewWillLayoutSubviews
: La vista del controlador mostrará los subcontrolesviewDidLayoutSubviews
: Se completa el subcontrol de diseño de vista del controladorviewDidAppear
: vista ya mostradaviewWillDisappear
: la vista desapareceráviewDidDisappear
: la vista ha desaparecido
UIViewController y UIResponder
Las clases con las que estamos más familiarizados son UIApplication
, y se heredan directamente de , y la clase se usa especialmente para responder a las operaciones del usuario y manejar varios eventos ( UIView
) .UIViewController
UIResponder
UIResponder
UIEvent
UIResponder
Proporciona métodos de devolución de llamada para el clic del usuario , la detección de presión ( presses
) y la detección de gestos ( ), que corresponden al inicio, movimiento, finalización y cancelación del usuario, respectivamente. El evento de cancelación solo se llamará cuando el programa se cierre o se reciba una llamada.motion
Control de interfaz de usuario
UIControl
Según la vista, se ha agregado más soporte interactivo. Lo más importante, agrega target / action
el modo. Al observar subclases específicas, podemos observar botones, selectores de fecha ( Date pickers
), cuadros de texto, etc. Al crear controles interactivos, generalmente desea subclasificar uno UIControl
. Algunas clases comunes como bar buttons
(aunque también admitidas target / action
) y textView
(aquí debe usar un proxy para recibir notificaciones) no lo son UIControl
.
UIResponder
UIResponder
es UIView
la clase padre de . responder
Capaz de manejar eventos táctiles, gestuales, de control remoto, etc. La razón por la que es una clase separada y no se fusiona UIView
es porque UIResponder
tiene más subclases, sobre todo UIApplication
y UIViewController
. Al anular UIResponder
los métodos, es posible determinar si una clase puede convertirse en el primer respondedor ( first responder
), como el elemento de enfoque de entrada actual.
Cuando ocurren interacciones como touches
(toque) o (refiriéndose a una serie de sensores de movimiento), se envían al primer respondedor (generalmente una vista). motion
Si el primer respondedor no la maneja, la acción sube por la cadena de respondedores hasta el controlador de vista y, si la acción aún no se maneja, se pasa a la aplicación. Si desea monitorear los gestos de agitación, puede manejarlos en cualquier lugar de estas 3 capas según sea necesario.
UIResponder
También permite métodos de entrada personalizados, desde inputAccessoryView
agregar vistas secundarias al teclado hasta usar inputView
para proporcionar un teclado completamente personalizado.
marco和límites
Frame
: La posición y el tamaño de la vista utilizan el sistema de coordenadas de la vista principal, por lo que es importante colocar la vista en la principal.Bounds
: La posición y tamaño de la vista, utilizando su propio sistema de coordenadas, y para ello es importante colocar el contenido de la vista o subvistas dentro de sí misma.
Primero inicialicemos una vista para ver:
UIView *firstView = [[UIView alloc] init];
firstView.frame = CGRectMake(200, 200, 200, 200);
firstView.backgroundColor = [UIColor redColor];
[self.view addSubview:firstView];
NSLog(@"frame = %@\n", NSStringFromCGRect(firstView.frame));
NSLog(@"bounds = %@", NSStringFromCGRect(firstView.bounds));
Luego rotamos la Vista 90 grados para ver:
firstView.transform = CGAffineTransformMakeRotation(M_PI * 0.25);
Puede ver que Bounds
sigue siendo el mismo, pero Frame
se han producido cambios. Ahora es más fácil ver la diferencia entre frame
y .bounds
Cuándo usar Marco y cuándo usar Límites
- Debido a
frame
la posición de la vista asociada dentro de su supervista, la usa cuando realiza cambios externos, como cambiar su ancho o encontrar la distancia entre la vista y la parte superior de su supervista. - Cuando usa
bounds
, está cambiando hacia adentro, como dibujar algo u organizar subvistas dentro de una vista. También puede usar para obtener el tamaño de la vista si realiza algunas transformaciones en ellabounds
.