2016-08-09 17 views
9

Układam 3 widoki poziomo na ekranie (obraz o stałym rozmiarze i 2 jednolinijkowe widoki tekstowe: leftTextView i rightTextView) i próbuję uzyskać rightTextView do przytulenia leftTextView, ale jeśli szerokość obu etykiet przekroczyłaby rozmiar ekranu, skróć leftTextiew.Android TextView Priorytet skracania lub Kompresja rezystancji

Przykład pożądanego funkcjonalności:

|img|leftText|rightText|    ||(end of screen) 
|img|leftTextMedium|rightText|   || 
|img|leftTextTooLongSoTrunc...|rightText|| 

Co się rzeczywiście dzieje:

|img|leftText|rightText|    ||(end of screen) 
|img|leftTextPrettyLongButNotHuge|rightT|| 
|img|leftTextWhichIsIncrediblyLongBlahBl|| 

Obecnie, jeśli wielkość obu widokach tekstu przekracza szerokość widoku, tym rightTextView kończy się coraz spłaszczony w dół, aby pokoju, chociaż ustawiłem android:ellipsize="end" na leftTextView.

Czy istnieje sposób, aby leftTextView miał "priorytet skracania", który mówi, że powinien on zostać obcięty, jeśli spowodowałoby to, że inne widoki nie pasowały? Lub po drugiej stronie, czy mogę ustawić rightTextView, aby miał "odporność na ściskanie", aby nie został zgnieciony, aby zrobić miejsce dla leftTextView? Oto próbka mojego XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"> 

    <ImageView 
     android:id="@+id/fixedWidthImage" 
     android:layout_width="50dp" 
     android:layout_height="50dp" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" /> 

    <TextView 
     android:id="@+id/leftTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_toEndOf="@+id/fixedWidthImage" 
     android:layout_toRightOf="@id/fixedWidthImage" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:ellipsize="end" /> 

    <TextView 
     android:id="@+id/rightTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_toEndOf="@+id/leftTextView" 
     android:layout_toRightOf="@+id/leftTextView" 
     android:layout_alignParentEnd="true" 
     android:layout_alignParentRight="true" 
     android:maxLines="1" 
     android:textSize="12sp" /> 

</RelativeLayout> 

Rzeczy próbowałem:

  1. W leftTextView, dodać toStartOf/toLeftOfrightTextView (wywala aplikację)
  2. Zamiast wyrównując rightTextView na końcu/na prawo od leftTextView, odwróć go i dopasuj leftTextView do początku/z lewej strony rightTextView. Powoduje to, że rightTextView jest zakotwiczony na końcu ekranu zamiast bezpośrednio na prawo od leftTextView. Przykład jak to kończy się patrzy:

    |img|leftText     |rightText|| 
    |img|leftTextMedium   |rightText|| 
    |img|leftTextTooLongSoTrunc...|rightText|| 
    
  3. Nawet jeśli ustawić android:minWidth="25dp" tylko w celu zapewnienia przynajmniej część z rightTextView jest widoczny (co nie chcę zrobić, ponieważ ten tekst jest zmienna długość) nadal kompresuje szerokość, aby zrobić miejsce dla leftTextView.

  4. Za odpowiedź na Emanuel Moecklin próbowałem owijania w LinearLayout i ustawienie masy na leftTextView. Wynik był wizualnie identyczny z tym, którego próbowałem w punkcie 2.
+0

W mojej obronie oznakowania duplikatu, że drugie pytanie nie ma odpowiedzi w czasie poprosiłem moją. Poza tym jego tytuł jest okropny, prawdopodobnie dlatego nie zdawałem sobie sprawy, że on istnieje. – Stonz2

Odpowiedz

6

