android - layout_weight - Dos TextViews uno al lado del otro, solo uno para elipsis?
table layout android (5)
Quiero que TextView
dos elementos TextView
uno al lado del otro (en un elemento de la lista), uno alineado a la izquierda y otro a la derecha. Algo como:
|<TextView> <TextView>|
(el |
representan las extremidades de la pantalla)
Sin embargo, el TextView
de la izquierda puede tener un contenido demasiado largo para caber en la pantalla. En este caso, quiero que sea ellipsize pero mostrar toda la TextView
correcta. Algo como:
|This is a lot of conte...<TextView>|
He tenido numerosos intentos al respecto, usando tanto LinearLayout
como RelativeLayout
, y la única solución que he encontrado es usar un RelativeLayout
y poner un marginRight
en el TextView
izquierdo TextView
suficientemente grande como para borrar el TextView
correcto. Como se puede imaginar, sin embargo, esto no es óptimo.
¿Hay alguna otra solución?
Solución final, LinearLayout
:
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:inputType="text"
/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="0"
android:layout_gravity="right"
android:inputType="text"
/>
</LinearLayout>
Solución antigua, TableLayout
:
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:shrinkColumns="0"
>
<TableRow>
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
/>
<TextView android:id="@+id/date"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="none"
android:gravity="right"
/>
</TableRow>
</TableLayout>
¿Por qué no pones un margen izquierdo en el TextView correcto? Estoy usando este enfoque para un
|<TextView> <ImageButton>|
y funciona.
Hay muchas respuestas a esto y preguntas duplicadas prácticamente equivalentes sobre SO. Los enfoques sugeridos generalmente funcionan, más o menos. Poniéndolo en LinearLayout
, envuelva todo en un RelativeLayout
adicional, use un TableLayout
; todo esto parece resolverlo para un diseño más simple, pero si necesita estos dos TextView
dentro de algo más complicado, o el mismo diseño será reutilizado, por ejemplo, con un RecyclerView
, las cosas se romperán muy rápidamente.
La única solución que encontré que realmente funciona todo el tiempo, independientemente de la distribución más grande en la que la pongas, es un diseño personalizado. Es muy fácil de implementar, y al estar tan delgado como sea posible, mantendrá el diseño razonablemente plano, es fácil de mantener, por lo que, a la larga, considero que esta es la mejor solución al problema.
public class TwoTextLayout extends ViewGroup {
public TwoTextLayout(Context context) {
super(context);
}
public TwoTextLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TwoTextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
if (count != 2)
throw new IllegalStateException("TwoTextLayout needs exactly two children");
int childLeft = this.getPaddingLeft();
int childTop = this.getPaddingTop();
int childRight = this.getMeasuredWidth() - this.getPaddingRight();
int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
int childWidth = childRight - childLeft;
int childHeight = childBottom - childTop;
View text1View = getChildAt(0);
text1View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
int text1Width = text1View.getMeasuredWidth();
int text1Height = text1View.getMeasuredHeight();
View text2View = getChildAt(1);
text2View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
int text2Width = text2View.getMeasuredWidth();
int text2Height = text2View.getMeasuredHeight();
if (text1Width + text2Width > childRight)
text1Width = childRight - text2Width;
text1View.layout(childLeft, childTop, childLeft + text1Width, childTop + text1Height);
text2View.layout(childLeft + text1Width, childTop, childLeft + text1Width + text2Width, childTop + text2Height);
}
}
La implementación no podría ser más sencilla, simplemente mide los dos textos (o cualquier otra vista secundaria) y si su ancho combinado excede el ancho de la disposición, reduce el ancho de la primera vista.
Y si necesita modificaciones, por ej. para alinear el segundo texto con la línea de base del primero, también puedes resolverlo fácilmente:
text2View.layout(childLeft + text1Width, childTop + text1Height - text2Height, childLeft + text1Width + text2Width, childTop + text1Height);
O cualquier otra solución, como reducir la segunda vista en relación con la primera, alinearla a la derecha, etc.
La respuesta LinearLayout funcionó para mí con este mismo problema. Publicado como una respuesta separada porque no estaba claro qué funcionó y qué no funcionó para el solicitante.
Una diferencia TableLayout fue menos ideal para mí porque tenía dos filas de datos, y quería que la fila inferior se comportara como lo describe esta pregunta, y la fila superior para abarcar el área. Esa pregunta ha sido respondida en otra pregunta de SO: Colspan en TableLayout , pero LinearLayout fue más simple.
Aunque obtener los anchos correctos me llevó un poco. 0dp
modificación de la pelusa de Android al usar el ancho de 0dp
en el ítem de escala para el rendimiento.
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
>
<TextView
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:ellipsize="end"
android:inputType="text"
/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="0"
android:layout_gravity="right"
android:inputType="text"
/>
</LinearLayout>
Solo una idea, ¿por qué no declaras primero en el diseño xml la vista de texto a la derecha y configuras su ancho como contenido wrap, android:layout_alignParentRight="true"
y android:gravity="right"
. A continuación, declare la vista de texto a la izquierda, establezca su ancho como relleno primario, android:layout__toLeftOf
= {el id de la vista de texto a la derecha} teniendo RelativeView
como vista raíz.
Al declarar primero la vista de texto correcta, su ancho requerido se calculará primero y ocupará la vista, mientras que la vista de texto de la izquierda ocupará el espacio restante de la vista.
Todavía no lo he intentado aunque podría darte una idea.
[Actualizar]
Intenté crear un diseño de recursos xml ... y de alguna manera funciona ...
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/right"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="right"
>
</TextView>
<TextView
android:id="@+id/left"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/right"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:singleLine="true"
android:maxLines="1"
android:text="too looooooooooong ofskgjo sdogj sdkogjdfgds dskjgdsko jgleft"
>
</TextView>
</RelativeLayout>
Use TableLayout y coloque ambos TextView en la fila de la tabla, inténtelo. No lo he intentado