Gridview с двумя колонками и изображениями с автоматическим изменением размера

179

Я пытаюсь сделать gridview с двумя столбцами. Я имею в виду две фотографии в строке рядом, как это изображение.

введите описание изображения здесь

Но у моих картин есть промежутки между ними, потому что это не тот же самый размер. Вот что я получаю.

введите описание изображения здесь

Как видно на первом рисунке, скрывается легенда, в которой указаны имя контакта и номер телефона. и другие картинки не растягиваются правильно.

Вот мой XML-файл GridView . Как вы можете видеть, columnWidthустановлено значение 200dp . Я бы хотел, чтобы это было автоматически , поэтому размер картинки будет изменяться автоматически для каждого размера экрана.

<?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" />

и вот XML-файл item, который представляет каждый элемент.

<?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>

Так что я хочу, чтобы показать два изображения в строке, и изображения автоматически меняются, независимо от размера экрана. Что я делаю не так на моем макете?

Спасибо.

rogcg
источник
1
Возможно, вам следует попробовать инкапсулировать ImageView в его собственный LinearLayout. Таким образом, вы можете настроить тег LinearLayout именно так, как вам нужно, а затем просто заполнить его ImageView.
Дани
@ Дани, что ты имеешь в виду? я все еще могу настроить ImageView именно так, как я хочу. не могли бы вы привести пример?
rogcg
Я думаю, вам нужно создавать большие пальцы из изображений, которые все одинаковы, например, 100x100 или что вам нужно. Если вы можете видеть на своем примере изображения, эффект, который вы ищете, отображает только часть изображения. И в вашем проекте вы просто отображаете оригинальное изображение, что неправильно, если вам нужно сделать галерею. Попробуйте поискать большие пальцы на веб-сайте android dev :)
Василь Вальчев
@VasilValchev, но проблема в том, что даже если я создаю большие пальцы (например, 100x100), мне нужно изменить его размер для разных размеров экрана. Я уже использую scaleTypeсвойство centerCrop в ImageView. Чего мне нужно добиться, так это сделать изображения рядом друг с другом и автоматически изменять их размер для разных размеров экрана.
rogcg
Вы всегда можете получить размер экрана в горизонтальном белом коде и просто разделить его на / 2. Если вы видите в своем проекте, что проблема в росте, если вы точно знаете свой вес, вы всегда можете сделать идеальный прямоугольник. Я не вижу, где проблема?
Василь Вальчев,

Ответы:

402

Вот сравнительно простой способ сделать это. Добавьте GridView в макет, установив режим растягивания для растягивания ширины столбцов, установите интервал в 0 (или как хотите) и установите количество столбцов в 2:

разреш / макет / 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>

Создайте кастом ImageView, поддерживающий соотношение сторон:

SRC / COM / пример / 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
    }
}

Создайте макет для элемента сетки с помощью этого SquareImageView и установите для scaleType значение centerCrop:

разреш / макет / 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>

Теперь сделайте своего рода адаптер для вашего GridView:

SRC / COM / пример / 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;
        }
    }
}

Установите этот адаптер на ваш 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));
}

И наслаждайтесь результатами:

Пример GridView

Кевин Коппок
источник
3
это сработало! но я хотел бы, чтобы вы объяснили мне необходимость создания класса для ImageViewи почему используйте что-то подобное этому <com.example.graphicstest.SquareImageView>вместо простого <ImageView>тега в файле XML . Не могли бы вы объяснить мне больше об этом соотношении сторон , и как не создание этого класса влияет на элементы. Есть ли способ оптимизировать это, без необходимости пользовательского ImageViewкласса? в любом случае спасибо за вашу помощь.
rogcg
10
По сути, в классе ImageView для Android нет способа просто указать «эй, сохраняйте квадратное соотношение сторон (ширина / высота) для этого вида», если только вы не указали ширину и высоту кода. Вы можете выполнить некоторую ручную настройку LayoutParams в getView адаптера, но, честно говоря, намного проще позволить ImageView обрабатывать все измерения и просто переопределить результаты, чтобы сказать: «Какой бы ни была ширина, оставьте мою высоту неизменной». Вы никогда не должны думать об этом, он всегда квадратный, и он просто работает, как и ожидалось. По сути, это самый простой способ сохранить площадь обзора.
Кевин Коппок
8
Я не могу придумать причину, по которой стоит избегать создания пользовательского класса ImageView, так как вы можете делать с ним все, что можете с обычным ImageView, но это просто избавляет вас от необходимости выполнять измерения и создание экземпляров LayoutParams и проверку повсюду. ,
Кевин Коппок
1
Спасибо за редактирование, думал, что это может быть, работая как шарм!
Зандер
1
@kcoppock: Большое спасибо за то, что поделились этим кодом. Что мне больше всего нравится, так это то, что вы можете заменить цвета для изображения на «настоящие» картинки, и их размер будет правильно изменен! Я хотел бы понять, можно ли изменить размеры представлений таким образом, чтобы определенное количество представлений занимало весь экран.
AntonSack
14

Еще один простой подход с современными встроенными функциями, такими как PercentRelativeLayout , теперь доступен для новых пользователей, которые столкнулись с этой проблемой. спасибо команде Android за выпуск этого элемента.

<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>

и для лучшей производительности вы можете использовать некоторые вещи, такие как Picasso Image Loader, которые помогут вам заполнить всю ширину каждого изображения родителей. например, в вашем адаптере вы должны использовать это:

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);

теперь вам больше не нужен класс CustomImageView.

PS Я рекомендую использовать ImageView вместо типа Int в классе Item.

надеюсь, это поможет ..

SetMax
источник
С API 26.1 это было ограничено. Смотрите ссылку
Dominikus K.