Możesz zarchiwizować ten układ za pomocą atrybutu TableLayout i shrinkColumns.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:orientation="vertical" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

    <!-- Row 1 --> 
    <TableLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:shrinkColumns="1"> 

     <TableRow 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:gravity="center_vertical"> 

      <ImageView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:src="@mipmap/ic_launcher"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="end" 
        android:text="leftText"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="none" 
        android:text="rightText"/> 
     </TableRow> 

    </TableLayout> 


    <!-- Row 2 --> 
    <TableLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:shrinkColumns="1"> 

     <TableRow 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:gravity="center_vertical"> 

      <ImageView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:src="@mipmap/ic_launcher"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="end" 
        android:text="leftTextPrettyLongButNotHuge"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="none" 
        android:text="rightText"/> 
     </TableRow> 

    </TableLayout> 

    <!-- Row 3 --> 
    <TableLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:shrinkColumns="1"> 

     <TableRow 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:gravity="center_vertical"> 

      <ImageView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:src="@mipmap/ic_launcher"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="end" 
        android:text="leftTextWhichIsIncrediblyLongBlahBlahBlahBlah"/> 

      <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:padding="4dp" 
        android:maxLines="1" 
        android:ellipsize="none" 
        android:text="rightText"/> 
     </TableRow> 

    </TableLayout> 

</LinearLayout> 

enter image description here

+0

Czy można to zrobić dla układów pionowych? Potrzebuję pozycji w TableRow, aby były wyrównane w pionie i ustawić android: shrinkColumns = "0", aby zmniejszyć pierwszy widok. – Vlad

1

Oto, co zrobić:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal"> 

    <ImageView 
     android:id="@+id/fixedWidthImage" 
     android:layout_width="50dp" 
     android:layout_height="50dp" 
     android:src="@drawable/ic_launcher_pro" /> 

    <TextView 
     android:id="@+id/leftTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_weight="1" 
     android:layout_gravity="center_vertical|left" 
     android:ellipsize="marquee" 
     android:lines="1" 
     android:text="This is a very long text, and now even longer" /> 

    <TextView 
     android:id="@+id/rightTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center_vertical|left" 
     android:lines="1" 
     android:text="This is also quite long" /> 

</LinearLayout> 

Android: layout_weight = "1" robi "trick" tutaj. Dokumentacja nie jest całkiem jasne, na to jedno ale:

Na przykład, jeśli istnieją trzy pola tekstowe i dwa z nich deklaruje masie 1, a drugi otrzymuje żadnej wagi, pole tekstowe trzeci bez wagi nie będzie rosnąć i będzie zajmować tylko obszar wymagany przez jego zawartość.

(https://developer.android.com/guide/topics/ui/layout/linear.html#Weight)

To nie wdawanie się w przypadku, w którym nie ma miejsca do wypełnienia, ale nie wystarczająco dużo miejsca dla wszystkich widoków. Jedną z interpretacji wspomnianego fragmentu dokumentacji byłoby to, że pole bez ciężaru (rightTextView w tym przypadku) zajmie obszar wymagany przez jego zawartość, podczas gdy pole z wagą (w tym przypadku leftTextView) będzie "rosnąć" (jak w negatywie). wzrost) i dokładnie tak się dzieje.

+0

Podczas gdy waga pozwala na "wzrost ujemny", o którym wspominasz, rozwija również pole, aby wypełnić szerokość, gdy nie musi. Kończy się to tym, że 'rightTextView' jest przypięty do prawego/końca widoku rodzica. Funkcjonalnie wygląda tak samo, jak w # 2 tego, co próbowałem w pytaniu. – Stonz2

1

Myślę, że będziesz musiał stworzyć niestandardowy układ. Działa to dobrze w przypadku próbki, którą wykonałem i spełnia wszystkie wymagania, które napisałeś powyżej, ale musisz dodać więcej kodu, aby obliczyć layout_margins i dopełnienie.

Podstawową ideą tego, co się tutaj dzieje, jest podklasa LinearLayout oraz w przepustce onMeasure, sprawdzam, aby upewnić się, że odpowiedni widok ma opcję zajmowania jak największej przestrzeni. Zauważ, że muszę ponownie zmierzyć właściwy widok, a nie tylko uzyskać zmierzoną szerokość, ponieważ Linelayout nie da mu wystarczająco dużo miejsca. Kiedy już uzyskasz ile miejsca zajmuje odpowiedni widok, sprawdź, czy środkowy widok (nazywany lewym widokiem ... przepraszam) zajmuje więcej miejsca, niż chcesz. Jeśli tak, po prostu daj mu miejsce, które pozostało.

W zależności od wymagań użytkownika w RecyclerView ... Wiem, że powiedziałeś, że potrzebujesz czystego rozwiązania xml, ale uzyskasz lepszą wydajność, jeśli zajmiesz się tym w kodzie jako xml 1. może być niemożliwe i 2. będzie wymagać więcej obliczeń niż samo robienie tego bezpośrednio.

