是一个动态宽度的正方形?

我有一个 GridView,里面有图像视图。我每排有三个。我可以使用 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));

我在适配器里做。

54996 次浏览

The best option is to subclass ImageView yourself, overriding the 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);
}


...


}

The other answer works fine. This is just an extension of bertucci's solution to make an ImageView with square width and height with respect to xml inflated layout.

Create a class, say a SquareImageView extending ImageView like this,

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


}

Now, in your xml do this,

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

If you need an ImageView not to be dynamically created in program, instead, to be fixed in xml, then this implementation will be helpful.

Even more simple:

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

Several of the previous answers are perfectly sufficient. I'm just adding a small optimization to both @Andro Selva and @a.bertucci's solutions here:

It's a tiny optimization, but checking that the width and the height are different could prevent another measurement pass.

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


}

Here all are unnecessary calling its superclass for onMeasure. Here is my implementation

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

For those looking for a Kotlin solution:

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

if someone wants the view to be not square, but proportionally resized in height (for example, 16/9 or 1/3), you can do it like this:

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

An squareImageView by specified width:

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


...
}

An squareImageView by specified height:

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


...
}

An squareImageView by minimum of dimentions:

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


...
}

Single line solution -

layout.setMinimumHeight(layout.getWidth());

Fast solution for Kotlin (Material.ShapeableImageView can be changed to 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)
}
}