【iOS】—— Problemas relacionados con UIKit

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

UIViewHeredado de UIResponder, principalmente responsable de la transmisión de eventos, respuesta de eventos, pertenece al UIKitmarco basado
CALayeren NSObject, responsable de la representación de imágenes, animación y visualización de vistas, pertenece al QuartzCoremarco

Estos dos contenidos se ajustan al principio de culpabilidad única,
aunque CALayerno 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 es CALayermanejada por la clase. UIViewEs más como un CALayeradministrador, acceder a sus atributos relacionados con el dibujo y las coordenadas, como framey, boundsetc., en realidad está accediendo CALayera los atributos relacionados que contiene internamente.
  • UIViewHay una layerpropiedad que devuelve su CALayerinstancia principal. UIViewHay un layerClassmétodo que devuelve layerla clase utilizada por el principal (el valor predeterminado es [CALayer class]), UIViewy las subclases se pueden mostrar UIViewde manera diferente al sobrecargar este método CALayer.
  • UIViewLa estructura de subárbol CALayersimilar de , también puede agregarle subárboles para completar algunas representaciones especialesUIViewviewlayerlayer
    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:
inserte la descripción de la imagen aquí

  • CALayerSe le puede agregar UIViewuna estructura de subárbol similar a la estructura de vista , similar a agregar hacia arriba , para completar algunas representaciones especiales.viewlayer子layerViewView
  • UIVIewLa layerestructura 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 segunda parte, 动画树, es una capa intermedia, donde el sistema cambia los atributos y realiza varias operaciones de renderizado.
    • El tercero, 显示树es el contenido del árbol que se muestra actualmente en la pantalla.

UITableView

Los dos delegados seguidos por UITableView y los métodos que deben implementarse

  • UITableViewSe necesita una fuente de datos ( dataSource) para mostrar los datos, y UITableViewse 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 datos UITableView. Cualquier UITableViewDataSourceobjeto OC que cumpla con el protocolo puede ser UITableViewuna fuente de datos.
  • También necesitamos UITableViewconfigurar el objeto proxy ( delegate) para UITableViewel procesamiento correspondiente cuando se activan ciertos eventos, como seleccionar una fila determinada. Cualquier objeto OC que cumpla con UITableViewDelegateel acuerdo. Ambos pueden ser UITableViewobjetos proxy y , en general, permiten que el controlador actúe UITableViewcomo un objeto proxy, y la implementación se realiza implementando manualmente algunos métodos en el protocolo.dataSourcedelegatetableView

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 UICollectionViewLayoutAttributesincluyen 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, layoutestablece el correspondiente a cada celda y luego asigna Attributesel todo a .layoutcollectionView

La diferencia entre UICollectionViewFlowLayout y UICollectionViewLayout

  • UICollectionViewLayoutEs una clase abstracta La clase abstracta solo define algunos atributos y comportamientos comunes de las subclases, que no se pueden usar directamente.
  • UICollectionViewFlowLayoutEs 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:

  • objHace referencia a la cadena que se va a calcular y mostrar
  • boundingRectWithSizeIndica 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 determinadoself.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
  • optionses una opción adicional para el dibujo de texto y NSStringDrawingUsesLineFragmentOrigines la línea de base predeterminada
  • attributesFormato de diccionario, que restringe el estilo de visualización de las cadenas y, en general, restringe más fuentes, como:@{NSFontAttributeName:[UIFont systemFontOfSize:16]}
  • contextIncluye 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 subcontroles
  • viewDidLayoutSubviews: Se completa el subcontrol de diseño de vista del controlador
  • viewDidAppear: vista ya mostrada
  • viewWillDisappear: 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) .UIViewControllerUIResponderUIResponderUIEvent

UIResponderProporciona 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

UIControlSegún la vista, se ha agregado más soporte interactivo. Lo más importante, agrega target / actionel 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

UIResponderes UIViewla clase padre de . responderCapaz de manejar eventos táctiles, gestuales, de control remoto, etc. La razón por la que es una clase separada y no se fusiona UIViewes porque UIRespondertiene más subclases, sobre todo UIApplicationy UIViewController. Al anular UIResponderlos 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). motionSi 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.

UIResponderTambién permite métodos de entrada personalizados, desde inputAccessoryViewagregar vistas secundarias al teclado hasta usar inputViewpara 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.
    inserte la descripción de la imagen aquí

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));

inserte la descripción de la imagen aquí
Luego rotamos la Vista 90 grados para ver:

firstView.transform = CGAffineTransformMakeRotation(M_PI * 0.25);

inserte la descripción de la imagen aquí
Puede ver que Boundssigue siendo el mismo, pero Framese han producido cambios. Ahora es más fácil ver la diferencia entre framey .bounds
Por favor agregue una descripción de la imagen

Cuándo usar Marco y cuándo usar Límites

  • Debido a framela 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 ella bounds.

Supongo que te gusta

Origin blog.csdn.net/m0_62386635/article/details/131974018
Recomendado
Clasificación