144 votes

Android : Mettre à l'échelle un Drawable ou une image de fond ?

Sur une mise en page, je souhaite mettre à l'échelle l'image d'arrière-plan (en conservant son rapport d'aspect) pour qu'elle corresponde à l'espace alloué lors de la création de la page. Quelqu'un a-t-il une idée de la manière de procéder ?

J'utilise layout.setBackgroundDrawable() et un BitmapDrawable() pour fixer gravity pour le découpage et le remplissage, mais je ne vois aucune option pour la mise à l'échelle.

5voto

maddob Points 300

Lorsque vous définissez le Drawable d'un ImageView à l'aide de la fonction setBackgroundDrawable l'image sera toujours mise à l'échelle. Les paramètres sont adjustViewBounds ou différent ScaleTypes seront simplement ignorés. La seule solution que j'ai trouvée pour conserver le rapport d'aspect est de redimensionner l'image. ImageView après le chargement de votre objet. Voici l'extrait de code que j'ai utilisé :

// bmp is your Bitmap object
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
int containerHeight = imageView.getHeight();
int containerWidth = imageView.getWidth();
boolean ch2cw = containerHeight > containerWidth;
float h2w = (float) imgHeight / (float) imgWidth;
float newContainerHeight, newContainerWidth;

if (h2w > 1) {
    // height is greater than width
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth * h2w;
    } else {
        newContainerHeight = (float) containerHeight;
        newContainerWidth = newContainerHeight / h2w;
    }
} else {
    // width is greater than height
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth / h2w; 
    } else {
        newContainerWidth = (float) containerHeight;
        newContainerHeight = newContainerWidth * h2w;       
    }
}
Bitmap copy = Bitmap.createScaledBitmap(bmp, (int) newContainerWidth, (int) newContainerHeight, false);
imageView.setBackgroundDrawable(new BitmapDrawable(copy));
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageView.setLayoutParams(params);
imageView.setMaxHeight((int) newContainerHeight);
imageView.setMaxWidth((int) newContainerWidth);

Dans l'extrait de code ci-dessus, on trouve bmp l'objet Bitmap qui doit être affiché et imageView est le ImageView objet

Il est important de noter que les paramètres de mise en page ont été modifiés. . Ceci est nécessaire car setMaxHeight y setMaxWidth ne fera de différence que si la largeur et la hauteur sont définies pour envelopper le contenu, et non pour remplir le parent. Remplir le parent, d'autre part, est le paramètre souhaité au début, car sinon containerWidth y containerHeight auront tous deux une valeur égale à 0. Ainsi, dans votre fichier de mise en page, vous aurez quelque chose comme ceci pour votre ImageView :

...
<ImageView android:id="@+id/my_image_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
...

4voto

Malachiasz Points 1537

Ce n'est pas la solution la plus performante, mais comme quelqu'un l'a suggéré, au lieu d'un arrière-plan, vous pouvez créer un FrameLayout ou un RelativeLayout et utiliser ImageView comme pseudo-arrière-plan - les autres éléments seront positionnés simplement au-dessus :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <ImageView
        android:id="@+id/ivBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:scaleType="fitStart"
        android:src="@drawable/menu_icon_exit" />

    <Button
        android:id="@+id/bSomeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="61dp"
        android:layout_marginTop="122dp"
        android:text="Button" />

</RelativeLayout>

