Jak stracić margines / padding w UITextView?
Mam UITextView
w mojej aplikacji na iOS, która wyświetla dużą ilość tekstu. Następnie stronicuję ten tekst, używając parametru marginesu offset UITextView
. Mój problem polega na tym, że wypełnienie UITextView
jest mylące moje obliczenia, ponieważ wydaje się być różne w zależności od rozmiaru czcionki i kroju pisma, którego używam.
W związku z tym zadaję pytanie: czy możliwe jest usunięcie wyściółki otaczającej treść UITextView
?
Czekamy na Wasze odpowiedzi!
19 answers
Na rok 2018
Jest to jeden z najgłupszych błędów w iOS.Klasa {[4] } jest zwykle rozsądnym rozwiązaniem.
Oto Klasa:
@IBDesignable class UITextViewFixed: UITextView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
}
}
Nie zapomnij wyłączyć scrollEnabled w Inspektorze!
-
Rozwiązanie działa poprawnie w storyboard
-
Rozwiązanie działa poprawnie w czasie wykonywania
Ogólnie rzecz biorąc, to powinno być wszystko, czego potrzebujesz w większości przypadki .
Nawet jeśli zmieniasz wysokość widoku tekstowego w locie, zwykle robi to wszystko, czego potrzebujesz.
(częstym przykładem zmiany wysokości w locie jest zmiana jej jako typów użytkowników.)
Oto zepsuty UITextView od Apple...
Oto UITextViewFixed
:
Zauważ, że oczywiście musisz
Wyłącz scrollEnabled w Inspektorze!
Nie zapomnij wyłączyć scrollEnabled! :)
Kilka dalszych zagadnień
(1) w niektórych nietypowych przypadkach-przykład, niektóre przypadki elastycznych widoków tabeli wysokości komórek z dynamicznie zmieniającą się wysokością-Apple robi najbardziej irytującą rzecz na świecie: dodają dodatkowego miejsca na dole. Nie, naprawdę! To musi być jedna z najbardziej irytujących rzeczy w iOS.
Oto "szybka poprawka" do dodania, która często pomaga w tym szaleństwie.
...
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
// this is not ideal, but you can sometimes use this
// to fix the "space at bottom" insanity
var b = bounds
let h = sizeThatFits(CGSize(
width: bounds.size.width,
height: CGFloat.greatestFiniteMagnitude)
).height
b.size.height = h
bounds = b
...
(2) czasami, aby naprawić jeszcze jeden subtelny Apple bałagan, trzeba to dodać:
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
super.setContentOffset(contentOffset, animated: false)
}
(3) powinniśmy dodać:
contentInset = UIEdgeInsets.zero
Tuż po .lineFragmentPadding = 0
W UITextViewFixed
. Jednak ... Informatyka po prostu nie działa W obecnym iOS! Może być konieczne, aby dodać, że w przyszłości.
Na koniec nieco podobna wskazówka dla pola tekstowego : https://stackoverflow.com/a/43099816/294884
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-13 03:01:01
Dla iOS 7.0 odkryłem, że sztuczka contentInset już nie działa. To jest kod, którego użyłem, aby pozbyć się marginesu / wypełnienia w iOS 7.
Powoduje przeniesienie lewej krawędzi tekstu do lewej krawędzi kontenera:
textView.textContainer.lineFragmentPadding = 0
Powoduje to wyrównanie górnej części tekstu do górnej części kontenera
textView.textContainerInset = .zero
Obie linie są potrzebne do całkowitego usunięcia marginesu / wyściółki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-01 02:22:36
To obejście zostało napisane w 2009 roku, gdy wydano IOS 3.0. To już nie ma zastosowania.
Napotkałem dokładnie ten sam problem, w końcu musiałem skończyć używając
nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);
Gdzie nameField jest UITextView
. Czcionka, której akurat używałem, to Helvetica 16 point. To tylko niestandardowe rozwiązanie dla konkretnego rozmiaru pola rysowałem. To sprawia, że lewe przesunięcie równo z lewą stroną, a górne przesunięcie tam, gdzie chcę go dla pola, jego przyciągnięcie.
Dodatkowo, wydaje się, że dotyczy to tylko UITextViews
, gdzie używasz domyślnego aligmentu, tj.
nameField.textAlignment = NSTextAlignmentLeft;
Wyrównaj do prawej np. UIEdgeInsetsMake
wydaje się nie mieć żadnego wpływu na prawą krawędź.
Przynajmniej, używając .właściwość contentInset umożliwia umieszczanie pól z" poprawnymi " pozycjami i dostosowywanie odchyleń bez kompensowania UITextViews
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 22:51:21
Bazując na dobrych odpowiedziach już udzielonych, oto rozwiązanie oparte wyłącznie na budownictwie interfejsu, które wykorzystuje atrybuty środowiska uruchomieniowego zdefiniowane przez Użytkownika i działa w systemie iOS 7.0+:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 00:58:53
Na iOS 5 UIEdgeInsetsMake(-8,-8,-8,-8);
wydaje się działać świetnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-08 12:36:13
Zdecydowanie unikałbym odpowiedzi dotyczących zakodowanych na twardo wartości, ponieważ rzeczywiste marginesy mogą się zmieniać wraz z ustawieniami rozmiaru czcionki użytkownika itp.
Oto odpowiedź @user1687195, napisana bez modyfikacji textContainer.lineFragmentPadding
(PonieważDocs stwierdzają, że nie jest to zamierzone użycie).
Działa to świetnie na iOS 7 i nowszych.
self.textView.textContainerInset = UIEdgeInsetsMake(
0,
-self.textView.textContainer.lineFragmentPadding,
0,
-self.textView.textContainer.lineFragmentPadding);
Jest to efektywnie ten sam wynik, tylko trochę czystszy, ponieważ nie nadużywa właściwości lineFragmentPadding.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-09 00:52:36
Rozwiązanie Storyboard lub Interface Builder, wykorzystujące zdefiniowane przez użytkownika atrybuty runtime. Update. Dodano zrzuty ekranu iOS7.1 i iOS6.1 z contentInset = {{-10, -5}, {0, 0}}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 08:59:26
Wszystkie te odpowiedzi odnoszą się do pytania tytułowego, ale chciałem zaproponować kilka rozwiązań problemów przedstawionych w treści pytania OP.
Wielkość zawartości tekstu
Szybkim sposobem obliczenia rozmiaru tekstu wewnątrz UITextView
jest użycie NSLayoutManager
:
UITextView *textView;
CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size;
Daje to całkowitą zawartość przewijalną, która może być większa niż ramka UITextView
. Okazało się, że jest to o wiele dokładniejsze niż textView.contentSize
, ponieważ oblicza, ile miejsca zajmuje tekst w górę. Na przykład, biorąc pod uwagę pusty UITextView
:
textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)
Wysokość Linii
UIFont
posiada właściwość, która pozwala szybko uzyskać wysokość linii dla danej czcionki. Możesz więc szybko znaleźć wysokość linii tekstu w swoim UITextView
za pomocą:
UITextView *textView;
CGFloat lineHeight = textView.font.lineHeight;
Obliczanie Rozmiaru Widocznego Tekstu
Określenie ilości tekstu, który jest rzeczywiście widoczny, jest ważne dla obsługi efektu "stronicowania". UITextView
ma właściwość o nazwie textContainerInset
, która w rzeczywistości jest marginesem między rzeczywistą UITextView.frame
i sam tekst. Aby obliczyć rzeczywistą wysokość widocznej ramki można wykonać następujące obliczenia:
UITextView *textView;
CGFloat textViewHeight = textView.frame.size.height;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textHeight = textViewHeight - textInsets.top - textInsets.bottom;
Określanie Rozmiaru Stronicowania
Wreszcie, teraz, gdy masz widoczny rozmiar tekstu i treść, możesz szybko określić, jakie powinny być twoje przesunięcia, odejmując textHeight
od textSize
:
// where n is the page number you want
CGFloat pageOffsetY = textSize - textHeight * (n - 1);
textView.contentOffset = CGPointMake(textView.contentOffset.x, pageOffsetY);
// examples
CGFloat page1Offset = 0;
CGFloat page2Offset = textSize - textHeight
CGFloat page3Offset = textSize - textHeight * 2
Używając wszystkich tych metod, nie dotykałem moich wstawek i mogłem przejść do karetki lub gdziekolwiek w tekście, który chcę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-26 15:31:44
Możesz użyć textContainerInset
właściwości UITextView
:
TextView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
(Góra, Lewo, Dół, prawo)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 05:24:57
W systemie iOS 10 następująca linia działa dla usuwania górnej i dolnej wyściółki.
captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 20:38:14
Oto zaktualizowana wersja bardzo pomocnej odpowiedzi Fattie.
Dodaje bardzo ważne linie 2, które pomogły mi uzyskać idealny układ działający na iOS 10 i 11 (i prawdopodobnie również na niższych).
d
@IBDesignable class UITextViewFixed: UITextView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
translatesAutoresizingMaskIntoConstraints = true
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
translatesAutoresizingMaskIntoConstraints = false
}
}
Ważne linie to dwa translatesAutoresizingMaskIntoConstraints = <true/false>
stwierdzenia!
To zaskakująco usuwa wszystkie marginesy we wszystkich moich okolicznościach!
Podczas gdy textView
nie jest pierwszą odpowiedzią, może się zdarzyć, że istnieje jakiś dziwny dolny margines, który nie może być rozwiązane przy użyciu metody sizeThatFits
, która jest wymieniona w zaakceptowanej odpowiedzi.
Podczas stukania w textView nagle dziwny dolny margines zniknął i wszystko wyglądało tak, jak powinno, ale tylko tak szybko, jak textView ma firstResponder
.
Więc przeczytałem tutaj na tak , że włączanie i wyłączanie translatesAutoresizingMaskIntoConstraints
pomaga przy ręcznym ustawianiu ramki/granic pomiędzy wywołaniami.
Na szczęście działa to nie tylko z ustawieniem ramki, ale z 2 liniami setup()
/ align = "center" bgcolor = "# e0ffe0 " / cesarz chin / / align = center /
Jest to na przykład bardzo pomocne przy obliczaniu ramki widoku przy użyciu systemLayoutSizeFitting
na UIView
. Zwraca prawidłowy rozmiar (który wcześniej nie był)!
Jak w oryginalnej odpowiedzi wymienionej:
nie zapomnij wyłączyć scrollEnabled w Inspektorze!
To rozwiązanie działa poprawnie w storyboardzie,a także w czasie wykonywania.
To jest to, teraz jesteś naprawdę zrobione!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-14 14:51:08
Dla swift 4, Xcode 9
Użyj poniższej funkcji, aby zmienić margines / wypełnienie tekstu w UITextView
Public func uiedgeinsetsmake (_top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: cgfloat) - > UIEdgeInsets
Więc w tym przypadku jest
self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 16:54:33
Robiąc rozwiązanie wstawiania nadal miałem wyściółkę po prawej stronie i na dole. Również wyrównanie tekstu powodowało problemy. Jedynym pewnym sposobem ognia znalazłem było umieszczenie widoku tekstowego wewnątrz innego widoku, który jest przycięty do granic.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-31 23:49:05
Oto łatwe małe rozszerzenie, które usunie domyślny margines Apple z każdego widoku tekstu w aplikacji.
Uwaga: Interface Builder nadal będzie wyświetlał Stary margines, ale Twoja aplikacja będzie działać zgodnie z oczekiwaniami.
extension UITextView {
open override func awakeFromNib() {
super.awakeFromNib();
removeMargins();
}
/** Removes the Apple textview margins. */
public func removeMargins() {
self.contentInset = UIEdgeInsetsMake(
0, -textContainer.lineFragmentPadding,
0, -textContainer.lineFragmentPadding);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-04 00:19:15
Najnowszy Swift
Self.textView.textContainerInset = .init(top: -2, left: 0, bottom: 0, right: 0) siebie.textView.textContainer.lineFragmentPadding = 0
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-24 07:54:33
Dla mnie (iOS 11 & Xcode 9.4.1) magicznie działało ustawienie textView.właściwość font do stylu UIFont.preferred(forTextStyle:UIFontTextStyle)
, a także pierwsza odpowiedź, o której wspomniał @Fattie. Ale odpowiedź @ Fattie nie zadziałała, dopóki nie ustawiłem textView.właściwość font else UITextView zachowuje się nieprawidłowo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-17 11:20:45
Znalazłem jeszcze jedno podejście, pobierając widok z tekstem z podwidów UITextView i ustawiając go w metodzie layoutSubview podklasy:
- (void)layoutSubviews {
[super layoutSubviews];
const int textViewIndex = 1;
UIView *textView = [self.subviews objectAtIndex:textViewIndex];
textView.frame = CGRectMake(
kStatusViewContentOffset,
0.0f,
self.bounds.size.width - (2.0f * kStatusViewContentOffset),
self.bounds.size.height - kStatusViewContentOffset);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-28 10:17:28
Przewijanie widoku tekstu wpływa również na położenie tekstu i sprawia, że nie jest on wyśrodkowany pionowo. Udało mi się wyśrodkować tekst w widoku, wyłączając przewijanie i ustawiając górną wstawkę na 0:
textView.scrollEnabled = NO;
textView.textContainerInset = UIEdgeInsetsMake(0, textView.textContainerInset.left, textView.textContainerInset.bottom, textView.textContainerInset.right);
Z jakiegoś powodu jeszcze tego nie rozgryzłem, kursor nadal nie jest wyśrodkowany przed rozpoczęciem pisania, ale tekst centruje się natychmiast, gdy zaczynam pisać.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-25 19:37:05
[firstNameTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-21 13:40:06