Stały widok proporcji obrazu

Jak mam zaimplementować stały współczynnik proporcji View? Chciałbym mieć przedmioty o proporcjach 1: 1 w GridView. Myślę, że lepiej podklasować dzieci niż GridView?

EDIT: zakładam, że trzeba to zrobić programowo, to żaden problem. Nie chcę też ograniczać rozmiaru, tylko proporcje.

Author: cb4, 2011-08-14

7 answers

Zaimplementowałem FixedAspectRatioFrameLayout, więc mogę go ponownie użyć i mieć dowolny widok hostowany ze stałym współczynnikiem proporcji:

public class FixedAspectRatioFrameLayout extends FrameLayout
{
    private int mAspectRatioWidth;
    private int mAspectRatioHeight;

    public FixedAspectRatioFrameLayout(Context context)
    {
        super(context);
    }

    public FixedAspectRatioFrameLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        init(context, attrs);
    }

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

        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs)
    {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FixedAspectRatioFrameLayout);

        mAspectRatioWidth = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioWidth, 4);
        mAspectRatioHeight = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioHeight, 3);

        a.recycle();
    }
    // **overrides**

    @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
    {
        int originalWidth = MeasureSpec.getSize(widthMeasureSpec);

        int originalHeight = MeasureSpec.getSize(heightMeasureSpec);

        int calculatedHeight = originalWidth * mAspectRatioHeight / mAspectRatioWidth;

        int finalWidth, finalHeight;

        if (calculatedHeight > originalHeight)
        {
            finalWidth = originalHeight * mAspectRatioWidth / mAspectRatioHeight; 
            finalHeight = originalHeight;
        }
        else
        {
            finalWidth = originalWidth;
            finalHeight = calculatedHeight;
        }

        super.onMeasure(
                MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY), 
                MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
    }
}
 71
Author: TalL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 17:51:23

Dla nowych użytkowników, oto lepsze rozwiązanie non-code:

Nowa biblioteka wsparcia o nazwie procentowa Biblioteka wsparcia jest dostępny w Android SDK v22 (MinAPI jest 7 ja myślę, nie jestem pewien):

Src: android-developers.blogspot.in

Biblioteka obsługi procent zapewnia wymiary i marginesy oparte na procentach, a także, nowość w tej wersji, możliwość ustawienia niestandardowego współczynnika proporcji za pomocą aplikacji: aspectRatio. Przez ustawiając tylko jedną szerokość lub wysokość i używając aspectRatio, Procentframelayout lub Procentrelativelayout automatycznie dostosuje inny wymiar, tak aby układ używał ustawionego współczynnika proporcji.

To include add this to your build.gradle :

compile 'com.android.support:percent:23.1.1'

Teraz zawiń swój Widok (ten, który musi być kwadratowy) z PercentRelativeLayout / PercentFrameLayout :

<android.support.percent.PercentRelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
     <ImageView
         app:layout_aspectRatio="100%"
         app:layout_widthPercent="100%"/>
 </android.support.percent.PercentRelativeLayout>

Możesz zobaczyć przykład tutaj .

 37
Author: ShahiM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-15 23:09:51

Ostatnio zrobiłem klasę pomocniczą dla tego właśnie problemu i napisałem blog o tym .

Mięso kodeksu jest następujące:

/**
 * Measure with a specific aspect ratio<br />
 * <br />
 * @param widthMeasureSpec The width <tt>MeasureSpec</tt> passed in your <tt>View.onMeasure()</tt> method
 * @param heightMeasureSpec The height <tt>MeasureSpec</tt> passed in your <tt>View.onMeasure()</tt> method
 * @param aspectRatio The aspect ratio to calculate measurements in respect to 
 */
