web-dev-qa-db-ja.com

固定アスペクト比ビュー

固定アスペクト比Viewを実装するにはどうすればよいですか? GridViewにアスペクト比1:1のアイテムが欲しいです。 GridViewよりも子をサブクラス化する方が良いと思いますか?

編集:これはプログラムで行う必要があると思いますが、それは問題ありません。また、サイズを制限するのではなく、アスペクト比のみを制限します。

41
Jani

FixedAspectRatioFrameLayoutを実装したので、それを再利用して、ホストされたビューを固定アスペクト比にすることができます。

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));
    }
}
76
TalL

新規ユーザー向けの、より優れた非コードソリューションを以下に示します。

パーセントサポートライブラリ と呼ばれる新しいサポートライブラリは、Android SDK v22で利用可能です(MinAPIは- 7私は考えている、わからない):

src: Android-developers.blogspot.in

パーセントサポートライブラリは、パーセントベースの寸法とマージンを提供します。このリリースでは、app:aspectRatioを介してカスタムアスペクト比を設定する機能が追加されました。単一の幅または高さのみを設定し、aspectRatioを使用することにより、PercentFrameLayoutまたはPercentRelativeLayoutは、レイアウトが設定されたアスペクト比を使用するように他の寸法を自動的に調整します。

これを含めるには、これをbuild.gradleに追加します。

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

ここで、ビュー(正方形にする必要があるビュー)を 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>

あなたは例を見ることができます here

38
ShahiM

サードパーティのソリューションを使用せず、PercentFrameLayoutとPercentRelativeLayoutの両方が26.0.0で廃止されたという事実を考慮するために、グリッドアイテムのルートレイアウトとしてConstraintLayoutを使用することを検討することをお勧めします。

きみの item_grid.xmlは次のようになります。

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

その結果、次のような結果が得られます。

Fixed ratio sized grid items

19
Eugene Brusov

最近、この問題のヘルパークラスを作成し、 それに関するブログ記事 を作成しました。

コードの要点は次のとおりです。

/**
 * 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);
        }

    }
}
9
JesperB

TalL の答えを使用してレイアウトライブラリを作成しました。気軽に使用してください。

RatioLayouts

Installation

これをファイルの先頭に追加します

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


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

使用法

レイアウトのルートビューで 'app'名前空間を定義する

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

このライブラリをレイアウトに含めます

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

更新

ConstraintLayout の導入により、1行のコードを記述したり、サードパーティを使用したり、26.0.0で非推奨となったPercentFrameLayoutに依存したりする必要がなくなります。

ConstraintLayoutを使用してレイアウトのアスペクト比を1:1に保つ方法の例を次に示します。

<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>
4
Ritesh Shakya

私はImageViewのJake Whartonの実装を使用し、気に入っています(他のビューでも同様に行う必要があります)。

AspectRatioImageView.Java -特定の測定に適用されるアスペクト比を尊重するImageView

良いことは、すでにxmlでスタイル設定可能です。

4
Czechnology

単にonSizeChangedをオーバーライドし、そこで比率を計算します。

アスペクト比の式は次のとおりです。

newHeight =  original_height / original_width x new_width

これはあなたにそのような何かを与えるでしょう:

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

}

お役に立てれば!

3
Jmorvan

GoogleのExoPlayerには AspectRatioFrameLayout が付属しており、次のように使用します。

<com.google.Android.exoplayer2.ui.AspectRatioFrameLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    app:resize_mode="fixed_width">
    <!-- https://exoplayer.dev/doc/reference/com/google/Android/exoplayer2/ui/AspectRatioFrameLayout.html#RESIZE_MODE_FIXED_WIDTH -->

    <ImageView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" />

</com.google.Android.exoplayer2.ui.AspectRatioFrameLayout>

次に、アスペクト比をプログラムで設定する必要があります。

aspectRatioFrameLayout.setAspectRatio(16f/9f)

setResizeMode を使用してプログラムでサイズ変更モードを設定することもできます。


この単一クラスのExoPlayerライブラリ全体を取得することは明らかにないので、GitHubからファイルを単純にコピーして貼り付けてくださいをプロジェクト(オープンソース)にできます。

https://github.com/google/ExoPlayer/blob/release-v2/library/ui/src/main/Java/com/google/Android/exoplayer2/ui/AspectRatioFrameLayout.Java

属性resize_modeも取得することを忘れないでください:

https://github.com/google/ExoPlayer/blob/release-v2/library/ui/src/main/res/values/attrs.xml#L18-L25

<attr name="resize_mode" format="enum">
  <enum name="fit" value="0"/>
  <enum name="fixed_width" value="1"/>
  <enum name="fixed_height" value="2"/>
  <enum name="fill" value="3"/>
  <enum name="zoom" value="4"/>
</attr>
0