ImageView - czy wysokość dopasowania do szerokości?

166

Mam widok obrazu. Chcę, aby jego szerokość była wypełniona_parent. Chcę, aby jego wysokość była taka sama, jak szerokość. Na przykład:

<ImageView
  android:layout_width="fill_parent"
  android:layout_height="whatever the width ends up being" />

Czy coś takiego jest możliwe w pliku układu bez konieczności tworzenia własnej klasy widoku?

Dzięki

user291701
źródło
Czy wiesz, jak to zrobić? Zakładam, że chcesz, aby proporcje pozostały takie same. Większość tych odpowiedzi zakłada, że ​​chcesz, aby obraz był kwadratowy.
Adam
@Joe Blow, to BARDZO zły sposób na zrobienie tego
Agresor

Odpowiedzi:

170

Aktualizacja: 14 września 2017 r

Zgodnie z poniższym komentarzem biblioteka procentowego wsparcia jest przestarzała od wersji 26.0.0 Android Support Library. Oto nowy sposób na zrobienie tego:

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

</android.support.constraint.ConstraintLayout>

Zobacz tutaj

Wycofane:

Zgodnie z tym postem napisanym przez programistów Androida, wszystko, co musisz teraz zrobić, to zawinąć wszystko, co chcesz, w PercentRelativeLayout lub PercentFrameLayout, a następnie określić jego współczynniki

<android.support.percent.PercentRelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        app:layout_widthPercent="100%"
        app:layout_aspectRatio="100%"/>

</android.support.percent.PercentRelativeLayout>
davidchuyaya
źródło
8
Link do tej odpowiedzi ma najbardziej eleganckie rozwiązanie dostarczone przez Google. W moim przypadku chciałem, aby obraz był wyświetlany w proporcjach 16: 9 bez względu na oryginalne proporcje obrazu. Działa świetnie. Dzięki!
LETs
W moim przypadku rozwiązania takie jak ten nie działały, ten działał!
Gooey,
5
nie zapomnij dodać „compile com.android.support:percent:23.3.0” w swoich zależnościach
Milad Faridnia
Wygląda na to, że to podejście ma problemy z WrappedViewPager, który oblicza wysokość na podstawie zawartości podrzędnej. Źródło dla WrappedViewPager podobne do gist.github.com/egslava/589b82a6add9c816a007
sha
1
Moduł obsługi procentowej jest przestarzały i jest przestarzały od czasu biblioteki obsługi Androida 26.0.0. Źródło: developer.android.com/topic/libraries/support-library/ ...
MHogge
97

Może to odpowie na twoje pytanie:

<ImageView
    android:id="@+id/cover_image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true" />

Możesz zignorować scaleTypeatrybut dla tej konkretnej sytuacji.

Vlad Stefanescu
źródło
12
Tak, to bezużyteczne
Fattie
4
To niekoniecznie jest bezużyteczne. Działa to dobrze w moim przypadku, mam ikonę na pasku tytułowym, którą chcę przeskalować, aby wypełnić wysokość, pozostając kwadratowym.
Anubian Noob
3
Rozwiązał też mój problem.
Dielson Sales
Najłatwiej! Powinno to być oznaczone jako Najlepsza odpowiedź.
H. Farid
30

Można to zrobić za pomocą LayoutParams, aby dynamicznie ustawić wysokość widoków, gdy znasz szerokość widoków w czasie wykonywania. Musisz użyć wątku Runnable, aby uzyskać szerokość widoków w czasie wykonywania, w przeciwnym razie będziesz próbował ustawić wysokość, zanim poznasz szerokość widoku, ponieważ układ nie został jeszcze narysowany.

Przykład tego, jak rozwiązałem swój problem:

final FrameLayout mFrame = (FrameLayout) findViewById(R.id.frame_id);

    mFrame.post(new Runnable() {

        @Override
        public void run() {
            RelativeLayout.LayoutParams mParams;
            mParams = (RelativeLayout.LayoutParams) mFrame.getLayoutParams();
            mParams.height = mFrame.getWidth();
            mFrame.setLayoutParams(mParams);
            mFrame.postInvalidate();
        }
    });

