tło
Wiele razy musimy automatycznie dopasować czcionkę TextView do podanych granic.
Problem
Niestety, chociaż istnieje wiele wątków i postów (i sugerowanych rozwiązań) mówiących o tym problemie (przykład tutaj , tutaj i tutaj ), żaden z nich tak naprawdę nie działa dobrze.
Dlatego postanowiłem przetestować każdy z nich, dopóki nie znajdę prawdziwej oferty.
Myślę, że wymagania takiego textView powinny być:
Powinny zezwalać na użycie dowolnej czcionki, kroju pisma, stylu i zestawu znaków.
Powinien obsługiwać zarówno szerokość, jak i wysokość
Nie obcinamy, chyba że tekst nie może się zmieścić z powodu ograniczenia, które mu daliśmy (przykład: zbyt długi tekst, zbyt mały dostępny rozmiar). Możemy jednak poprosić o poziomy / pionowy pasek przewijania, jeśli tylko chcemy, tylko w takich przypadkach.
Powinny zezwalać na wiele linii lub jedną linię. W przypadku wielu linii, zezwól na maksymalne i minimalne linie.
Nie powinno być powolne w obliczeniach. Używasz pętli do znalezienia najlepszego rozmiaru? Przynajmniej zoptymalizuj to i nie zwiększaj próbkowania o 1 za każdym razem.
W przypadku linii wieloliniowej należy zezwolić na zmianę rozmiaru lub użycie większej liczby linii i / lub pozwolić na samodzielne wybranie linii za pomocą znaku „\ n”.
Co próbowałem
Próbowałem tak wielu próbek (w tym tych linków, o których pisałem), a także próbowałem je zmodyfikować, aby obsługiwały przypadki, o których mówiłem, ale żadne z nich naprawdę nie działa.
Zrobiłem przykładowy projekt, który pozwala mi wizualnie sprawdzić, czy TextView automatycznie dopasowuje się poprawnie.
Obecnie mój przykładowy projekt losowo losuje tylko tekst (alfabet angielski plus cyfry) i rozmiar textView, i niech pozostanie z jedną linią, ale nawet to nie działa dobrze na żadnej próbce, której próbowałem.
Oto kod (dostępny również tutaj ):
Plik res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity">
<Button android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" android:text="Button" />
<FrameLayout android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_above="@+id/button1"
android:layout_alignParentLeft="true" android:background="#ffff0000"
android:layout_alignParentRight="true" android:id="@+id/container"
android:layout_alignParentTop="true" />
</RelativeLayout>
Plik src/.../MainActivity.java
public class MainActivity extends Activity
{
private final Random _random =new Random();
private static final String ALLOWED_CHARACTERS ="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewGroup container=(ViewGroup)findViewById(R.id.container);
findViewById(R.id.button1).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
container.removeAllViews();
final int maxWidth=container.getWidth();
final int maxHeight=container.getHeight();
final FontFitTextView fontFitTextView=new FontFitTextView(MainActivity.this);
final int width=_random.nextInt(maxWidth)+1;
final int height=_random.nextInt(maxHeight)+1;
fontFitTextView.setLayoutParams(new LayoutParams(width,height));
fontFitTextView.setSingleLine();
fontFitTextView.setBackgroundColor(0xff00ff00);
final String text=getRandomText();
fontFitTextView.setText(text);
container.addView(fontFitTextView);
Log.d("DEBUG","width:"+width+" height:"+height+" text:"+text);
}
});
}
private String getRandomText()
{
final int textLength=_random.nextInt(20)+1;
final StringBuilder builder=new StringBuilder();
for(int i=0;i<textLength;++i)
builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
return builder.toString();
}
}
Pytanie
Czy ktoś wie o rozwiązaniu tego powszechnego problemu, który faktycznie działa?
Nawet rozwiązanie, które ma o wiele mniej funkcji niż to, o czym pisałem, na przykład takie, które ma tylko stałą liczbę wierszy tekstu i dostosowuje czcionkę zgodnie z jego rozmiarem, ale nigdy nie ma dziwnych trzasków i zbyt dużej ilości tekstu duży / mały w porównaniu do dostępnej przestrzeni.
Projekt GitHub
Ponieważ jest to tak ważny TextView, postanowiłem opublikować bibliotekę, aby każdy mógł z niego łatwo korzystać i wnosić coś do tego tutaj .
źródło
Odpowiedzi:
Dzięki prostym fix MartinH jest tutaj kod ten zajmuje się również
android:drawableLeft
,android:drawableRight
,android:drawableTop
iandroid:drawableBottom
tagów.Moja odpowiedź tutaj powinna sprawić, że będziesz zadowolony z automatycznego skalowania tekstu Zobacz tekst, aby zmieścił się w granicach
Zmodyfikowałem twój przypadek testowy:
Wysyłam kod tutaj na żądanie dewelopera Androida :
Efekt końcowy:
Przykładowy plik układu:
I kod Java:
Ostrzeżenie:
Uważaj jednak na ten rozwiązany błąd w Androidzie 3.1 (Honeycomb).
źródło
Zmodyfikowałem nieco odpowiedź M-WaJeEh, aby uwzględnić złożone szuflady po bokach.
Te
getCompoundPaddingXXXX()
metody powrotupadding of the view + drawable space
. Zobacz na przykład: TextView.getCompoundPaddingLeft ()Problem: to naprawia pomiar szerokości i wysokości przestrzeni TextView dostępnej dla tekstu. Jeśli nie weźmiemy pod uwagę rozmiaru do rysowania, zostanie on zignorowany, a tekst będzie nakładał się na ten rysunek.
Zaktualizowany segment
adjustTextSize(String)
:źródło
Ok, wykorzystałem ostatni tydzień do masowego przepisania mojego kodu, aby dokładnie pasował do twojego testu. Możesz teraz skopiować ten 1: 1 i od razu zadziała - w tym
setSingleLine()
. Pamiętaj o dostosowaniuMIN_TEXT_SIZE
iMAX_TEXT_SIZE
jeśli szukasz ekstremalnych wartości.Algorytm konwergencji wygląda następująco:
Całą klasę można znaleźć tutaj.
Rezultat jest teraz bardzo elastyczny. Działa to tak samo zadeklarowane w XML, jak:
... a także zbudowany programowo jak w teście.
Naprawdę mam nadzieję, że możesz teraz tego użyć. Możesz
setText(CharSequence text)
teraz zadzwonić, by użyć go przy okazji. Klasa zajmuje się niezwykle rzadkimi wyjątkami i powinna być solidna. Jedyne, czego algorytm jeszcze nie obsługuje, to:setMaxLines(x)
gdziex >= 2
Ale dodałem obszerne komentarze, które pomogą Ci to zbudować, jeśli chcesz!
Proszę zanotować:
Jeśli po prostu użyjesz tego normalnie, nie ograniczając go do jednej linii, może dojść do podziału słów, jak wspomniałeś wcześniej. To funkcja Androida , a nie wina
AutoFitText
. Android zawsze rozbija słowa, które są zbyt długie dla TextView, i jest to całkiem wygodna funkcja. Jeśli chcesz zainterweniować tutaj, zapoznaj się z moimi komentarzami i kodem rozpoczynającym się od wiersza 203. Napisałem już odpowiedni podział i uznanie dla ciebie, wszystko, co musisz zrobić odtąd, to podzielić słowa, a następnie zmodyfikować, jak chcesz .Podsumowując: powinieneś rozważyć przepisanie testu, aby obsługiwał także znaki spacji, na przykład:
To da bardzo piękne (i bardziej realistyczne) wyniki.
Znajdziesz tu także komentarze, które pomogą Ci zacząć w tej sprawie.
Powodzenia i pozdrawiam
źródło
Moje wymaganie to
Odsyłam link: Automatyczne skalowanie tekstu Zobacz tekst, aby zmieścił się w granicach (w tym komentarze), a także DialogTitle.java
Przekonałem się, że dostarczone rozwiązanie jest ładne i proste, ale nie zmienia dynamicznie rozmiaru pola tekstowego. Działa świetnie, gdy wybrana długość tekstu z widoku listy jest większa niż istniejąca długość tekstu w
ScalableTextView
. Po wybraniu tekstu o długości mniejszej niż istniejący tekstScalableTextView
nie zwiększa rozmiaru tekstu, pokazując tekst w mniejszym rozmiarze.Zmodyfikowałem ScalableTextView.java, aby ponownie dopasować rozmiar tekstu na podstawie długości tekstu. Tutaj jest mój
ScalableTextView.java
Happy Coding ....
źródło
Wyjaśnię krok po kroku, jak działa ten atrybut w niższych wersjach Androida:
1- Zaimportuj bibliotekę pomocy Androida 26.xx do pliku oceny projektu. Jeśli nie ma biblioteki wsparcia w IDE, pliki zostaną pobrane automatycznie.
2- Otwórz plik XML układu i refaktoryzuj tak, jak ten tag TextView. Ten scenariusz wygląda następująco: po zwiększeniu rozmiaru czcionki w systemie dopasuj tekst do dostępnej szerokości, a nie zawijanie słów.
źródło
Ostrzeżenie, błąd w systemie Android 3 (Honeycomb) i Android 4.0 (Ice Cream Sandwich)
Wersje Android: 3.1 - 4.04 mają błąd, który ustawił TextText () w TextView tylko po raz pierwszy (pierwsze wywołanie).
Błąd jest opisany w numerze 22493: Błąd wysokości TextView w Androidzie 4.0 i numerze 17343: wysokość przycisku i tekst nie wraca do pierwotnego stanu po zwiększeniu i zmniejszeniu rozmiaru tekstu w HoneyComb .
Obejściem tego problemu jest dodanie znaku nowej linii do tekstu przypisanego do TextView przed zmianą rozmiaru:
Używam go w kodzie w następujący sposób:
Dodaję ten znak „\ u3000” po lewej i prawej stronie mojego tekstu, aby zachować wyśrodkowanie. Jeśli masz wyrównany do lewej, to dołącz tylko do prawej. Oczywiście można go również osadzić z widżetem AutoResizeTextView, ale chciałem zachować poprawiony kod na zewnątrz.
źródło
Istnieje teraz oficjalne rozwiązanie tego problemu. Automatyczne powiększanie TextViews wprowadzone w Androidzie O są dostępne w Bibliotece pomocy 26 i są kompatybilne wstecz aż do Androida 4.0.
https://developer.android.com/preview/features/autosizing-textview.html
Nie jestem pewien, dlaczego https://stackoverflow.com/a/42940171/47680, który również zawierał te informacje, został usunięty przez administratora.
źródło
Od czerwca 2018 roku Android oficjalnie obsługuje tę funkcję dla Androida 4.0 (API poziom 14) i wyższych.
W systemie Android 8.0 (poziom API 26) i nowszym:
Wersje Androida wcześniejsze niż Android 8.0 (poziom API 26):
Sprawdź moją szczegółową odpowiedź .
źródło
Konwertuj widok tekstu na obraz i skaluj obraz w granicach.
Oto przykład, jak przekonwertować widok na obraz: Konwersja widoku do mapy bitowej bez wyświetlania go w systemie Android?
Problem w tym, że twój tekst nie będzie dostępny do wyboru, ale powinien załatwić sprawę. Nie próbowałem tego, więc nie jestem pewien, jak by to wyglądało (ze względu na skalowanie).
źródło
Poniżej znajduje się avalancha TextView z dodatkową funkcjonalnością dla niestandardowej czcionki.
Stosowanie:
Nie zapomnij dodać: xmlns: foo = "http://schemas.android.com/apk/res-auto". Czcionka powinna znajdować się w katalogu zasobów
znane błędy: nie działa z Androidem 4.03 - czcionki są niewidoczne lub bardzo małe (oryginalna avalancha też nie działa) poniżej znajduje się obejście tego błędu: https://stackoverflow.com/a/21851239/2075875
źródło
Spróbuj tego
źródło
Jeśli szukasz czegoś łatwiejszego:
źródło
Szybka naprawa problemu opisanego przez @Malachiasz
Rozwiązałem problem, dodając niestandardową obsługę tego w klasie automatycznej zmiany rozmiaru:
Po prostu zadzwoń
yourView.setTextCompat(newTextValue)
zamiastyourView.setText(newTextValue)
źródło
Spróbuj dodać
LayoutParams
aMaxWidth
iMaxHeight
doTextView
. Zmusi układ do przestrzegania kontenera nadrzędnego, a nie przepełnienia.źródło
Od Androida O można automatycznie zmieniać rozmiar tekstu w formacie xml:
https://developer.android.com/preview/features/autosizing-textview.html
źródło
Po wypróbowaniu oficjalnego automatycznego sortowania tekstu w systemie Android okazało się , że jeśli twoja wersja Androida jest wcześniejsza niż Android 8.0 (poziom API 26), musisz z niej skorzystać
android.support.v7.widget.AppCompatTextView
i upewnij się, że twoja wersja biblioteki wsparcia jest wyższa niż 26.0.0. Przykład:aktualizacja :
Zgodnie z odpowiedzią @ android-developer, sprawdzam
AppCompatActivity
kod źródłowy i znalazłem te dwie linieonCreate
final AppCompatDelegate delegate = getDelegate(); delegate.installViewFactory();
oraz w
AppCompatDelegateImpl
„screateView
używa
AppCompatViewInflater
widoku inflatora, podczasAppCompatViewInflater
createView użyje AppCompatTextView dla „TextView”.W moim projekcie nie używam
AppCompatActivity
, więc potrzebuję użyć<android.support.v7.widget.AppCompatTextView>
w XML.źródło
AppCompatActivity
. AppCompatActivity używa układu inflatora AppCompatViewInflater.