Vista de cuadrícula con dos columnas e imágenes redimensionadas automáticamente

179

Estoy tratando de hacer una vista de cuadrícula con dos columnas. Me refiero a dos fotos por fila una al lado de la otra como esta imagen.

ingrese la descripción de la imagen aquí

Pero mis imágenes tienen espacios entre ellas, debido al hecho de que no es del mismo tamaño. Esto es lo que estoy obteniendo.

ingrese la descripción de la imagen aquí

Como puede ver, la primera imagen oculta la leyenda que muestra el nombre del contacto y el número de teléfono. y las otras imágenes no se estiran correctamente.

Aquí está mi archivo xml GridView . Como puede ver, el columnWidthestá configurado en 200dp . Me gustaría que sea automático , para que las imágenes cambien de tamaño automáticamente para cada tamaño de pantalla.

<?xml version="1.0" encoding="utf-8"?>
<GridView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridViewContacts"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:numColumns="2"
    android:columnWidth="200dp"
    android:stretchMode="columnWidth"    
    android:gravity="center" />

y aquí está el archivo xml del elemento, que representa cada elemento en sí.

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

    <ImageView
        android:id="@+id/imageViewContactIcon"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY" />

    <LinearLayout
        android:id="@+id/linearlayoutContactName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingLeft="5dp"
        android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:background="#99000000"
        android:layout_alignBottom="@+id/imageViewContactIcon">

        <TextView
            android:id="@+id/textViewContactName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            android:textSize="15sp"
            android:text="Lorem Ipsum" />       

        <TextView
            android:id="@+id/textViewContactNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#FFFFFF"
            android:layout_marginLeft="5dp"
            android:focusable="true"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit="marquee_forever"
            android:textSize="10sp"
            android:text="123456789" />

    </LinearLayout>

</RelativeLayout>

Entonces, lo que quiero es mostrar dos imágenes por fila, y las imágenes se redimensionan automáticamente, sin importar el tamaño de la pantalla. ¿Qué estoy haciendo mal en mi diseño?

Gracias.

rogcg
fuente
1
Quizás debería intentar encapsular el ImageView en su propio LinearLayout. De esta manera, puede configurar la etiqueta LinearLayout exactamente como lo desea y luego simplemente hacer que ImageView la complete.
dani
@dani a que te refieres? Todavía puedo configurar el ImageView exactamente como quiero. podrías darme un ejemplo?
rogcg
Creo que necesita crear pulgares a partir de imágenes, que son todas iguales, por ejemplo 100x100 o lo que sea que las necesite. Si puede ver su imagen de ejemplo, el efecto que está buscando es mostrar solo una parte de la imagen. Y en su proyecto simplemente muestra la imagen original, lo cual es incorrecto si necesita hacer una galería. Intente buscar los pulgares en el sitio web de desarrollo de Android :)
Vasil Valchev
@VasilValchev, pero el problema es que, incluso si creo pulgares (por ejemplo, 100x100), tendré que cambiar el tamaño para diferentes tamaños de pantalla. Ya utilicé la scaleTypepropiedad centerCrop en ImageView. Lo que necesito lograr es una forma de hacer las imágenes una al lado de la otra y cambiar el tamaño automáticamente para diferentes tamaños de pantalla.
rogcg
Siempre puede obtener el tamaño de la pantalla en código horizontal con solo dividirlo por / 2. Si puede ver en su proyecto que el problema está en la altura, si sabe cuál es exactamente su peso, siempre puede hacer un rectángulo perfecto. ¿No veo dónde está el problema?
Vasil Valchev

Respuestas:

402

Aquí hay un método relativamente fácil para hacer esto. Lanza un GridView a tu diseño, configura el modo de estiramiento para estirar los anchos de columna, establece el espaciado en 0 (o lo que quieras) y establece el número de columnas en 2:

res / layout / main.xml

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

    <GridView
        android:id="@+id/gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:verticalSpacing="0dp"
        android:horizontalSpacing="0dp"
        android:stretchMode="columnWidth"
        android:numColumns="2"/>

</FrameLayout>

Haga una costumbre ImageViewque mantenga su relación de aspecto:

src / com / example / graphicstest / SquareImageView.java

public class SquareImageView extends ImageView {
    public SquareImageView(Context context) {
        super(context);
    }

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

    public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width
    }
}

Haga un diseño para un elemento de cuadrícula utilizando este SquareImageView y configure el scaleType en centerCrop:

res / layout / grid_item.xml

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent">

    <com.example.graphicstest.SquareImageView
        android:id="@+id/picture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:layout_gravity="bottom"
        android:textColor="@android:color/white"
        android:background="#55000000"/>

</FrameLayout>

Ahora haga algún tipo de adaptador para su GridView:

src / com / example / graphicstest / MyAdapter.java