LayoutParams musi być typu widoku nadrzędnego, w którym znajduje się widok. Mój układ FrameLayout znajduje się wewnątrz elementu RelativeLayout w pliku xml.

    mFrame.postInvalidate();

jest wywoływana, aby wymusić ponowne rysowanie widoku w innym wątku niż wątek interfejsu użytkownika

drees
źródło
4
świetna odpowiedź, szczególnie w przypadku Runnable, dzięki!
jesses.co.tt
1
Chociaż to działa, nie jest idealne. Uruchomiony w poście oznacza, że ​​widok renderuje się raz przed zmianą układu. Może pozwolić na błysk zawartości na niewłaściwej wysokości, przed prawidłowym rysowaniem. Lepiej rozwiązać wcześniej. Najwcześniejszym możliwym momentem do rozwiązania jest zwyczaj onMeasure, jak pokazano w odpowiedzi Regisa . Alternatywą, ale tylko dla widoków renderowanych przez adapter, np. Wewnątrz GridView, jest odpowiedź Matta .
ToolmakerSteve
1
dobrze u mnie zadziałało dopiero po wywołaniu requestLayout()po ustawieniu parametrów. dlaczego tak by było?
Divins Mathew
mFrame.postInvalidate (); co to zrobiło, bez tego miałem widok z pozycji.
Jacolack
17

Nie mogłem uzyskać odpowiedzi Davida Chu, aby pracować dla elementu RecyclerView i zorientowałem się, że muszę ograniczyć ImageView do elementu nadrzędnego. Ustaw szerokość ImageView na 0dpi ogranicz jej początek i koniec do elementu nadrzędnego. Nie jestem pewien, czy ustawienie szerokości na wrap_contentlub match_parentdziała w niektórych przypadkach, ale myślę, że jest to lepszy sposób, aby element podrzędny ConstraintLayout wypełnił jego element nadrzędny.

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="1:1"/>

</android.support.constraint.ConstraintLayout>
Shawn Aten
źródło
13

Oto, co zrobiłem, aby mieć ImageButton, który zawsze ma szerokość równą jego wysokości (i unikam głupich pustych marginesów w jednym kierunku ... które uważam za błąd SDK ...):

Zdefiniowałem klasę SquareImageButton, która dziedziczy z ImageButton:

package com.myproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;

    public class SquareImageButton extends ImageButton {

        public SquareImageButton(Context context) {
        super(context);


        // TODO Auto-generated constructor stub
    }

    public SquareImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

    }

    public SquareImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    int squareDim = 1000000000;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        int h = this.getMeasuredHeight();
        int w = this.getMeasuredWidth();
        int curSquareDim = Math.min(w, h);
        // Inside a viewholder or other grid element,
        // with dynamically added content that is not in the XML,
        // height may be 0.
        // In that case, use the other dimension.
        if (curSquareDim == 0)
            curSquareDim = Math.max(w, h);

        if(curSquareDim < squareDim)
        {
            squareDim = curSquareDim;
        }

        Log.d("MyApp", "h "+h+"w "+w+"squareDim "+squareDim);


        setMeasuredDimension(squareDim, squareDim);

    }

}

Oto mój xml:

<com.myproject.SquareImageButton
            android:id="@+id/speakButton"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerInside"
            android:src="@drawable/icon_rounded_no_shadow_144px"
            android:background="#00ff00"
            android:layout_alignTop="@+id/searchEditText"
            android:layout_alignBottom="@+id/searchEditText"
            android:layout_alignParentLeft="true"
           />

Działa jak marzenie !

Regis_AG
źródło
Tak, to najlepsza odpowiedź. (i jedyny, który naprawdę pasuje do pytania PO)
Twometer,
6

W systemie Android 26.0.0 PercentRelativeLayout został wycofany .

Najlepszym sposobem rozwiązania tego problemu jest teraz ConstraintLayout:

<android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

    <ImageView android:layout_width="match_parent"
               android:layout_height="0dp"
               android:scaleType="centerCrop"
               android:src="@drawable/you_image"                       
               app:layout_constraintDimensionRatio="1:1"/>


</android.support.constraint.ConstraintLayout>


