Mam UITextView
w mojej aplikacji na iOS, która wyświetla dużą ilość tekstu.
Następnie stronicuję ten tekst za pomocą parametru marginesu przesunięcia parametru UITextView
.
Mój problem polega na tym, że wypełnienie UITextView
pomieszało moje obliczenia, ponieważ wydaje się być różne w zależności od rozmiaru czcionki i kroju pisma, którego używam.
Dlatego zadaję pytanie: Czy można usunąć wypełnienie otaczające zawartość UITextView
?
Czekamy na Wasze odpowiedzi!
ios
iphone
cocoa-touch
uikit
uitextview
sniurkst
źródło
źródło
Odpowiedzi:
Aktualizacja na 2019 rok
Jest to jeden z najgłupszych błędów w systemie iOS.
Podana tutaj klasa
UITextViewFixed
jest ogólnie najbardziej rozsądnym rozwiązaniem.Oto klasa:
Nie zapomnij wyłączyć przewijania w Inspektorze!
Rozwiązanie działa poprawnie w serii ujęć
Rozwiązanie działa poprawnie w czasie wykonywania
To już koniec.
Zasadniczo powinno to być wszystko, czego potrzebujesz w większości przypadków .
Nawet jeśli zmieniasz wysokość widoku tekstowego w locie ,
UITextViewFixed
zwykle robi wszystko, czego potrzebujesz.(Typowym przykładem zmiany wysokości w locie jest zmiana jej w zależności od typu użytkownika.)
Oto zepsuty UITextView od Apple ...
Oto
UITextViewFixed
:Pamiętaj, że oczywiście musisz
wyłącz scroll Przewiń w Inspektorze!
Nie zapomnij wyłączyć scrollEnabled! :)
Kilka dalszych problemów
(1) W niektórych nietypowych przypadkach - na przykład w niektórych tabelach z elastycznymi, dynamicznie zmieniającymi się wysokościami komórek - Apple robi dziwną rzecz: dodaje dodatkową przestrzeń u dołu . Nie naprawdę! To musiałaby być jedna z najbardziej irytujących rzeczy w iOS.
Oto „szybka poprawka” do dodania do powyższego, która zwykle pomaga w tym szaleństwie.
(2) Czasami, aby naprawić kolejny subtelny bałagan Apple, musisz dodać:
(3) Prawdopodobnie powinniśmy dodać:
po prostu
.lineFragmentPadding = 0
wUITextViewFixed
.Jednak ... wierzcie lub nie ... to po prostu nie działa w obecnym iOS! (Sprawdzone w 2019 r.) Może być konieczne dodanie tej linii w przyszłości.
Fakt, że
UITextView
jest uszkodzony w iOS jest jednym z najdziwniejszych rzeczy na wszystkich komputerów przenośnych. Dziesięciolecie tego pytania i wciąż nie jest ustalone!Wreszcie, jest nieco podobna wskazówka dla pola tekstowego : https://stackoverflow.com/a/43099816/294884
Zupełnie losowa wskazówka: jak dodać „...” na końcu
Często używasz UITextView „jak UILabel”. Więc chcesz, aby obcinał tekst za pomocą wielokropka „...”
Jeśli tak, dodaj trzeci wiersz kodu w „setup”:
Przydatna wskazówka, jeśli chcesz mieć zerową wysokość, kiedy nie ma w ogóle tekstu
Często używasz widoku tekstu tylko do wyświetlania tekstu. Tak więc użytkownik nie może tak naprawdę niczego edytować. Używasz linii „0”, co oznacza, że widok tekstu automatycznie zmieni wysokość w zależności od liczby linii tekstu.
To świetnie, ale jeśli w ogóle nie ma tekstu, to niestety otrzymujesz taką samą wysokość, jakby był jeden wiersz tekstu !! Widok tekstu nigdy nie „znika”.
Jeśli chcesz, aby „zniknął”, po prostu dodaj to
(Zrobiłem to „1”, więc jasne jest, co się dzieje, „0” jest w porządku.)
Co z UILabel?
Podczas wyświetlania tekstu UILabel ma wiele zalet w porównaniu z UITextView. UILabel nie cierpi z powodu problemów opisanych na tej stronie kontroli jakości. Rzeczywiście powodem, dla którego wszyscy zwykle „poddajemy się” i używamy UITextView jest fakt, że UILabel jest trudny w obsłudze. W szczególności absurdalnie trudno jest po prostu poprawnie dodać wypełnienie do UILabel. W rzeczywistości tutaj jest pełna dyskusja na temat tego, jak „w końcu” poprawnie dodać dopełnienie do UILabel: https://stackoverflow.com/a/58876988/294884 W niektórych przypadkach, jeśli robisz trudny układ z dynamicznymi komórkami wysokości, czasami jest to lepiej zrobić to na poważnie dzięki UILabel.
źródło
self.textView.isScrollEnabled = false
środkuviewDidLayoutSubviews()
i to też zadziałało. Apple po prostu lubi zmuszać nas do przeskakiwania przez obręcze :)translatesAutoresizingMaskIntoConstraints
. Tylko z tą odpowiedzią nie byłem w stanie usunąć wszystkich marginesów (niektóre dziwne dolne marginesy nie chciały zniknąć) w hierarchii widoków przy użyciu automatycznego układu. Zajmuje się również obliczaniem rozmiarów widokówsystemLayoutSizeFitting
, które wcześniejUITextView
W przypadku iOS 7.0 okazało się, że sztuczka contentInset już nie działa. To jest kod, którego użyłem, aby pozbyć się marginesu / wypełnienia w iOS 7.
Sprowadza to lewą krawędź tekstu do lewej krawędzi kontenera:
Powoduje to wyrównanie górnej części tekstu z górną krawędzią kontenera
Obie linie są potrzebne do całkowitego usunięcia marginesu / wypełnienia.
źródło
self.descriptionTextView.textContainerInset = UIEdgeInsetsZero;
lineFragmentPadding
na 0 to magia, której szukałem. Nie mam pojęcia, dlaczego Apple tak trudno dopasowuje zawartość UITextView do innych elementów sterujących.lineFragmentPadding
nie ma na celu modyfikowania marginesów. Z dokumentów Wypełnienie fragmentu linii nie jest przeznaczone do wyrażania marginesów tekstu. Zamiast tego należy użyć wypustek w widoku tekstowym, dostosować atrybuty marginesu akapitu lub zmienić pozycję widoku tekstowego w jego nadzorze.To obejście zostało napisane w 2009 roku, kiedy IOS 3.0 został wydany. To już nie ma zastosowania.
Wpadłem na dokładnie ten sam problem, w końcu musiałem skończyć z użyciem
gdzie nameField to
UITextView
. Czcionka, której używałem, to Helvetica 16 punktów. To tylko niestandardowe rozwiązanie dla konkretnego rozmiaru pola, które rysowałem. Powoduje to, że lewe przesunięcie wyrównuje się z lewą stroną, a górne przesunięcie tam, gdzie chcę, dla pudełka, w którym jest rysowane.Ponadto wydaje się, że dotyczy to tylko sytuacji, w
UITextViews
której używasz domyślnego wyrównania, tj.Wyrównaj na przykład do prawej, a
UIEdgeInsetsMake
wydaje się, że nie ma żadnego wpływu na prawą krawędź.Przynajmniej użycie właściwości .contentInset pozwala na umieszczenie pól w „prawidłowych” pozycjach i uwzględnienie odchyleń bez ich kompensowania
UITextViews
.źródło
Opierając się na niektórych dobrych odpowiedziach już podanych, oto rozwiązanie oparte wyłącznie na Storyboard / Interface Builder, które działa w iOS 7.0+
Ustaw Zdefiniowane przez użytkownika atrybuty środowiska wykonawczego UITextView dla następujących kluczy:
źródło
Na iOS 5
UIEdgeInsetsMake(-8,-8,-8,-8);
wydaje się działać świetnie.źródło
Zdecydowanie unikałbym odpowiedzi obejmujących wartości zakodowane na stałe, ponieważ rzeczywiste marginesy mogą się zmieniać w zależności od ustawień rozmiaru czcionki użytkownika itp.
Oto odpowiedź @ user1687195, napisana bez modyfikacji
textContainer.lineFragmentPadding
(ponieważ dokumenty stwierdzają, że nie jest to zamierzone użycie).Działa to świetnie na iOS 7 i nowszych.
To faktycznie ten sam wynik, tylko trochę czystszy, ponieważ nie niewłaściwie używa właściwości lineFragmentPadding.
źródło
self.textView.textContainer.lineFragmentPadding = 0;
lineFragmentPadding
nie ma na celu kontrolowania marginesów. Właśnie dlatego powinieneś użyćtextContainerInset
.Rozwiązanie do tworzenia scenorysów lub interfejsów wykorzystujące atrybuty środowiska wykonawczego zdefiniowanego przez użytkownika :
Zrzuty ekranu dotyczą systemu iOS 7.1 i iOS 6.1
contentInset = {{-10, -5}, {0, 0}}
.źródło
Wszystkie te odpowiedzi dotyczą pytania tytułowego, ale chciałem zaproponować kilka rozwiązań problemów przedstawionych w treści pytania PO.
Rozmiar treści tekstowej
Szybkim sposobem obliczenia rozmiaru tekstu w środku
UITextView
jest użycieNSLayoutManager
:Daje to całkowitą przewijalną zawartość, która może być większa niż
UITextView
ramka. Odkryłem, że jest to o wiele dokładniejsze niż,textView.contentSize
ponieważ oblicza, ile miejsca zajmuje tekst. Na przykład, biorąc pod uwagę pustyUITextView
:Wysokość linii
UIFont
ma właściwość, która pozwala szybko uzyskać wysokość linii dla danej czcionki. Dzięki temu możesz szybko znaleźć wysokość linii tekstu wUITextView
:Obliczanie widocznego rozmiaru tekstu
Określenie ilości faktycznie widocznego tekstu jest ważne dla obsługi efektu „stronicowania”.
UITextView
ma właściwość o nazwie,textContainerInset
która faktycznie stanowi margines między faktycznymUITextView.frame
a samym tekstem. Aby obliczyć rzeczywistą wysokość widocznej ramki, możesz wykonać następujące obliczenia:Określanie rozmiaru stronicowania
Wreszcie, gdy masz już widoczny rozmiar tekstu i treść, możesz szybko określić, jakie powinny być przesunięcia, odejmując
textHeight
odtextSize
:Używając wszystkich tych metod, nie dotknąłem swoich wypustek i mogłem pójść do kursora lub gdziekolwiek w tekście, który chcę.
źródło
możesz użyć
textContainerInset
właściwościUITextView
:textView.textContainerInset = UIEdgeInsetsMake (10, 10, 10, 10);
(góra, lewo, dół, prawo)
źródło
textContainerInset
własności nie działa na mnie, gdy chcę zmienić na nową wartość zobaczyć stackoverflow.com/questions/19422578/... .W systemie iOS 10 następujący wiersz działa w przypadku usuwania górnej i dolnej krawędzi.
źródło
UIEdgeInset.zero
działa przy użyciu XCode 8.3 i iOS 10.3 SimulatorNajnowszy Swift:
źródło
Oto zaktualizowana wersja bardzo pomocnej odpowiedzi Fattie. Dodaje 2 ważne linie, które pomogły mi uruchomić układ na iOS 10 i 11 (i prawdopodobnie także na niższych):
Ważnymi liniami są dwie
translatesAutoresizingMaskIntoConstraints = <true/false>
wypowiedzi!To zaskakująco usuwa wszystkie marginesy we wszystkich moich okolicznościach!
Chociaż
textView
nie jest to pierwsza odpowiedź, może się zdarzyć, że istnieje dziwny dolny margines, którego nie można rozwiązać za pomocąsizeThatFits
metody wymienionej w zaakceptowanej odpowiedzi.Po dotknięciu do textView nagle dziwny dolny margines zniknął i wszystko wyglądało tak, jak powinno, ale tylko jak tylko textView się pojawi
firstResponder
.Czytam więc tutaj na SO, że włączanie i wyłączanie
translatesAutoresizingMaskIntoConstraints
pomaga podczas ręcznego ustawiania ramki / granic między połączeniami.Na szczęście działa to nie tylko z ustawieniem ramki, ale z 2 liniami
setup()
umieszczonymi pomiędzy dwomatranslatesAutoresizingMaskIntoConstraints
wywołaniami!Jest to na przykład bardzo pomocne podczas obliczania ramki widoku przy użyciu
systemLayoutSizeFitting
naUIView
. Zwraca prawidłowy rozmiar (czego wcześniej nie robił)!Jak wspomniano w pierwotnej odpowiedzi:
Nie zapomnij wyłączyć scrollEnabled w Inspektorze!
To rozwiązanie działa poprawnie zarówno w scenorysie, jak i w środowisku wykonawczym.
To wszystko, teraz naprawdę gotowe!
źródło
Dla szybkiego 4, Xcode 9
Użyj poniższej funkcji, aby zmienić margines / wypełnienie tekstu w UITextView
więc w tym przypadku jest
źródło
Robiąc rozwiązanie na wkładce nadal miałem wyściółkę po prawej stronie iu dołu. Wyrównanie tekstu również powodowało problemy. Jedynym pewnym sposobem, jaki udało mi się znaleźć, było umieszczenie widoku tekstu w innym widoku przyciętym do granic.
źródło
Oto proste, małe rozszerzenie, które usunie domyślny margines Apple z każdego widoku tekstu w Twojej aplikacji.
Uwaga: Konstruktor interfejsów nadal będzie wyświetlał stary margines, ale aplikacja będzie działać zgodnie z oczekiwaniami.
źródło
Dla mnie (iOS 11 i Xcode 9.4.1) magicznie działało ustawienie właściwości textView.font do
UIFont.preferred(forTextStyle:UIFontTextStyle)
stylu, a także pierwsza odpowiedź wspomniana przez @Fattie. Ale odpowiedź @Fattie nie zadziałała, dopóki nie ustawiłem właściwości textView.font. W przeciwnym razie UITextView zachowuje się nieprawidłowo.źródło
Na wypadek, gdyby ktokolwiek szukał najnowszej wersji Swift, poniższy kod działa dobrze z Xcode 10.2 i Swift 4.2
źródło
Znalazłem jeszcze jedno podejście, uzyskiwanie widoku z tekstem z widoków podrzędnych UITextView i konfigurowanie go w metodzie layoutSubview podklasy:
źródło
Przewijanie textView wpływa również na pozycję tekstu i sprawia, że wygląda on tak, jakby nie był wyśrodkowany w pionie. Udało mi się wyśrodkować tekst w widoku, wyłączając przewijanie i ustawiając górną wstawkę na 0:
Z jakiegoś powodu jeszcze tego nie rozgryzłem, kursor nadal nie jest wyśrodkowany przed rozpoczęciem pisania, ale tekst jest wyśrodkowany natychmiast po rozpoczęciu pisania.
źródło
Jeśli chcesz ustawić ciąg HTML i uniknąć dolnego dopełniania, upewnij się, że nie używasz tagów blokowych, np. Div, p.
W moim przypadku był to powód. Możesz to łatwo przetestować, zastępując występowanie tagów blokowych np. Tagiem span.
źródło
Dla SwiftUI
Jeśli tworzysz własny TextView
UIViewRepresentable
i chcesz kontrolować wypełnienie, w swojejmakeUIView
funkcji po prostu wykonaj:uiTextView.textContainerInset = UIEdgeInsets(top: 10, left: 18, bottom: 0, right: 18)
lub cokolwiek chcesz.
źródło
źródło