public void measure(int widthMeasureSpec, int heightMeasureSpec, double aspectRatio) {
    int widthMode = MeasureSpec.getMode( widthMeasureSpec );
    int widthSize = widthMode == MeasureSpec.UNSPECIFIED ? Integer.MAX_VALUE : MeasureSpec.getSize( widthMeasureSpec );
    int heightMode = MeasureSpec.getMode( heightMeasureSpec );
    int heightSize = heightMode == MeasureSpec.UNSPECIFIED ? Integer.MAX_VALUE : MeasureSpec.getSize( heightMeasureSpec );

    if ( heightMode == MeasureSpec.EXACTLY && widthMode == MeasureSpec.EXACTLY ) {
        /* 
         * Possibility 1: Both width and height fixed
         */
        measuredWidth = widthSize;
        measuredHeight = heightSize;

    } else if ( heightMode == MeasureSpec.EXACTLY ) {
        /*
         * Possibility 2: Width dynamic, height fixed
         */
        measuredWidth = (int) Math.min( widthSize, heightSize * aspectRatio );
        measuredHeight = (int) (measuredWidth / aspectRatio);

    } else if ( widthMode == MeasureSpec.EXACTLY ) {
        /*
         * Possibility 3: Width fixed, height dynamic
         */
        measuredHeight = (int) Math.min( heightSize, widthSize / aspectRatio );
        measuredWidth = (int) (measuredHeight * aspectRatio);

    } else {
        /* 
         * Possibility 4: Both width and height dynamic
         */
        if ( widthSize > heightSize * aspectRatio ) {
            measuredHeight = heightSize;
            measuredWidth = (int)( measuredHeight * aspectRatio );
        } else {
            measuredWidth = widthSize;
            measuredHeight = (int) (measuredWidth / aspectRatio);
        }

    }
}
 8
Author: JesperB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 18:53:32

Aby nie używać rozwiązań innych firm i biorąc pod uwagę fakt, że zarówno Procentframelayout, jak i Procentrelativelayout były przestarzałe w 26.0.0, sugerowałbym rozważenie użycia ConstraintLayout jako głównego układu dla elementów siatki.

Twoje item_grid.xml może wyglądać tak:

<android.support.constraint.ConstraintLayout
    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="wrap_content">

    <ImageView
        android:id="@+id/imageview_item"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="H,1:1" />

</android.support.constraint.ConstraintLayout>

W rezultacie otrzymujesz coś takiego:

Elementy siatki o stałym rozmiarze

 8
Author: Eugene Brusov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-25 15:40:35

Użyłem i polubiłem implementację ImageView Jake ' a Whartona (powinno być podobnie dla innych widoków), innym też może się spodobać:

AspectRatioImageView.java - ImageView, który respektuje współczynnik proporcji zastosowany do określonego pomiaru

Fajna sprawa jest już styleable w xml.

 4
Author: Czechnology,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-24 20:16:06

Wystarczy zastąpić onSizeChanged i obliczyć współczynnik.

Wzór na proporcje wynosi:

newHeight =  original_height / original_width x new_width

To da ci coś takiego:

 @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    //3:5 ratio
    float RATIO = 5/3;
    setLayoutParams(new LayoutParams((int)RATIO * w, w));

}
Mam nadzieję, że to pomoże!
 3
Author: Jmorvan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 14:00:24

Stworzyłem bibliotekę układu używając odpowiedzi TalL . Możesz go użyć.

RatioLayouts

Instalacja

Dodaj to do góry pliku

repositories {
    maven {
        url  "http://dl.bintray.com/riteshakya037/maven" 
    }
}


dependencies {
    compile 'com.ritesh:ratiolayout:1.0.0'
}

Użycie

Zdefiniuj przestrzeń nazw ' app ' w widoku głównym w układzie

xmlns:app="http://schemas.android.com/apk/res-auto"

Dołącz tę bibliotekę do układu

<com.ritesh.ratiolayout.RatioRelativeLayout
        android:id="@+id/activity_main_ratio_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:fixed_attribute="WIDTH" // Fix one side of the layout 
        app:horizontal_ratio="2" // ratio of 2:3
        app:vertical_ratio="3">

Update

Z wprowadzeniem ConstraintLayout nie musisz pisać ani jednej linii kodu, ani używać stron trzecich lub polegaj na PercentFrameLayout, które zostały wycofane w 26.0.0.

Oto przykład, jak zachować proporcje 1: 1 dla układu za pomocą ConstraintLayout:
<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        android:layout_marginTop="0dp"
        android:background="@android:color/black"
        app:layout_constraintDimensionRatio="H,1:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </LinearLayout>

</android.support.constraint.ConstraintLayout>
 3
Author: riteshakya037,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-26 10:37:26