private final class MyAdapter extends BaseAdapter {
    private final List<Item> mItems = new ArrayList<Item>();
    private final LayoutInflater mInflater;

    public MyAdapter(Context context) {
        mInflater = LayoutInflater.from(context);

        mItems.add(new Item("Red",       R.drawable.red));
        mItems.add(new Item("Magenta",   R.drawable.magenta));
        mItems.add(new Item("Dark Gray", R.drawable.dark_gray));
        mItems.add(new Item("Gray",      R.drawable.gray));
        mItems.add(new Item("Green",     R.drawable.green));
        mItems.add(new Item("Cyan",      R.drawable.cyan));
    }

    @Override
    public int getCount() {
        return mItems.size();
    }

    @Override
    public Item getItem(int i) {
        return mItems.get(i);
    }

    @Override
    public long getItemId(int i) {
        return mItems.get(i).drawableId;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        View v = view;
        ImageView picture;
        TextView name;

        if (v == null) {
            v = mInflater.inflate(R.layout.grid_item, viewGroup, false);
            v.setTag(R.id.picture, v.findViewById(R.id.picture));
            v.setTag(R.id.text, v.findViewById(R.id.text));
        }

        picture = (ImageView) v.getTag(R.id.picture);
        name = (TextView) v.getTag(R.id.text);

        Item item = getItem(i);

        picture.setImageResource(item.drawableId);
        name.setText(item.name);

        return v;
    }

    private static class Item {
        public final String name;
        public final int drawableId;

        Item(String name, int drawableId) {
            this.name = name;
            this.drawableId = drawableId;
        }
    }
}

Configure ese adaptador para su GridView:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    GridView gridView = (GridView)findViewById(R.id.gridview);
    gridView.setAdapter(new MyAdapter(this));
}

Y disfruta los resultados:

Ejemplo GridView

Kevin Coppock
fuente
3
¡funcionó! pero me gustaría que me explicara la necesidad de crear una clase para ImageViewy por qué usar algo como esto en <com.example.graphicstest.SquareImageView>lugar de una <ImageView>etiqueta simple en el archivo xml . ¿Podría explicarme más sobre esta relación de aspecto y cómo no crear esta clase afecta los elementos? ¿Hay alguna manera de optimizar esto, sin la necesidad de la ImageViewclase personalizada ? Gracias por tu ayuda de todos modos.
rogcg
10
Básicamente, en la clase ImageView de Android, no hay forma de especificar simplemente "oye, mantén una relación de aspecto cuadrada (ancho / alto) para esta vista" a menos que codifiques el ancho y la altura. Podría hacer algunos ajustes manuales de LayoutParams en getView del adaptador, pero, francamente, es mucho más simple dejar que ImageView maneje todas las medidas, y simplemente anule los resultados para decir "Cualquiera que sea el ancho, haga que mi altura permanezca igual". Nunca tiene que pensarlo, siempre es cuadrado y funciona como se esperaba. Básicamente, esta es la forma más fácil de mantener la vista cuadrada.
Kevin Coppock
8
No puedo pensar en una razón para evitar hacer la clase ImageView personalizada, ya que puedes hacer todo lo que puedas con un ImageView normal, pero esto solo evita que tengas que hacer mediciones y crear instancias de LayoutParams y verificar todo el lugar .
Kevin Coppock
1
Gracias por editar, pensé que podría ser eso, ¡trabajar como un encanto!
Zander
1
@kcoppock: Muchas gracias por compartir este código. Lo que más me gusta es que puedes reemplazar los colores para la vista de imagen por imágenes "reales" y ¡se redimensionan correctamente! Lo que me gustaría entender es si es posible cambiar el tamaño de las vistas para que un cierto número de vistas llene toda la pantalla.
AntonSack
14

otro enfoque simple con cosas integradas modernas como PercentRelativeLayout ahora está disponible para nuevos usuarios que enfrentan este problema. Gracias al equipo de Android por lanzar este artículo.

<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
app:layout_widthPercent="50%">

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/picture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="#55000000"
        android:paddingBottom="15dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:textColor="@android:color/white" />

</FrameLayout>

y para un mejor rendimiento, puede usar algunas cosas como el cargador de imágenes picasso que lo ayudan a llenar todo el ancho de cada imagen de los padres. por ejemplo en tu adaptador deberías usar esto:

int width= context.getResources().getDisplayMetrics().widthPixels;
    com.squareup.picasso.Picasso
            .with(context)
            .load("some url")
            .centerCrop().resize(width/2,width/2)
            .error(R.drawable.placeholder)
            .placeholder(R.drawable.placeholder)
            .into(item.drawableId);

ahora ya no necesita la clase CustomImageView.

PD: recomiendo usar ImageView en lugar de Type Int en la clase Item.

espero que esto ayude..

Setmax
fuente
Con API 26.1 esto se depreció. Ver enlace
Dominikus K.