Oto samouczek dotyczący dodawania ConstraintLayoutdo projektu.

Sebastian Schneider
źródło
6

Jeśli widok obrazu znajduje się wewnątrz układu ograniczonego, można użyć następujących ograniczeń, aby utworzyć kwadratowy widok obrazu

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:id="@+id/ivImageView"
    app:layout_constraintDimensionRatio="W,1:1"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>
ChaturaM
źródło
5

Nie możesz tego zrobić z samym układem, próbowałem. Skończyło się na tym, że napisałem bardzo prostą klasę do obsługi tego, możesz to sprawdzić na githubie. SquareImage.java Jest częścią większego projektu, ale nic, czego nie można naprawić, małe kopiowanie i wklejanie (licencjonowane w ramach Apache 2.0)

Zasadniczo wystarczy ustawić wysokość / szerokość równą innemu wymiarowi (w zależności od tego, w jaki sposób chcesz go skalować)

Uwaga: możesz ustawić go jako kwadratowy bez niestandardowej klasy, używając scaleTypeatrybutu, ale granice widoku wykraczają poza widoczny obraz, co sprawia, że ​​problem jest, jeśli umieszczasz w pobliżu inne widoki.

smith324
źródło
3

Aby ustawić ImageView na połowę ekranu, musisz dodać do swojego kodu XML dla ImageView:

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:scaleType="fitXY"
    android:adjustViewBounds="true"/>

Aby następnie ustawić wysokość równą tej szerokości, musisz to zrobić w kodzie. W getViewmetodzie swojego GridViewadaptera ustaw ImageViewwysokość równą jego zmierzonej szerokości:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();
Matt Logan
źródło
3

Dla osób przechodzących teraz, w 2017 roku, najlepszym sposobem na osiągnięcie tego, co chcesz, jest użycie ConstraintLayout w następujący sposób:

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:layout_constraintDimensionRatio="1:1" />

I nie zapomnij dodać ograniczeń we wszystkich czterech kierunkach zgodnie z wymaganiami układu.

Zbuduj responsywny interfejs użytkownika z ConstraintLayout

Ponadto do tej pory PercentRelativeLayout jest przestarzały (zobacz dokumentację systemu Android ).

Cristina De Rito
źródło
1

Oto jak rozwiązałem ten problem:

int pHeight =  picture.getHeight();
int pWidth = picture.getWidth();
int vWidth = preview.getWidth();
preview.getLayoutParams().height = (int)(vWidth*((double)pHeight/pWidth));

podgląd - imageView z szerokością ustawioną na „match_parent” i scaleType na „cropCenter”

picture - Obiekt bitmapowy do ustawienia w src imageView.

U mnie to działa całkiem nieźle.

udenfox
źródło
Nie wyjaśniłeś, gdzie należy umieścić ten kod. Nie wyjaśniłeś również, dlaczego to robisz, = vw*ph/pwzamiast prostszego = vw. (Myślę, że robisz to, aby zachować proporcje obrazu źródłowego, zamiast wymuszać kwadratowy podgląd.)
ToolmakerSteve
0

Nie sądzę, aby można było to zrobić w pliku układu XML i nie sądzę, aby android:scaleTypeatrybut działał tak, jak chcesz.
Jedynym sposobem byłoby zrobienie tego programowo. Możesz ustawić szerokość na fill_parent i albo przyjąć szerokość ekranu jako wysokość, Viewalbo użyć View.getWidth()metody.

Nowicjusz
źródło
0

W tym przypadku może Ci pomóc funkcja „scaleType” ImageView.

Ten kod zachowa proporcje i umieści obraz na górze:

android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitStart"

Oto świetny post przedstawiający możliwości i wygląd przy użyciu scaleType.

Przykłady skali ImageView typu scaleType

ac_banks
źródło
„scaleType” nie pomaga tutaj. Celem jest, aby sam ImageView był zawsze kwadratowy, a nie tylko obraz wewnątrz niego. W przypadku scaleType ImageView może być większy niż obraz.
ToolmakerSteve
0

podobało mi się to -

layout.setMinimumHeight(layout.getWidth());
HarshitG
źródło