objective - marco de iOS cambiar una propiedad(por ejemplo, ancho)
cgrectmake objective c (9)
Esta pregunta fue originalmente hecha para el lenguaje de programación objetivo-c. En el momento de escribir, Swift ni siquiera existía todavía.
Pregunta
¿Es posible cambiar solo una propiedad de un CGRect
?
Por ejemplo:
self.frame.size.width = 50;
en lugar de
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
50);
por supuesto, entiendo que self.frame.size.width
es de solo lectura, así que me pregunto cómo hacerlo.
CSS ANALOGY proceda bajo su propio riesgo
para aquellos de ustedes que están familiarizados con CSS
, la idea es muy similar a usar:
margin-left: 2px;
en lugar de tener que cambiar todo el valor:
margin: 5px 5px 5px 2px;
Basado en la solución de ArtOfWarfare (que es realmente increíble), he UIView
categoría UIView
sin funciones C.
Ejemplos de uso:
[self setFrameWidth:50];
self.frameWidth = 50;
self.frameWidth += 50;
self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;
Archivo de encabezado UIView+easy_frame.h
:
@interface UIView (easy_frame)
- (void) setFrameWidth:(CGFloat)width;
- (void) setFrameHeight:(CGFloat)height;
- (void) setFrameX:(CGFloat)x;
- (void) setFrameY:(CGFloat)y;
- (CGFloat) frameWidth;
- (CGFloat) frameHeight;
- (CGFloat) frameX;
- (CGFloat) frameY;
Archivo de implementación UIView+easy_frame.m
:
#import "UIView+easy_frame.h"
@implementation UIView (easy_frame)
# pragma mark - Setters
- (void) setFrameWidth:(CGFloat)width
{
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
width,
self.frame.size.height);
}
- (void) setFrameHeight:(CGFloat)height
{
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
height);
}
- (void) setFrameX:(CGFloat)x
{
self.frame = CGRectMake(x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height);
}
- (void) setFrameY:(CGFloat)y
{
self.frame = CGRectMake(self.frame.origin.x,
y,
self.frame.size.width,
self.frame.size.height);
}
# pragma mark - Getters
- (CGFloat) frameWidth
{
return self.frame.size.width;
}
- (CGFloat) frameHeight
{
return self.frame.size.height;
}
- (CGFloat) frameX
{
return self.frame.origin.x;
}
- (CGFloat) frameY
{
return self.frame.origin.y;
}
En Swift puedes extender la clase UIView para la aplicación, de modo que, por ejemplo, puedas mover la vista de encabezado de la tabla hacia arriba en 10 puntos como este:
tableView.tableHeaderView!.frameAdj(0, -20, 0, 0)
(por supuesto, si está utilizando AutoLayout, es posible que en realidad no haga nada ... :))
Al extender UIView (afectando a cada UIView y subclase de este en su aplicación)
extension UIView {
func frameAdj(x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) {
self.frame = CGRectMake(
self.frame.origin.x + x,
self.frame.origin.y + y,
self.frame.size.width + width,
self.frame.size.height + height)
}
}
En base a la respuesta de n0_quarter, aquí hay una extensión de UIView escrita en Swift:
/**
* Convenience category for manipulating UIView frames
*/
extension UIView {
//MARK: - Getters
func frameX() -> CGFloat {
return frame.origin.x
}
func frameY() -> CGFloat {
return frame.origin.y
}
func frameWidth() -> CGFloat {
return frame.size.width
}
func frameHeight() -> CGFloat {
return frame.size.height
}
//MARK: - Setters
func setFrameX(x: CGFloat) {
frame = CGRect(x: x, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
}
func setFrameY(y: CGFloat) {
frame = CGRect(x: frame.origin.x, y: y, width: frame.size.width, height: frame.size.height)
}
func setFrameWidth(width: CGFloat) {
frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: width, height: frame.size.height)
}
func setFrameHeight(height: CGFloat) {
frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width, height: height)
}
}
Espero no llegar demasiado tarde a la fiesta, esta es mi solución en ObjC.
Para mí, prefiero mantener una única función en lugar de varias funciones, y me gusta el enfoque CSS que se muestra en el póster. A continuación se muestra la función que agrego a mi Categoría UIView.
- (void)resetFrame:(CGRect)frame {
CGRect selfFrame = self.frame;
selfFrame.origin = CGPointMake(frame.origin.x>0 ? frame.origin.x : selfFrame.origin.x, frame.origin.y>0 ? frame.origin.y : selfFrame.origin.y);
selfFrame.size = CGSizeMake(frame.size.width>0 ? frame.size.width : selfFrame.size.width, frame.size.height>0 ? frame.size.height : selfFrame.size.height);
[self setFrame:selfFrame]; }
Se muestra en el ejemplo, observa cada valor en el CGRect proporcionado, y si el valor es mayor que 0, significa que queremos reemplazar ese valor. Y por lo tanto, puede hacer CGRect (0,0,100,0) y supondrá que queremos reemplazar solo el ancho.
Me gustó la respuesta de Ahmed Khalaf , pero se me ocurrió que también podría escribir algunas funciones en C ... la principal ventaja es que será más fácil rastrear los errores en caso de que esté utilizando el error. tipo.
Habiendo dicho eso, escribí un archivo .h con estas declaraciones de función:
CGRect CGRectSetWidth(CGRect rect, CGFloat width);
CGRect CGRectSetHeight(CGRect rect, CGFloat height);
CGRect CGRectSetSize(CGRect rect, CGSize size);
CGRect CGRectSetX(CGRect rect, CGFloat x);
CGRect CGRectSetY(CGRect rect, CGFloat y);
CGRect CGRectSetOrigin(CGRect rect, CGPoint origin);
Y un archivo .m correspondiente con estas implementaciones de funciones:
CGRect CGRectSetWidth(CGRect rect, CGFloat width) {
return CGRectMake(rect.origin.x, rect.origin.y, width, rect.size.height);
}
CGRect CGRectSetHeight(CGRect rect, CGFloat height) {
return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, height);
}
CGRect CGRectSetSize(CGRect rect, CGSize size) {
return CGRectMake(rect.origin.x, rect.origin.y, size.width, size.height);
}
CGRect CGRectSetX(CGRect rect, CGFloat x) {
return CGRectMake(x, rect.origin.y, rect.size.width, rect.size.height);
}
CGRect CGRectSetY(CGRect rect, CGFloat y) {
return CGRectMake(rect.origin.x, y, rect.size.width, rect.size.height);
}
CGRect CGRectSetOrigin(CGRect rect, CGPoint origin) {
return CGRectMake(origin.x, origin.y, rect.size.width, rect.size.height);
}
Entonces, ahora, para hacer lo que quieras, puedes hacer lo siguiente:
self.frame = CGRectSetWidth(self.frame, 50);
Obtenga incluso Fancier (actualización que hice un año después)
Sin embargo, esto tiene un self.frame
redundante. Para solucionarlo, puede agregar una category
en UIView
con métodos que se ven así:
- (void) setFrameWidth:(CGFloat)width {
self.frame = CGRectSetWidth(self.frame, width); // You could also use a full CGRectMake() function here, if you''d rather.
}
Y ahora puedes escribir:
[self setFrameWidth:50];
O mejor:
self.frameWidth = 50;
Y solo para que puedas hacer algo como esto:
self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;
También necesitarás tener esto en tu categoría:
- (CGFloat) frameWidth {
return self.frame.size.width;
}
Disfrutar.
Para responder a su pregunta original: sí, es posible cambiar solo un miembro de una estructura CGRect
. Este código no arroja errores:
myRect.size.width = 50;
Lo que no es posible, sin embargo, es cambiar un solo miembro de un CGRect
que es en sí mismo una propiedad de otro objeto. En ese caso muy común, tendría que usar una variable local temporal:
CGRect frameRect = self.frame;
frameRect.size.width = 50;
self.frame = frameRect;
La razón para esto es que usar el acceso de propiedad self.frame = ...
es equivalente a [self setFrame:...]
y este acceso siempre espera un CGRect
completo. En este caso, no funciona bien mezclar el acceso de struct
estilo C con la notación de punto de la propiedad Objective-C.
Si se ve en la necesidad de hacer este tipo de modificación de componentes individuales, puede valer la pena tener macros como estos en algún lugar accesible por todo su código:
#define CGRectSetWidth(rect, w) CGRectMake(rect.origin.x, rect.origin.y, w, rect.size.height)
#define ViewSetWidth(view, w) view.frame = CGRectSetWidth(view.frame, w)
De esta forma, cada vez que necesite cambiar el ancho solo, simplemente escriba
ViewSetWidth(self, 50);
en lugar de
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, 50);
con frecuencia el método de llamada a setFrame no es tan bueno, como: setFrameX(x) setFrameY(y) setFrameWidth(width) ...
en cambio, de forma rápida podemos utilizar los parámetros predeterminados para establecer múltiples parámetros solo en una llamada:
func setFrame(x x: CGFloat = CGFloat.NaN, y: CGFloat = CGFloat.NaN, width: CGFloat = CGFloat.NaN, height: CGFloat = CGFloat.NaN) {
let newX = x.isNaN ? self.frame.origin.x : x
let newY = y.isNaN ? self.frame.origin.y : y
let newWidth = width.isNaN ? self.bounds.size.width : width
let newHeight = height.isNaN ? self.bounds.size.height : height
self.frame = CGRect(x: newX, y: newY, width: newWidth, height: newHeight)
}
luego actualiza los parámetros de frame only need:
setFrame(x: x, width: min(maxX - x, titleLabel.bounds.size.width))
setFrame(width: titleDescriptionLabel.bounds.size.width + 5, height: titleDescriptionLabel.bounds.size.height + 6)
-(void) sizeScreen : (UIView *) size : (double) width : (double) height : (double) x : (double) y {
CGRect frameRect = size.frame;
frameRect.size.width = width;
frameRect.size.height = height;
frameRect.origin.x = x;
frameRect.origin.y = y;
self.view.frame = frameRect;
}
es genial para mi :)