Widok siatki z dwiema kolumnami i automatycznie zmieniającymi się obrazami

179

Próbuję utworzyć widok siatki z dwoma kolumnami. Mam na myśli dwa zdjęcia obok siebie, tak jak to zdjęcie.

wprowadź opis zdjęcia tutaj

Ale moje zdjęcia mają odstępy między nimi, ponieważ nie są tego samego rozmiaru. Oto co otrzymuję.

wprowadź opis zdjęcia tutaj

jak widać pierwsze zdjęcie ukrywa legendę, która pokazuje nazwę kontaktu i numer telefonu. a pozostałe zdjęcia nie są poprawnie rozciągnięte.

Oto mój plik xml GridView . Jak widać, columnWidthustawiony jest na 200dp . Chciałbym, aby była automatyczna , więc rozmiar obrazu będzie się zmieniać automatycznie dla każdego rozmiaru ekranu.

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

a tutaj jest plik xml elementu, który reprezentuje każdy element sam.

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

Chcę więc wyświetlać dwa obrazy w wierszu, a obrazy automatycznie się zmieniają, bez względu na rozmiar ekranu. Co robię źle na moim układzie?

Dzięki.

rogcg
źródło
1
Być może powinieneś spróbować enkapsulować ImageView we własnym LinearLayout. W ten sposób możesz skonfigurować tag LinearLayout dokładnie tak, jak chcesz, a następnie po prostu poprosić ImageView o wypełnienie go.
dani
@dani, co masz na myśli? Nadal mogę skonfigurować ImageView dokładnie tak, jak chcę. czy możesz podać mi jakiś przykład?
rogcg,
myślę, że musisz tworzyć kciuki z obrazów, które są takie same, np. 100 x 100 lub cokolwiek, czego potrzebujesz. Jeśli widzisz na przykładowym obrazie, efekt, którego szukasz, wyświetla tylko część obrazu. A w swoim projekcie wyświetlasz tylko oryginalny obraz, co jest złe, jeśli musisz zrobić galerię. Spróbuj poszukać kciuka w witrynie
deweloperów
@VasilValchev, ale problem polega na tym, że nawet jeśli utworzę kciuki (np. 100 x 100), będę musiał zmienić jego rozmiar dla różnych rozmiarów ekranu. Korzystam już z scaleTypewłaściwości centerCrop w ImageView. To, co muszę osiągnąć, to sposób na robienie zdjęć obok siebie i automatyczne zmienianie rozmiaru dla różnych rozmiarów ekranu.
rogcg,
Zawsze możesz uzyskać rozmiar ekranu w poziomym kodzie i po prostu podzielić go przez / 2. Jeśli widzisz w swoim projekcie problem dotyczy wysokości, jeśli wiesz dokładnie, jaka jest twoja waga, zawsze możesz zrobić idealny prostokąt. Nie widzę, gdzie jest problem?
Vasil Valchev

Odpowiedzi:

402

Oto stosunkowo prosta metoda, aby to zrobić. Wrzuć GridView do swojego układu, ustawiając tryb rozciągania w celu rozciągnięcia szerokości kolumn, ustaw odstępy na 0 (lub cokolwiek chcesz) i ustaw liczbę kolumn na 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>

Stwórz niestandardowy, ImageViewktóry zachowa proporcje:

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

Utwórz układ elementu siatki za pomocą tego SquareImageView i ustaw skalęType na 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>

Teraz stwórz jakiś adapter dla 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;
        }
    }
}

Ustaw ten adapter na swój 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));
}

I ciesz się wynikami:

Przykład GridView

Kevin Coppock
źródło
3
zadziałało! ale chciałbym, abyś wyjaśnił mi potrzebę utworzenia klasy dla tego ImageViewi dlaczego używać czegoś takiego <com.example.graphicstest.SquareImageView>zamiast prostego <ImageView>znacznika w pliku xml . Czy mógłbyś mi wyjaśnić więcej na temat tego współczynnika kształtu i tego, jak nie utworzenie tej klasy wpływa na przedmioty. czy istnieje sposób na zoptymalizowanie tego bez potrzeby korzystania z niestandardowej ImageViewklasy? i tak dziękuję za pomoc.
rogcg,
10
Zasadniczo w klasie ImageView Androida nie można po prostu określić „hej, zachowaj kwadratowy współczynnik kształtu (szerokość / wysokość) dla tego widoku”, chyba że podasz twardą szerokość i wysokość kodu. Możesz dokonać ręcznej regulacji LayoutParams w getView adaptera, ale szczerze mówiąc, znacznie łatwiej jest pozwolić ImageView obsługiwać wszystkie pomiary, i po prostu przesłonić wyniki, by powiedzieć: „Niezależnie od tego, jaka szerokość się skończy, spraw, by mój wzrost pozostał taki sam”. Nigdy nie musisz o tym myśleć, zawsze jest kwadratowy i działa po prostu zgodnie z oczekiwaniami. Zasadniczo jest to najłatwiejszy sposób, aby zachować kwadrat.
Kevin Coppock,
8
Nie mogę wymyślić powodu, aby uniknąć tworzenia niestandardowej klasy ImageView, ponieważ możesz zrobić z nią wszystko, co możesz za pomocą zwykłego ImageView, ale to tylko powstrzymuje cię od konieczności wykonywania pomiarów i tworzenia instancji LayoutParams i sprawdzania w dowolnym miejscu .
Kevin Coppock,
1
Dzięki za edycję, myślałem, że może tak być, działając jak urok!
Zander
1
@kcoppock: Bardzo dziękuję za udostępnienie tego kodu. Najbardziej podoba mi się to, że możesz zastąpić kolory widoku obrazu „prawdziwymi” zdjęciami, a ich rozmiar jest odpowiednio zmieniany! Chciałbym zrozumieć, czy można zmienić rozmiar widoków, tak aby pewna liczba widoków wypełniała cały ekran.
AntonSack
14

inne proste podejście z nowoczesnymi wbudowanymi funkcjami, takie jak PercentRelativeLayout, jest teraz dostępne dla nowych użytkowników, którzy napotkali ten problem. dzięki zespołowi Androida za wydanie tego elementu.

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

a dla lepszej wydajności możesz użyć pewnych rzeczy, takich jak program ładujący obraz Picasso, który pomaga wypełnić całą szerokość każdego rodzica obrazu. na przykład w adapterze powinieneś użyć tego:

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

teraz już nie potrzebujesz klasy CustomImageView.

PS Polecam używać ImageView zamiast Type Int w klasie Przedmiot.

Mam nadzieję, że to pomoże..

Setmax
źródło
W przypadku API 26.1 sytuacja się pogorszyła. Zobacz link
Dominikus K.,