Le problème avec ImageView est que les seuls scaleTypes disponibles sont : CENTER, CENTER_CROP, CENTER_INSIDE, FIT_CENTER,FIT_END, FIT_START, FIT_XY, MATRIX ( http://etcodehome.blogspot.de/2011/05/Android-imageview-scaletype-samples.html )

et pour "mettre à l'échelle l'image d'arrière-plan (en conservant son rapport d'aspect)" dans certains cas, lorsque vous voulez qu'une image remplisse tout l'écran (par exemple l'image d'arrière-plan) et que le rapport d'aspect de l'écran est différent de celui de l'image, le type d'échelle nécessaire est en quelque sorte TOP_CROP, car.. :

CENTER_CROP centre l'image mise à l'échelle au lieu d'aligner le bord supérieur sur le bord supérieur de la vue de l'image et FIT_START s'adapte à la hauteur de l'écran et ne remplit pas la largeur. Et comme l'utilisateur Anke l'a remarqué, FIT_XY ne conserve pas le rapport d'aspect.

Heureusement, quelqu'un a étendu ImageView pour supporter TOP_CROP.

public class ImageViewScaleTypeTopCrop extends ImageView {
    public ImageViewScaleTypeTopCrop(Context context) {
        super(context);
        setup();
    }

    public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs) {
        super(context, attrs);
        setup();
    }

    public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setup();
    }

    private void setup() {
        setScaleType(ScaleType.MATRIX);
    }

    @Override
    protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) {

        float frameWidth = frameRight - frameLeft;
        float frameHeight = frameBottom - frameTop;

        if (getDrawable() != null) {

            Matrix matrix = getImageMatrix();
            float scaleFactor, scaleFactorWidth, scaleFactorHeight;

            scaleFactorWidth = (float) frameWidth / (float) getDrawable().getIntrinsicWidth();
            scaleFactorHeight = (float) frameHeight / (float) getDrawable().getIntrinsicHeight();

            if (scaleFactorHeight > scaleFactorWidth) {
                scaleFactor = scaleFactorHeight;
            } else {
                scaleFactor = scaleFactorWidth;
            }

            matrix.setScale(scaleFactor, scaleFactor, 0, 0);
            setImageMatrix(matrix);
        }

        return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
    }

}

https://stackoverflow.com/a/14815588/2075875

Maintenant, IMHO serait parfait si quelqu'un a écrit un Drawable personnalisé qui met l'image à l'échelle comme ça. Il pourrait alors être utilisé comme paramètre d'arrière-plan.


Reflog suggère de mettre à l'échelle le dessinable avant de l'utiliser. Voici les instructions pour le faire : Java (Android) : Comment mettre à l'échelle un drawable sans Bitmap ? Bien qu'elle présente l'inconvénient de nécessiter plus de mémoire vive (RAM) pour la mise à l'échelle d'un dessin ou d'un bitmap, la mise à l'échelle à la volée utilisée par ImageView ne nécessite pas plus de mémoire. L'avantage pourrait être de réduire la charge du processeur.

4voto

Naresh Sharma Points 1766

Le code ci-dessous rend l'image bitmap parfaitement avec la même taille que l'imageview. Obtenez la hauteur et la largeur de l'image bitmap et calculez ensuite la nouvelle hauteur et largeur à l'aide des paramètres de l'imageview. Cela vous donne l'image requise avec le meilleur rapport d'aspect.

int bwidth=bitMap1.getWidth();
int bheight=bitMap1.getHeight();
int swidth=imageView_location.getWidth();
int sheight=imageView_location.getHeight();
new_width=swidth;
new_height = (int) Math.floor((double) bheight *( (double) new_width / (double) bwidth));
Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap1,new_width,new_height, true);
imageView_location.setImageBitmap(newbitMap)

2voto

Yar Points 2233

Ce que Dweebo a proposé fonctionne. Mais à mon humble avis, c'est inutile. Une image d'arrière-plan s'adapte bien par elle-même. La vue devrait avoir une largeur et une hauteur fixes, comme dans l'exemple suivant :

 < RelativeLayout 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/black">

    <LinearLayout
        android:layout_width="500dip"
        android:layout_height="450dip"
        android:layout_centerInParent="true"
        android:background="@drawable/my_drawable"
        android:orientation="vertical"
        android:padding="30dip"
        >
        ...
     </LinearLayout>
 < / RelativeLayout>

1voto

Sababado Points 1174

Une option à essayer est de mettre l'image dans le fichier drawable-nodpi et définir l'arrière-plan d'une mise en page avec l'identifiant de la ressource à dessiner.

Cela fonctionne sans aucun doute avec une réduction d'échelle, mais je n'ai pas testé avec une augmentation d'échelle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X