ImageView ein Quadrat mit dynamischer Breite sein?

73

Ich habe eine GridView mit ImageViews. Ich habe 3 davon für jede Reihe. Ich kann die Breite mit WRAP_CONTENT und scaleType = CENTER_CROP korrekt einstellen, aber ich weiß nicht, wie ich die Größe der ImageView als Quadrat festlegen soll. Hier ist, was ich bis jetzt gemacht habe, es scheint in Ordnung zu sein, außer der Höhe, die "statisch" ist:

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

Ich mache es in einem Adapter.

Andrea
quelle

Antworten:

170

Die beste Option ist, sich ImageViewselbst zu klassifizieren und den Messdurchlauf zu überschreiben:

public class SquareImageView  extends ImageView {

  ...

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

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

  ...

}
a.bertucci
quelle
1
Genial! Vielen Dank, ich habe nicht über diese Möglichkeit
Andrea
Wenn ich den // Auffüllrand einstelle, wird ein weißer Rand angezeigt. Haben Sie eine Idee, wie Sie das beheben können?
Waza_Be
2
android: adjustViewBounds = "true" android: scaleType = "centerCrop" @Waza_Be
JK
2
Sollte es nicht stattdessen als min (Breite, Höhe) eingestellt werden?
Android-Entwickler
1
Es ist eine winzige Optimierung, aber die Überprüfung, ob Breite und Höhe unterschiedlich sind, kann einen weiteren Messdurchgang verhindern. @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure (widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth (); int height = getMeasuredHeight (); // Optimierung, damit wir nicht zweimal messen, es sei denn, wir müssen if (width! = Height) {setMeasuredDimension (width, width); }}
Chantell Osejo
98

Die andere Antwort funktioniert gut. Dies ist nur eine Erweiterung von Bertuccis Lösung, um eine ImageView mit quadratischer Breite und Höhe in Bezug auf das aufgeblasene XML-Layout zu erstellen.

Erstellen Sie eine Klasse, z. B. eine SquareImageView, die ImageView wie folgt erweitert:

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

}

Tun Sie dies jetzt in Ihrer XML-Datei.

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

Wenn Sie eine ImageView benötigen, die nicht dynamisch im Programm erstellt, sondern in XML repariert werden soll, ist diese Implementierung hilfreich.

Andro Selva
quelle
1
Super, danke Andro. Genau das habe ich gesucht. Nochmals vielen Dank, dass Sie sich die Zeit genommen haben, eine vollständige Antwort zu geben.
Taliadon
1
Dies sollte als die richtige, vollständige Lösung markiert werden.
JRod
26

Noch einfacher:

public class SquareImageView extends ImageView {
    ...
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }    
}
mischen
quelle
nicht vergessen für sdk> = 21 @TargetApi (Build.VERSION_CODES.LOLLIPOP) public SquareImageView (Kontextkontext, AttributeSet-Attribute, int defStyleAttr, int defStyleRes) {super (Kontext, Attribute, defStyleAttr, defStyleRes); }
Jan Rabe
11

Einige der vorherigen Antworten sind völlig ausreichend. Ich füge hier nur eine kleine Optimierung zu den Lösungen von @Andro Selva und @ a.bertucci hinzu:

Es ist eine winzige Optimierung, aber die Überprüfung, ob Breite und Höhe unterschiedlich sind, kann einen weiteren Messdurchgang verhindern.

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

}
Chantell Osejo
quelle
3

Für diejenigen, die eine Kotlin-Lösung suchen:

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)
}
Marthijn Bontekoning
quelle
3

Eine squareImageView mit angegebener Breite:

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

     ...
}

Eine squareImageView nach angegebener Höhe:

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

        ...
    }

Eine squareImageView mit einem Minimum an Dimensionen:

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

       ...
    }
Misagh
quelle
Die Verwendung AppCompatImageViewin dieser Antwort ist ein wichtiger Punkt.
Richard Le Mesurier
1

Wenn jemand möchte, dass die Ansicht nicht quadratisch ist, sondern proportional in der Höhe geändert wird (z. B. 16/9 oder 1/3), können Sie dies folgendermaßen tun:

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

Einzeilige Lösung -

layout.setMinimumHeight(layout.getWidth());
HarshitG
quelle
-1

Hier sind alle unnötig, seine Oberklasse zu fordern onMeasure. Hier ist meine Implementierung

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