Quadro UIView, limites e centro

320

Gostaria de saber como usar essas propriedades da maneira correta.

Pelo que entendi, framepode ser usado no contêiner da exibição que estou criando. Ele define a posição da vista em relação à vista do contêiner. Ele também define o tamanho dessa exibição.

Também centerpode ser usado no contêiner da visualização que estou criando. Esta propriedade altera a posição da vista em relação ao seu contêiner.

Finalmente, boundsé relativo à própria visualização. Altera a área de desenho para a vista.

Você pode dar mais informações sobre a relação entre framee bounds? E as propriedades clipsToBoundse masksToBounds?

Lorenzo B
fonte
1
Esta discussão já foi resolvida aqui. portanto, procure aqui ou pode ver a documentação do desenvolvedor fornecida aqui developer.apple.com/library/ios/#documentation/uikit/reference/… stackoverflow.com/questions/1210047/… slideshare.net/onoaonoa/cs193p-lecture-5 -view-animation
Splendid

Respostas:

577

Como a pergunta que fiz foi vista muitas vezes, fornecerei uma resposta detalhada. Sinta-se à vontade para modificá-lo se desejar adicionar mais conteúdo correto.

Primeiro, uma recapitulação da questão: estrutura, limites e centro e o relacionamento deles.

Quadro A vista frame( CGRect) é a posição do seu retângulo no superviewsistema de coordenadas da. Por padrão, ele começa no canto superior esquerdo.

Limites As vistas bounds( CGRect) expressam um retângulo de vista em seu próprio sistema de coordenadas.

O centro A centeré CGPointexpresso em termos desuperview sistema de coordenadas do e determina a posição do ponto central exato da vista.

Retirados da posição do UIView +, esses são os relacionamentos (eles não funcionam no código, pois são equações informais) entre as propriedades anteriores:

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

NOTA: Esses relacionamentos não se aplicam se as vistas forem giradas. Para mais informações, sugiro que você dê uma olhada na imagem a seguir, tirada de The Kitchen Drawer, com base no curso Stanford CS193p . Os créditos vão para @Rhubarb .

Quadro, limites e centro

Usar o framepermite reposicionar e / ou redimensionar uma vista dentro dela superview. Geralmente, pode ser usado a partir de superview, por exemplo, quando você cria uma subvisão específica. Por exemplo:

// view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view]
// [self view] could be the view managed by a UIViewController
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

Quando você precisa das coordenadas para desenhar dentro de um, viewvocê costuma se referir bounds. Um exemplo típico pode ser desenhar dentro de viewuma subvisão como uma inserção da primeira. Para desenhar a subvisão, é necessário conhecer boundsa supervisão. Por exemplo:

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];    
view2.backgroundColor = [UIColor yellowColor];

[view1 addSubview:view2];

Comportamentos diferentes acontecem quando você altera o modo boundsde exibição. Por exemplo, se você alterar bounds size, as framealterações (e vice-versa). A mudança acontece em torno centerda vista. Use o código abaixo e veja o que acontece:

NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center));    

CGRect frame = view2.bounds;
frame.size.height += 20.0f;
frame.size.width += 20.0f;
view2.bounds = frame;

NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"New Center %@", NSStringFromCGPoint(view2.center));

Além disso, se você alterar, bounds originaltere o originsistema de coordenadas interno. Por padrão, originestá em (0.0, 0.0)(canto superior esquerdo). Por exemplo, se você alterar o originpara, view1poderá ver (comente o código anterior, se desejar) que agora o canto superior esquerdo view2toca no view1. A motivação é bastante simples. Você diz para view1que seu topo canto esquerdo agora está na posição (20.0, 20.0)mas desde view2's frame origincomeça a partir (20.0, 20.0), eles vão coincidir.

CGRect frame = view1.bounds;
frame.origin.x += 20.0f;
frame.origin.y += 20.0f;
view1.bounds = frame; 

O originrepresenta a viewposição do dentro dele, superviewmas descreve a posição dobounds centro.

Finalmente, boundse originnão são conceitos relacionados. Ambos permitem derivar a framevista (Veja as equações anteriores).

Estudo de caso de View1

Aqui está o que acontece ao usar o seguinte snippet.

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center]));

A imagem relativa.

insira a descrição da imagem aqui

Em vez disso, o que acontece se eu mudar os [self view]limites da seguinte forma.

// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];

A imagem relativa.

insira a descrição da imagem aqui

Aqui você diz [self view]que seu canto superior esquerdo está agora na posição (30.0, 20.0), mas como view1a origem do quadro começa em (30.0, 20.0), eles coincidirão.

Referências adicionais (para atualizar com outras referências, se desejar)

Sobre clipsToBounds(fonte Apple doc)

Definir esse valor como YES faz com que as subviews sejam cortadas nos limites do receptor. Se definido como NÃO, as subvisões cujos quadros ultrapassam os limites visíveis do receptor não serão cortadas. O valor padrão é não.

Em outras palavras, se uma visualização frameé (0, 0, 100, 100)e sua subvisão é (90, 90, 30, 30), você verá apenas uma parte dessa subvisualização. Este último não excederá os limites da visualização principal.

masksToBoundsé equivalente a clipsToBounds. Em vez de a UIView, essa propriedade é aplicada a a CALayer. Sob o capô, clipsToBoundschama masksToBounds. Para referências adicionais, consulte Como está a relação entre clipsToBounds do UIView e masksToBounds do CALayer? .

