固定宽高比视图

Jan*_*ani 42 android view aspect-ratio viewgroup

我如何实现固定的宽高比View?我想要一个宽高比为1:1的物品GridView.我认为将孩子分类比把它分类更好GridView

编辑:我认为这需要以编程方式完成,这没问题.另外,我不想限制大小,只限制宽高比.

Tal*_*alL 76

我实现了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));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Init方法应该以小写字母开头.Java惯例. (30认同)
  • 将其粘贴到res/values/attrs.xml中:`<declare-styleable name ="FixedAspectRatioFrameLayout"> <attr name ="aspectRatioWidth"format ="integer"/> <attr name ="aspectRatioHeight"format ="integer"/ > </ declare-styleable>` (7认同)
  • @Oliv:是的,我最终做了一些事情:https://github.com/commonsguy/cwac-layouts (4认同)
  • @CommonsWare将`FixedAspectRatioFrameLayout`放在`RelativeLayout`中,并将`android:layout_centerInParent ="true"`添加到`FixedAspectRatioFrameLayout`中 (2认同)

Sha*_*hiM 38

对于新用户,这是一个更好的非代码解决方案:

Android SDK v22中 提供了一个名为Percent Support Library的新支持库(MinAPI是7我认为,不确定):

src:android-developers.blogspot.in

百分比支持库提供基于百分比的维度和边距,以及此版本的新功能,可以通过app:aspectRatio设置自定义宽高比.通过仅设置单个宽度或高度并使用aspectRatio,PercentFrameLayout或PercentRelativeLayout将自动调整其他维度,以便布局使用设置的宽高比.

要包含将此添加到build.gradle:

compile 'com.android.support:percent:23.1.1'
Run Code Online (Sandbox Code Playgroud)

现在换了你的观点(即需要是方形的)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>
Run Code Online (Sandbox Code Playgroud)

你可以在这里看到一个例子.

  • 从26-rc1开始,不推荐使用百分比库来支持`ConstraintLayout` ...这彼此之间没有多大关系. (4认同)

Eug*_*sov 20

为了不使用第三方解决方案并考虑到在26.0.0中不推荐使用PercentFrameLayout和PercentRelativeLayout这一事实,我建议您考虑使用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>
Run Code Online (Sandbox Code Playgroud)

结果你得到这样的东西:

固定比例大小的网格项

  • 谢谢,这就像一个魅力,但是,Android Studio 抱怨“H,1:1”是一个无效的浮点数。如果您设置 app:layout_constraintDimensionRatio="1.0" ,它的工作方式相同,但没有警告。 (2认同)

Jes*_*erB 9

我最近为这个问题做了一个帮助类,并写了一篇关于它博客文章.

代码的内容如下:

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

    }
}
Run Code Online (Sandbox Code Playgroud)


Rit*_*kya 5

我使用TalL的答案创建了一个布局库。随意使用它。

比例布局

安装

将此添加到文件的顶部

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


dependencies {
    compile 'com.ritesh:ratiolayout:1.0.0'
}
Run Code Online (Sandbox Code Playgroud)

用法

在布局中的根视图上定义“app”命名空间

xmlns:app="http://schemas.android.com/apk/res-auto"
Run Code Online (Sandbox Code Playgroud)

在您的布局中包含此库

<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">
Run Code Online (Sandbox Code Playgroud)

更新

随着ConstraintLayout 的引入,您不必编写一行代码或使用第三方或依赖PercentFrameLayout于 26.0.0 中已弃用的第三方。

以下是如何使用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>
Run Code Online (Sandbox Code Playgroud)