Rasteransicht mit zwei Spalten und Bildern mit automatischer Größenänderung

179

Ich versuche, eine Rasteransicht mit zwei Spalten zu erstellen. Ich meine zwei Fotos pro Reihe nebeneinander, genau wie dieses Bild.

Geben Sie hier die Bildbeschreibung ein

Aber meine Bilder haben Leerzeichen dazwischen, weil sie nicht gleich groß sind. Hier ist was ich bekomme.

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, verbirgt das erste Bild die Legende, die den Kontaktnamen und die Telefonnummer anzeigt. und die anderen Bilder sind nicht richtig gedehnt.

Hier ist meine GridView- XML-Datei. Wie Sie sehen können, columnWidthist der Wert auf 200 dp eingestellt . Ich möchte, dass es automatisch ist , damit die Größe der Bilder für jede Bildschirmgröße automatisch geändert wird.

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

und hier ist die Element-XML-Datei, die jedes Element selbst darstellt.

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

Ich möchte also zwei Bilder pro Zeile anzeigen und die Größe der Bilder unabhängig von der Bildschirmgröße automatisch ändern. Was mache ich falsch in meinem Layout?

Vielen Dank.

Rogcg
quelle
1
Vielleicht sollten Sie versuchen, die ImageView in einem eigenen LinearLayout zu kapseln. Auf diese Weise können Sie das LinearLayout-Tag genau so konfigurieren, wie Sie es möchten, und es dann einfach von ImageView ausfüllen lassen.
Dani
@dani was meinst du? Ich kann das ImageView immer noch genau so konfigurieren, wie ich es möchte. Könntest du mir ein Beispiel geben?
Rogcg
Ich denke, Sie müssen Daumen aus Bildern erstellen, die alle gleich sind, ex 100x100 oder was auch immer Sie sie brauchen. Wenn Sie auf Ihrem Beispielbild sehen können, zeigt der gesuchte Effekt nur einen Teil des Bildes an. Und in Ihrem Projekt zeigen Sie nur das Originalbild an, was falsch ist, wenn Sie eine Galerie erstellen müssen. Versuchen Sie, nach Daumen in der Android Dev-Website zu suchen :)
Vasil Valchev
@ VasilValchev, aber das Problem ist, selbst wenn ich Daumen erstelle (z. B. 100x100), muss ich die Größe für verschiedene Bildschirmgrößen ändern. Ich verwende bereits die centerCrop- scaleTypeEigenschaft in der ImageView. Was ich erreichen muss, ist eine Möglichkeit, die Bilder nebeneinander zu erstellen und die Größe automatisch für verschiedene Bildschirmgrößen zu ändern.
Rogcg
Sie können die Bildschirmgröße immer in horizontalem Weißcode erhalten und einfach durch / 2 teilen. Wenn Sie in Ihrem Projekt sehen können, dass das Problem in der Höhe liegt, wenn Sie genau wissen, wie schwer Sie sind, können Sie immer ein perfektes Rechteck erstellen. Ich sehe nicht, wo das Problem liegt?
Vasil Valchev

Antworten:

402

Hier ist eine relativ einfache Methode, um dies zu tun. Fügen Sie eine GridView in Ihr Layout ein, stellen Sie den Streckmodus so ein, dass die Spaltenbreiten gedehnt werden, setzen Sie den Abstand auf 0 (oder was auch immer Sie wollen) und setzen Sie die Anzahl der Spalten auf 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>

Erstellen Sie einen benutzerdefinierten Benutzer ImageView, der sein Seitenverhältnis beibehält:

src / com / example / graphicsstest / 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
    }
}

Erstellen Sie mit dieser SquareImageView ein Layout für ein Rasterelement und setzen Sie den scaleType auf 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>

Machen Sie jetzt eine Art Adapter für Ihre GridView:

src / com / example / graphicsstest / 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;
        }
    }
}

Stellen Sie diesen Adapter auf Folgendes ein 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));
}

Und genießen Sie die Ergebnisse:

Beispiel GridView

Kevin Coppock
quelle
3
es funktionierte! Aber ich möchte, dass Sie mir erklären, wie wichtig es ist, eine Klasse für das zu erstellen, ImageViewund warum Sie so etwas <com.example.graphicstest.SquareImageView>anstelle eines einfachen <ImageView>Tags in der XML- Datei verwenden. Können Sie mir mehr über dieses Seitenverhältnis erklären und wie sich das Nichterstellen dieser Klasse auf die Elemente auswirkt? Gibt es eine Möglichkeit, dies zu optimieren, ohne dass die benutzerdefinierte ImageViewKlasse erforderlich ist ? Trotzdem danke für deine Hilfe.
Rogcg
10
Grundsätzlich gibt es in der ImageView-Klasse von Android keine Möglichkeit, einfach "Hey, behalte ein quadratisches Seitenverhältnis (Breite / Höhe) für diese Ansicht" anzugeben, es sei denn, Sie codieren Breite und Höhe fest. Sie können LayoutParams in getView des Adapters manuell anpassen, aber ehrlich gesagt ist es viel einfacher, ImageView alle Messungen durchführen zu lassen und die Ergebnisse einfach zu überschreiben, um zu sagen: "Unabhängig von der Breite bleibt meine Höhe gleich". Sie müssen nie darüber nachdenken, es ist immer quadratisch und es funktioniert einfach wie erwartet. Grundsätzlich ist dies der einfachste Weg, um die Ansicht quadratisch zu halten.
Kevin Coppock
8
Ich kann nicht glauben , dass ein Grund zu vermeiden macht die benutzerdefinierte Image Klasse, wie Sie alles , was damit zu tun , dass Sie mit einem normalen Image können, aber das hält man nur aus, die alle über den Ort zu tun , Messungen und LayoutParams Instanziierung und Überprüfung .
Kevin Coppock
1
Vielen Dank für die Bearbeitung, dachte, es könnte sein, wie ein Zauber zu arbeiten!
Zander
1
@kcoppock: Vielen Dank für das Teilen dieses Codes. Was mir am besten gefällt ist, dass Sie die Farben für die Bildansicht durch "echte" Bilder ersetzen können und die Größe richtig angepasst wird! Ich würde gerne verstehen, ob es möglich ist, die Größe der Ansichten so zu ändern, dass eine bestimmte Anzahl von Ansichten den gesamten Bildschirm ausfüllt.
AntonSack
14

Ein weiterer einfacher Ansatz mit modernen integrierten Funktionen wie PercentRelativeLayout ist jetzt für neue Benutzer verfügbar, die auf dieses Problem stoßen . Vielen Dank an das Android-Team für die Veröffentlichung dieses Artikels.

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

und für eine bessere Leistung können Sie einige Dinge wie Picasso Image Loader verwenden, die Ihnen helfen, die gesamte Breite aller Bildeltern zu füllen. In Ihrem Adapter sollten Sie beispielsweise Folgendes verwenden:

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

Jetzt brauchen Sie keine CustomImageView-Klasse mehr.

PS Ich empfehle, ImageView anstelle von Typ Int in der Klasse Item zu verwenden.

Ich hoffe das hilft..

Setmax
quelle
Mit API 26.1 wurde dies entzogen. Siehe Link
Dominikus K.