Lorenzo Boaro
fonte
@ Ruibarbo Você está perfeitamente certo. Vou apontar na minha resposta. Obrigado.
Lorenzo B
Não sei se vou receber uma resposta, mas por que a subvisão se move na direção negativa quando as origens dos limites são alteradas. Parece que não consigo entender isso. Obrigado!!
Nimgrg
@ nimgrg Parece que a visão se move na direção negativa, mas não é. As coordenadas internas da super visão são alteradas.
Lorenzo B
perdoe minhas habilidades geométricas, se as coordenadas internas da super visão são alteradas para origem (30.0, 20.0), o ponto (0,0) fica dentro do quadrado azul ou fora dele. Estou apenas tentando rastrear as mudanças e entendê-las. Obrigado por reservar um tempo para responder.
Nimgrg
@flexaddicted: Olá, o slide que você adicionou diz: "O meio da visualização B em seu próprio espaço de coordenadas é: bounds.size.width / 2 + origin.x" - por que esse é o caso? Como o título diz em seu próprio espaço de coordenadas, eu diria que é: bounds.size.width / 2 + bounds.origin.x ?? Não é?
134

Esta pergunta já tem uma boa resposta, mas quero complementá-la com mais algumas fotos. Minha resposta completa está aqui.

Para me ajudar a lembrar da moldura , penso em uma moldura na parede . Assim como uma imagem pode ser movida para qualquer lugar da parede, o sistema de coordenadas do quadro de uma vista é a superview. (parede = super visão, quadro = visão)

Para me ajudar a lembrar dos limites , penso nos limites de uma quadra de basquete . A bola de basquete está em algum lugar dentro da quadra, assim como o sistema de coordenadas dos limites da vista está dentro da própria vista. (quadra = exibição, basquete / jogadores = conteúdo dentro da exibição)

Como o quadro, view.center também está nas coordenadas da superview.

Quadro vs limites - Exemplo 1

O retângulo amarelo representa o quadro da vista. O retângulo verde representa os limites da vista. O ponto vermelho nas duas imagens representa a origem do quadro ou limites dentro de seus sistemas de coordenadas.

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

insira a descrição da imagem aqui


Exemplo 2

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

insira a descrição da imagem aqui


Exemplo 3

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

insira a descrição da imagem aqui


Exemplo 4

É o mesmo que no exemplo 2, exceto que, desta vez, todo o conteúdo da exibição é mostrado como seria se não estivesse cortado nos limites da exibição.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

insira a descrição da imagem aqui


Exemplo 5

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

insira a descrição da imagem aqui

Mais uma vez, veja aqui a minha resposta com mais detalhes.

Suragch
fonte
2
Obrigado Suragch. É realmente uma imagem muito clara do quadro e da diferença limitada. Eu realmente aprecio o seu esforço.
Mohd Haider 26/03
Todas as coisas que eu quero ver em uma resposta curta e concisa. Obrigado!
precisa saber é o seguinte
Impressionante! Por exemplo 3: eu não entendi. você mudou a origem do seu quadro apenas um pouco, como isso muda a rotação da sua imagem?
Honey
@ asma22, No exemplo 3, eu estava apenas tentando mostrar que, quando você gira uma imagem, o quadro muda, mas os limites não. Veja minha resposta mais completa .
Suragch
89

Achei esta imagem mais útil para entender quadro, limites etc.

insira a descrição da imagem aqui

Observe também que frame.size != bounds.sizequando a imagem é girada.

Erben Mo
fonte
14
Uma imagem vale mais que mil palavras.
Narendra Kamma
3
A melhor explicação possível
Ratikanta Patra
@Erben Mo: Oi, o slide que você adicionou diz: "O meio da visualização B em seu próprio espaço de coordenadas é: bounds.size.width / 2 + origin.x" - por que é esse o caso? Como o título diz em seu próprio espaço de coordenadas, eu diria que é: bounds.size.width / 2 + bounds.origin.x ?? Não é?
1
Qual é a fonte desta imagem? Ligação?
David
1
@David É do curso CS193p de Stanford no iTunesU encontrado aqui: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds
3

Eu acho que se você pensa do ponto de vista CALayer, tudo fica mais claro.

O quadro não é realmente uma propriedade distinta da vista ou da camada, é uma propriedade virtual, calculada a partir dos limites, da posição ( UIViewcentro) e da transformação.

Então, basicamente, como os layouts de camada / exibição são realmente decididos por essas três propriedades (e pelo anchorPoint), e qualquer uma dessas três propriedades não altera nenhuma outra propriedade, como alterar a transformação não altera os limites.

beterraba
fonte
2

Existem respostas muito boas com explicações detalhadas para este post. Eu apenas gostaria de referir que não há outra explicação com uma representação visual para o significado de Frame, Bounds, Centro, Transform, Bounds origem na WWDC 2011 Vídeo Compreender UIKit Rendering a partir de @ 4: 22 até 20:10

Wael Showair
fonte
0

Depois de ler as respostas acima, aqui adicionando minhas interpretações.

Suponha que navegando on-line, o navegador da web seja o seu frameque decida onde e qual o tamanho da página da web. O navegador do navegador é o seu bounds.originque decide qual parte da página da web será exibida. bounds.originé difícil de entender. A melhor maneira de aprender é criar o Aplicativo de exibição única, tentando modificar esses parâmetros e ver como as subvisões mudam.

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)];
[view1 setBackgroundColor:[UIColor redColor]];

UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
[view2 setBackgroundColor:[UIColor yellowColor]];
[view1 addSubview:view2];

[[self view] addSubview:view1];

NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));

// Modify this part.
CGRect bounds = view1.bounds;
bounds.origin.x += 10.0f;
bounds.origin.y += 10.0f;

// incase you need width, height
//bounds.size.height += 20.0f;
//bounds.size.width += 20.0f;

view1.bounds = bounds;

NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));
NSTNF
fonte