public class CustomLinearLayout extends LinearLayout { 

private View child0; 
private TextView leftView, rightView; 
public CustomLinearLayout(Context context) { 
    super(context); 
} 

public CustomLinearLayout(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    if (rightView == null) { 
     child0 = getChildAt(0); 
     leftView = (TextView)getChildAt(1); 
     rightView = (TextView) getChildAt(2); 
    } 

    int spec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); 
    rightView.measure(spec, spec); 

    int remaining = getMeasuredWidth() - child0.getMeasuredWidth() - rightView.getMeasuredWidth(); 
    if (leftView.getMeasuredWidth() > remaining) { 
     int specW = MeasureSpec.makeMeasureSpec(remaining, MeasureSpec.AT_MOST); 
     int specH = MeasureSpec.makeMeasureSpec(leftView.getMeasuredHeight(), MeasureSpec.EXACTLY); 
     leftView.measure(specW, specH); 
    } 
} 

układ XML

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:id="@+id/layout" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
tools:context="com.example.joshua.myapplication.MainActivity"> 

<com.example.joshua.myapplication.CustomLinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal"> 
    <ImageView 
     android:layout_width="30dp" 
     android:layout_height="30dp" 
     android:background="#FF0000"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:ellipsize="end" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Left View With Really Really Long Text That should fill the screen"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Right View" 
     /> 
</com.example.joshua.myapplication.CustomLinearLayout> 

<com.example.joshua.myapplication.CustomLinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal" 
    android:layout_marginTop="20dp"> 
    <ImageView 
     android:layout_width="30dp" 
     android:layout_height="30dp" 
     android:background="#FF0000"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:ellipsize="end" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Left View with short text"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Right View" 
     /> 
</com.example.joshua.myapplication.CustomLinearLayout> 
</LinearLayout> 

enter image description here

+0

Dzięki za odpowiedź - podałem mu wir i działa świetnie, ale podejście Nshmury działa również, ale jest czysto w XML i nie polega na podklasowaniu. – Stonz2

0

Wystarczy użyć android:maxWidth obiekt do lewej TextView. Twój lewy widok nigdy nie przekroczy tego limitu. i zawsze będzie miejsce na twój właściwy widok.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"> 

    <ImageView 
     android:id="@+id/fixedWidthImage" 
     android:layout_width="50dp" 
     android:layout_height="50dp" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:src="@drawable/ic_launcher" /> 

    <TextView 
     android:id="@+id/leftTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerVertical="true" 
     android:layout_toEndOf="@+id/fixedWidthImage" 
     android:layout_toRightOf="@+id/fixedWidthImage" 
     android:ellipsize="end" 
     android:lines="1" 
     android:maxWidth="250dp" 
     android:text="This is a Long left Text which never ends and You'll be tired after reading this long stuff.. blah blah... " /> 

    <TextView 
     android:id="@+id/rightTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerVertical="true" 
     android:layout_toEndOf="@+id/leftTextView" 
     android:layout_toRightOf="@+id/leftTextView" 
     android:ellipsize="end" 
     android:lines="1" 
     android:text="Right Text" /> 

</RelativeLayout> 

Preview of layout

Jednak ograniczenie roztworem to trzeba dać stałą wartość nieruchomości maxwidth. Dzięki temu będzie wyświetlał inny wygląd na różnych rozmiarach ekranu. Jednak w większości przypadków nie spotkasz się z problemem.

Również do wyświetlania długiego tekstuView w pojedynczej linii android:ellipsize="marquee" jest dobrym rozwiązaniem. W miarę przewijania widoku poziomo. Ale nie zapomnij zapisać tego kodu w swoim kodzie textView.setSelected(true), aby działało. Detail

+0

W przypadku Androida o tak dużej rozbieżności w wielkości ekranu (plus portret i krajobraz) stała szerokość zdecydowanie nie jest pożądanym podejściem. – Stonz2

+0

Powiedziałem już, że to zadziała, gdy znasz jakiś stały rozmiar widoku. W przeciwnym razie możesz to zrobić programowo, jak zasugerował @whizzle. –