iphone - fields - text field ios 11
Centrar el texto verticalmente en una UITextView (17)
Acabo de crear una vista de texto centrada verticalmente personalizada en Swift 3:
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
ref: http://geek-is-stupid.github.io/blog/2017/03/14/how-to-center-text-vertically-in-a-uitextview/
Quiero centrar el texto verticalmente dentro de una gran UITextView
que llena toda la pantalla, de modo que cuando hay poco texto, por ejemplo, un par de palabras, está centrado por la altura. No se trata de centrar el texto (una propiedad que se puede encontrar en IB) sino de colocar el texto verticalmente en el medio de UITextView
si el texto es corto, por lo que no hay áreas en blanco en UITextView
. Se puede hacer esto? ¡Gracias por adelantado!
Agregue a la respuesta de Carlos, solo en caso de que tenga texto en la TV más grande que el tamaño de la TV, no necesita volver a centrar el texto, así que cambie este código:
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
a esto:
if ([tv contentSize].height < [tv bounds].size.height) {
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
Aquí hay una extensión UITextView
que centra contenido verticalmente:
extension UITextView {
func centerVertically() {
let fittingSize = CGSize(width: bounds.width, height: CGFloat.max)
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(0, topOffset)
contentOffset.y = -positiveTopOffset
}
}
Debido a que UIKit no es compatible con KVO , decidí implementar esto como una subclase de UITextView
que se actualiza cada vez que UITextView
el UITextView
del contentSize
.
Es una versión ligeramente modificada de la respuesta de Carlos que establece el contentInset
lugar del contentOffset
. Además de ser compatible con iOS 9 , también parece tener menos errores en iOS 8.4.
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
Lo hice así: en primer lugar, incrustó el UITextView en una UIView (esto también debería funcionar para Mac OS). Luego fijé los cuatro lados de la UIView externa a los lados de su contenedor, dándole una forma y tamaño similar o igual al de UITextView. Por lo tanto, tenía un contenedor adecuado para el UITextView. Luego fijé los bordes izquierdo y derecho de UITextView a los lados de la UIView y le di a UITextView una altura. Finalmente, centré el UITextView verticalmente en UIView. Bingo :) ahora el UITextView está centrado verticalmente en el UIView, por lo tanto, el texto dentro del UITextView también está centrado verticalmente.
Para iOS 9.0.2. tendremos que configurar el contentInset en su lugar. Si KVO el contentOffset, iOS 9.0.2 lo establece en 0 en el último momento, anulando los cambios en contentOffset.
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
UITextView *tv = object;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
[tv setContentInset:UIEdgeInsetsMake(topCorrect,0,0,0)];
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
[questionTextView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
}
Usé 0,0 y 0 para los recuadros izquierdo, inferior y derecho respectivamente. Asegúrese de calcularlos también para su caso de uso.
Primero agregue un observador para el valor de la clave UITextView
de UITextView
cuando se carga la vista:
- (void) viewDidLoad {
[textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
[super viewDidLoad];
}
A continuación, agregue este método para ajustar contentOffset
cada vez que cambie el valor de contentOffset
:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
UITextView *tv = object;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
Puede configurarlo directamente con solo restricciones:
Hay 3 restricciones que agregué para alinear el texto verticalmente y horizontalmente en las restricciones de la siguiente manera:
- Haga que la altura sea 0 y agregue restricciones mayores que
- Añadir alineado verticalmente a las restricciones principales
- Añadir alineación horizontal a las restricciones principales
Puede probar el código siguiente, no se requiere necesariamente un observador. el observador arroja un error a veces cuando la vista lo desasigna. Puede mantener este código en viewDidLoad, viewWillAppear o en viewDidAppear en cualquier lugar.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^(void) {
UITextView *tv = txtviewDesc;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
});
});
Si no desea utilizar KVO, también puede ajustar manualmente el desplazamiento con la exportación de este código a una función como esta:
-(void)adjustContentSize:(UITextView*)tv{
CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height);
CGFloat inset = MAX(0, deadSpace/2.0);
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right);
}
y llamándolo
-(void)textViewDidChange:(UITextView *)textView{
[self adjustContentSize:textView];
}
y cada vez que edite el texto en el código. No te olvides de configurar el controlador como el delegado
Swift 3 versión:
func adjustContentSize(tv: UITextView){
let deadSpace = tv.bounds.size.height - tv.contentSize.height
let inset = max(0, deadSpace/2.0)
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right)
}
func textViewDidChange(_ textView: UITextView) {
self.adjustContentSize(tv: textView)
}
Solución de diseño automático:
- Cree una UIView que actúe como un contenedor para UITextView.
- Agregue las siguientes restricciones:
- TextView: Alinee el espacio delantero a: Contenedor
- TextView: Alinee el espacio final a: Contenedor
- TextView: Alinea el centro Y con: Contenedor
- TextView: altura igual a: contenedor, relación: ≤
Solución para iOS10 en RubyMotion:
class VerticallyCenteredTextView < UITextView
def init
super
end
def layoutSubviews
self.recenter
end
def recenter
contentSize = self.sizeThatFits(CGSizeMake(self.bounds.size.width, Float::MAX))
topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0;
topCorrection = 0 if topCorrection < 0
self.contentInset = UIEdgeInsetsMake(topCorrection, 0, 0, 0)
end
end
También tengo este problema y lo resolví con una UITableViewCell
con UITextView
. UITableViewCell
método en una subclase personalizada UITableViewCell
, propiedad statusTextView
:
- (void)centerTextInTextView
{
CGFloat topCorrect = ([self.statusTextView bounds].size.height - [self.statusTextView contentSize].height * [self.statusTextView zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
self.statusTextView.contentOffset = (CGPoint){ .x = 0, .y = -topCorrect };
Y llama a este método en métodos:
- (void)textViewDidBeginEditing:(UITextView *)textView
- (void)textViewDidEndEditing:(UITextView *)textView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Esta solución funcionó para mí sin problemas, puedes intentarlo.
Tengo una vista de texto que estoy usando con autolayout y con la configuración de lineFragmentPadding
y textContainerInset
en cero. Ninguna de las soluciones anteriores funcionó en mi situación. Sin embargo, esto funciona para mí. Probado con iOS 9
@interface VerticallyCenteredTextView : UITextView
@end
@implementation VerticallyCenteredTextView
-(void)layoutSubviews{
[self recenter];
}
-(void)recenter{
// using self.contentSize doesn''t work correctly, have to calculate content size
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)];
CGFloat topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0;
self.contentOffset = CGPointMake(0, -topCorrection);
}
@end
UITextView + VerticalAlignment.h
// UITextView+VerticalAlignment.h
// (c) The Internet 2015
#import <UIKit/UIKit.h>
@interface UITextView (VerticalAlignment)
- (void)alignToVerticalCenter;
- (void)disableAlignment;
@end
UITextView + VerticalAlignment.m
#import "UITextView+VerticalAlignment.h"
@implementation UITextView (VerticalAlignment)
- (void)alignToVerticalCenter {
[self addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
UITextView *tv = object;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
- (void)disableAlignment {
[self removeObserver:self forKeyPath:@"contentSize"];
}
@end
Swift 3:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textField.frame = self.view.bounds
var topCorrect : CGFloat = (self.view.frame.height / 2) - (textField.contentSize.height / 2)
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect
textField.contentInset = UIEdgeInsetsMake(topCorrect,0,0,0)
}
func alignTextVerticalInTextView(textView :UITextView) {
let size = textView.sizeThatFits(CGSizeMake(CGRectGetWidth(textView.bounds), CGFloat(MAXFLOAT)))
var topoffset = (textView.bounds.size.height - size.height * textView.zoomScale) / 2.0
topoffset = topoffset < 0.0 ? 0.0 : topoffset
textView.contentOffset = CGPointMake(0, -topoffset)
}