ImageView 是动态宽度的正方形?

Posted

技术标签:

【中文标题】ImageView 是动态宽度的正方形?【英文标题】:ImageView be a square with dynamic width? 【发布时间】:2013-05-06 13:20:10 【问题描述】:

我有一个 GridView,里面有 ImageViews。我每行有 3 个。我可以使用 WRAP_CONTENT 和 scaleType = CENTER_CROP 正确设置宽度,但我不知道如何将 ImageView 的大小设置为正方形。这是我到目前为止所做的,除了高度之外似乎还可以,即“静态”:

imageView = new ImageView(context);     
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.WRAP_CONTENT, 300));

我在适配器内部进行。

【问题讨论】:

【参考方案1】:

最好的选择是自己继承ImageView,覆盖measure pass:

public class SquareImageView  extends ImageView 

  ...

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

    int width = getMeasuredWidth();
    setMeasuredDimension(width, width);
  

  ...


【讨论】:

太棒了!非常感谢,我没有想过这种可能 如果我设置填充 // 边距,我会得到一个白色边框。知道如何解决这个问题吗? android:adjustViewBounds="true" android:scaleType="centerCrop" @Waza_Be 不应该改为min(width,height)吗? 这是一个微小的优化,但检查宽度和高度是否不同可能会阻止另一次测量通过。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) super.onMeasure(widthMeasureSpec, heightMeasureSpec); int 宽度 = getMeasuredWidth(); int 高度 = getMeasuredHeight(); // 优化所以我们不会测量两次,除非我们需要 if (width != height) setMeasuredDimension(width, width); 【参考方案2】:

另一个答案很好。这只是 bertucci 的解决方案的扩展,以相对于 xml 膨胀布局制作具有正方形宽度和高度的 ImageView。

创建一个类,比如像这样扩展 ImageView 的 SquareImageView,

public class SquareImageView extends ImageView 

    public SquareImageView(Context context) 
        super(context);
    

    public SquareImageView(Context context, AttributeSet attrs) 
        super(context, attrs);
    

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

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

        int width = getMeasuredWidth();
        setMeasuredDimension(width, width);
    


现在,在您的 xml 中执行此操作,

        <com.packagepath.tothis.SquareImageView
            android:id="@+id/Imageview"
            android:layout_
            android:layout_ />

如果你需要一个 ImageView 不在程序中动态创建,而是在 xml 中固定,那么这个实现会很有帮助。

【讨论】:

太棒了,谢谢安德罗。这正是我想要的。再次感谢您花时间提供完整的答案。 这应该被标记为正确的、完整的解决方案。 另请参阅使用此技术的优秀教程:raywenderlich.com/…【参考方案3】:

更简单:

public class SquareImageView extends ImageView 
    ...
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
        

【讨论】:

不要忘记 sdk >= 21 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) super(context, attrs, defStyleAttr, defStyleRes); 【参考方案4】:

前面的几个答案已经足够了。我只是在这里为@Andro Selva 和@a.bertucci 的解决方案添加了一个小优化:

这是一个微小的优化,但检查宽度和高度是否不同可能会阻止另一次测量通过。

public class SquareImageView extends ImageView 

    public SquareImageView(Context context) 
        super(context);
    

    public SquareImageView(Context context, AttributeSet attrs) 
        super(context, attrs);
    

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

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

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        // Optimization so we don't measure twice unless we need to
        if (width != height) 
            setMeasuredDimension(width, width);
        
    


【讨论】:

【参考方案5】:

对于那些寻找 Kotlin 解决方案的人:

class SquareImageView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0
) : ImageView(context, attrs, defStyleAttr, defStyleRes)
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) = super.onMeasure(widthMeasureSpec, widthMeasureSpec)

【讨论】:

【参考方案6】:

指定宽度的squareImageView:

public class SquareImageViewByWidth extends AppCompatImageView 

    public SquareImageViewByWidth(Context context) 
        super(context);
    

    public SquareImageViewByWidth(Context context, AttributeSet attrs) 
        super(context, attrs);
    

    public SquareImageViewByWidth(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
    

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

        int width= getMeasuredWidth();
        setMeasuredDimension(width, width);
    

     ...


指定高度的squareImageView:

    public class SquareImageViewByHeight extends AppCompatImageView 

        public SquareImageViewByHeight(Context context) 
            super(context);
        

        public SquareImageViewByHeight(Context context, AttributeSet attrs) 
            super(context, attrs);
        

        public SquareImageViewByHeight(Context context, AttributeSet attrs, int defStyleAttr) 
            super(context, attrs, defStyleAttr);
        

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

            int height = getMeasuredHeight();
            setMeasuredDimension(height, height);
        

        ...
    

最小尺寸的 squareImageView:

public class SquareImageViewByMin extends AppCompatImageView 

        public SquareImageViewByHeight(Context context) 
            super(context);
        

        public SquareImageViewByHeight(Context context, AttributeSet attrs) 
            super(context, attrs);
        

        public SquareImageViewByHeight(Context context, AttributeSet attrs, int defStyleAttr) 
            super(context, attrs, defStyleAttr);
        

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            int minSize = Math.min(width, height);
            setMeasuredDimension(minSize, minSize);
        

       ...
    

【讨论】:

这个答案中AppCompatImageView的使用很重要。【参考方案7】:

如果有人希望视图不是方形的,而是按比例调整高度(例如,16/9 或 1/3),您可以这样做:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth()/3, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

【讨论】:

【参考方案8】:

单线解决方案-

layout.setMinimumHeight(layout.getWidth());

【讨论】:

【参考方案9】:

Kotlin 的快速解决方案(Material.ShapeableImageView 可以改为 ImageView)

class SquareImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ShapeableImageView(context, attrs, defStyleAttr) 
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(measuredWidth, measuredWidth)
    

【讨论】:

【参考方案10】:

这里都没有必要将其超类称为onMeasure。这是我的实现

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    int size = Math.min(width, height);
    setMeasuredDimension(size, size);

【讨论】:

以上是关于ImageView 是动态宽度的正方形?的主要内容,如果未能解决你的问题,请参考以下文章

自定义 ImageView 为正方形

如何动态设置ImageView的宽度高度以及位置

如何设置playground liveview的宽度?

ImageView 填充父母的宽度或高度,但保持纵横比

如何正确裁剪图像以适合 imageview

宽度等于动态高度正方形[重复]