【问题标题】:Android ImageView - 16:9Android ImageView - 16:9
【发布时间】:2016-11-08 19:07:46
【问题描述】:

我需要将 Bitmap 设置为 ImageView 以保持 16:9 的比例。你有什么建议吗?主要的解决方案可能是在自定义 ImageView 的覆盖方法 onMeasure 但如何?

【问题讨论】:

    标签: android bitmap android-imageview aspect-ratio


    【解决方案1】:

    由于 PercentFrameLayoutPercentRelativeLayout 在 API 级别 26.0.0 中已被弃用,我建议您考虑使用 ConstraintLayout 以保持您的 ImageView 的比率为 16:9。 ConstraintLayout 是为 Android 平台构建响应式 UI 的强大工具,您可以在此处找到更多详细信息 Build a Responsive UI with ConstraintLayout

    以下是如何将 ImageView 构建到 ConstraintLayout 以保持 16:9 比例的示例:

    <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="match_parent">
    
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginEnd="0dp"
            android:layout_marginStart="0dp"
            android:layout_marginTop="0dp"
            app:srcCompat="@mipmap/ic_launcher"
            app:layout_constraintDimensionRatio="H,16:9"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
    

    不要忘记将 constraint-layout 依赖项添加到模块的 build.gradle 文件中

    implementation "com.android.support.constraint:constraint-layout:1.0.2"
    

    或者直接在布局编辑器中编辑您的布局,而不是编辑您的 XML 文件:

    【讨论】:

      【解决方案2】:

      EDIT 01/03/2019: 经过这么长时间,我强烈推荐使用@Eugene Brusov 下面介绍的ConstraintLayout。我个人永远不会通过覆盖 onMeasure 来使用我的图像视图。

      编辑 2018 年 3 月 29 日:我下面的答案可能很简单,但可能过于原始的答案。如果您想利用 Google 的 ConstraintLayout 已经提供的内容,请关注 this answer 或向下滚动并查看 @Eugene Brusov 的答案。

      旧答案:

      public class CustomImageView extends ImageView {
      
          // some other necessary things
      
          @Override 
          protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
              super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      
              int width = getMeasuredWidth();
      
              //force a 16:9 aspect ratio             
              int height = Math.round(width * .5625f);
              setMeasuredDimension(width, height);
          }
      }
      

      然后在你的xml中

      <path.to.package.CustomImageView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:src="@drawable/img"/>
      

      【讨论】:

        【解决方案3】:

        上面的答案对我不起作用,我发现了这个并且起作用了:

        public class AspectRatioImageView extends ImageView {
          // NOTE: These must be kept in sync with the AspectRatioImageView attributes in attrs.xml.
          public static final int MEASUREMENT_WIDTH = 0;
          public static final int MEASUREMENT_HEIGHT = 1;
        
          private static final float DEFAULT_ASPECT_RATIO = 1f;
          private static final boolean DEFAULT_ASPECT_RATIO_ENABLED = false;
          private static final int DEFAULT_DOMINANT_MEASUREMENT = MEASUREMENT_WIDTH;
        
          private float aspectRatio;
          private boolean aspectRatioEnabled;
          private int dominantMeasurement;
        
          public AspectRatioImageView(Context context) {
            this(context, null);
          }
        
          public AspectRatioImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
        
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AspectRatioImageView);
            aspectRatio = a.getFloat(R.styleable.AspectRatioImageView_aspectRatio, DEFAULT_ASPECT_RATIO);
            aspectRatioEnabled = a.getBoolean(R.styleable.AspectRatioImageView_aspectRatioEnabled,
                DEFAULT_ASPECT_RATIO_ENABLED);
            dominantMeasurement = a.getInt(R.styleable.AspectRatioImageView_dominantMeasurement,
                DEFAULT_DOMINANT_MEASUREMENT);
            a.recycle();
          }
        
          @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (!aspectRatioEnabled) return;
        
            int newWidth;
            int newHeight;
            switch (dominantMeasurement) {
              case MEASUREMENT_WIDTH:
                newWidth = getMeasuredWidth();
                newHeight = (int) (newWidth / aspectRatio);
                break;
        
              case MEASUREMENT_HEIGHT:
                newHeight = getMeasuredHeight();
                newWidth = (int) (newHeight * aspectRatio);
                break;
        
              default:
                throw new IllegalStateException("Unknown measurement with ID " + dominantMeasurement);
            }
        
            setMeasuredDimension(newWidth, newHeight);
          }
        
          /** Get the aspect ratio for this image view. */
          public float getAspectRatio() {
            return aspectRatio;
          }
        
          /** Set the aspect ratio for this image view. This will update the view instantly. */
          public void setAspectRatio(float aspectRatio) {
            this.aspectRatio = aspectRatio;
            if (aspectRatioEnabled) {
              requestLayout();
            }
          }
        
          /** Get whether or not forcing the aspect ratio is enabled. */
          public boolean getAspectRatioEnabled() {
            return aspectRatioEnabled;
          }
        
          /** set whether or not forcing the aspect ratio is enabled. This will re-layout the view. */
          public void setAspectRatioEnabled(boolean aspectRatioEnabled) {
            this.aspectRatioEnabled = aspectRatioEnabled;
            requestLayout();
          }
        
          /** Get the dominant measurement for the aspect ratio. */
          public int getDominantMeasurement() {
            return dominantMeasurement;
          }
        
          /**
           * Set the dominant measurement for the aspect ratio.
           *
           * @see #MEASUREMENT_WIDTH
           * @see #MEASUREMENT_HEIGHT
           */
          public void setDominantMeasurement(int dominantMeasurement) {
            if (dominantMeasurement != MEASUREMENT_HEIGHT && dominantMeasurement != MEASUREMENT_WIDTH) {
              throw new IllegalArgumentException("Invalid measurement type.");
            }
            this.dominantMeasurement = dominantMeasurement;
            requestLayout();
          }
        }
        

        注意:一个符号 * 更改为 / (阅读源代码中的 cmets) 这在你的/values/attrs.xml

        <?xml version="1.0" encoding="utf-8"?>
        <resources>
            <declare-styleable name="AspectRatioImageView">
                <attr name="aspectRatio" format="float" />
                <attr name="aspectRatioEnabled" format="boolean" />
                <attr name="dominantMeasurement">
                    <enum name="width" value="0" />
                    <enum name="height" value="1" />
                </attr>
            </declare-styleable>
        </resources>
        

        那么你可以在你的布局中使用这种方式(aspectRatio = width/height):

        <com.yourpackage.ui.classes.AspectRatioImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="centerCrop"
                app:aspectRatio="1.78"
                app:aspectRatioEnabled="true"
                app:dominantMeasurement="width" />
        

        Source

        【讨论】:

        • 非常感谢,未来自定义视图的好例子
        【解决方案4】:

        编辑:Google 从 API 26 开始正式弃用 Percent 支持库,您应该尽快远离它。

        将大小设置为比率 如果至少有一个视图尺寸设置为“匹配约束”(0dp),您可以将视图尺寸设置为 16:9 等比例。要启用该比率,请单击 Toggle Aspect Ratio Constraint(图 10 中的标注 1),然后在出现的输入中输入宽高比。

        如果宽度和高度都设置为匹配约束,您可以单击切换纵横比约束以选择哪个尺寸基于另一个的比率。视图检查器通过用实线连接相应的边来指示设置为比率。

        例如,如果您将两边都设置为“匹配约束”,请单击两次切换纵横比约束以将宽度设置为高度的比率。现在整个大小由视图的高度决定(可以以任何方式定义),如下图所示:

        更多信息在这里:https://developer.android.com/training/constraint-layout/index.html#adjust-the-view-size


        支持库中有一个名为 PercentFrameLayoutPercentRelativeLayout 的东西。

        <android.support.percent.PercentFrameLayout 
          android:layout_width="match_parent"
          android:layout_height="wrap_content">
          <ImageView
            app:layout_widthPercent="100%"
            app:layout_aspectRatio="178%"
            android:scaleType="centerCrop"
            android:src="@drawable/header_background"/>
          <!-- The rest of your layout -->
        </android.support.percent.PercentRelativeLayout>
        

        如果您仔细查看上面的布局,您会发现有问题的 ImageView(需要固定在 16:9)被包裹在 PercentFrameLayout 周围,并且在ImageView 你可能没见过:

        app:layout_widthPercent="100%"
        app:layout_aspectRatio="178%"
        

        因此 (1) 您需要将其中一个维度(宽度或高度)定义为我们所讨论的ImageView前导 维度。在这种情况下,ImageView 将垂直扩展至其最大宽度(如android:layout_width="match_parent") 并且(2)您需要以百分比设置纵横比(因此是库的名称),在这种情况下为 178%(16/9 = 1.77777777778 或更多,简单地说是 1.78:1 或 178%)。

        阅读有关百分比支持库的更多信息here

        【讨论】:

          猜你喜欢
          • 2018-03-17
          • 1970-01-01
          • 2015-08-06
          • 1970-01-01
          • 2017-07-30
          • 1970-01-01
          • 2020-04-01
          • 2018-03-06
          • 1970-01-01
          相关资源
          最近更新 更多