Android : 가로 세로 비율을 유지하면서 이미지를 화면 너비로 늘리는 방법은 무엇입니까?


118

이미지 (크기는 알 수 없지만 항상 대략 정사각형)를 다운로드하여 화면을 가로로 채우고 모든 화면 크기에서 이미지의 가로 세로 비율을 유지하기 위해 세로로 늘어나도록 표시하고 싶습니다. 다음은 내 (작동하지 않는) 코드입니다. 이미지를 가로로 늘리지 만 세로로는 늘이지 않기 때문에 스쿼시됩니다.

ImageView mainImageView = new ImageView(context);
    mainImageView.setImageBitmap(mainImage); //downloaded from server
    mainImageView.setScaleType(ScaleType.FIT_XY);
    //mainImageView.setAdjustViewBounds(true); 
    //with this line enabled, just scales image down
    addView(mainImageView,new LinearLayout.LayoutParams( 
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

모든 Android 기기의 너비 / 높이 비율이 정확히 동일합니까? 그렇지 않은 경우는 원래의 비율을 유지하면서 ... 전체 너비 / 높이에 맞게 이미지 크기를 조절하기 위해 단순히 불가능하다
NoozNooz42

4
아니요, 저는 이미지가 화면을 채우는 것을 원하지 않습니다. 화면 너비에 맞게 크기를 조정하기 위해 이미지가 올바른 비율이면 이미지가 수직으로 차지하는 화면의 양은 신경 쓰지 않습니다.
fredley 2010-06-07

1
비슷한 질문에 좋은 답변 : stackoverflow.com/questions/4677269/...
Pēteris Caune

1
'adjustViewBounds'가 작동하지 않습니까?
Darpan 2015-06-17

답변:


132

사용자 지정보기로이를 수행했습니다. layout_width = "fill_parent"및 layout_height = "wrap_content"를 설정하고 적절한 드로어 블을 가리 킵니다.

public class Banner extends View {

  private final Drawable logo;

  public Banner(Context context) {
    super(context);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs) {
    super(context, attrs);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  @Override protected void onMeasure(int widthMeasureSpec,
      int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = width * logo.getIntrinsicHeight() / logo.getIntrinsicWidth();
    setMeasuredDimension(width, height);
  }
}

12
감사합니다!! 정답이되어야합니다! :)이 게시물에서 좀 더 유연하게 조정했습니다. stackoverflow.com/questions/4677269/… 거기에서 ImageView를 사용하여 XML에서 드로어 블을 설정하거나 코드에서 일반 ImageView와 같이 사용하여 이미지를 설정할 수 있습니다. 잘 작동합니다!
Patrick Boos 2011 년

1
이상한 천재! 그것은 챔피언처럼 작동했습니다! 감사합니다. 모든 화면 크기가 아닌 상단에 이미지 배너로 문제를 해결했습니다! 정말 고맙습니다!
JPM 2011

1
로고가 null인지 확인하십시오 (인터넷에서 콘텐츠를 다운로드하는 경우). 그렇지 않으면 훌륭하게 작동합니다. XML 스 니펫에 대한 Patrick의 게시물을 따르십시오.
Artem Russakovskii 2011

44
iOS와 Windows Phone에서 사소한 일을 Android에서 수행하는 것이 얼마나 어려운지 믿을 수 없습니다.
mxcl

1
나는 약간의 변경을가했지만 다른 곳에 게시하는 대신이 답변을 커뮤니티 위키로 바꿀 수 있습니까? 내 변경 사항은 여기에 언급 된 특수한 경우를 처리하는 모든 것뿐 아니라 레이아웃 정의를 통해 크기를 조정할 측면을 선택할 수있는 기능입니다.
Steve Pomeroy 2012

24

결국, 저는 수동으로 치수를 생성했습니다.

DisplayMetrics dm = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = width * mainImage.getHeight() / mainImage.getWidth(); //mainImage is the Bitmap I'm drawing
addView(mainImageView,new LinearLayout.LayoutParams( 
        width, height));

문제를 해결하기 위해 이런 종류의 솔루션을 찾고 있었는데이 계산의 도움으로 가로 세로 비율을 줄이지 않고 이미지를 성공적으로로드했습니다.
Steve

21

방금 소스 코드를 읽었 ImageView으며이 스레드에서 서브 클래 싱 솔루션을 사용하지 않고는 기본적으로 불가능합니다. 에서 ImageView.onMeasure우리는이 라인에 도착 :

        // Get the max possible width given our constraints
        widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);

        // Get the max possible height given our constraints
        heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);

이미지의 크기는 어디 h이며 패딩입니다.wp*

그리고:

private int resolveAdjustedSize(int desiredSize, int maxSize,
                               int measureSpec) {
    ...
    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            /* Parent says we can be as big as we want. Just don't be larger
               than max size imposed on ourselves.
            */
            result = Math.min(desiredSize, maxSize);

따라서 layout_height="wrap_content"를 설정 widthSize = w + pleft + pright하면 최대 너비가 이미지 너비와 같습니다.

, 정확한 크기를 설정하지 않으면 이미지가 확대되지 않습니다 . 나는 이것이 버그라고 생각하지만, 구글이이를 알리거나 고칠 수 있기를 바랍니다. 편집 : 내 말을 먹고 버그 보고서를 제출 했으며 향후 릴리스에서 수정되었다고합니다!

또 다른 해결책

여기에 또 다른 서브 클래스 해결 방법이지만, 당신이 해야한다 (이론, 정말 많이 테스트하지 않았습니다!) 어디서나 그것을 사용할 수 있습니다 ImageView. 그것을 사용하려면 layout_width="match_parent", 및 layout_height="wrap_content". 허용되는 솔루션보다 훨씬 더 일반적입니다. 예를 들어 너비에 맞추는 것뿐만 아니라 높이에 맞추기를 할 수 있습니다.

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

// This works around the issue described here: http://stackoverflow.com/a/12675430/265521
public class StretchyImageView extends ImageView
{

    public StretchyImageView(Context context)
    {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // Call super() so that resolveUri() is called.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // If there's no drawable we can just use the result from super.
        if (getDrawable() == null)
            return;

        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int w = getDrawable().getIntrinsicWidth();
        int h = getDrawable().getIntrinsicHeight();
        if (w <= 0)
            w = 1;
        if (h <= 0)
            h = 1;

        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = (float) w / (float) h;

        // We are allowed to change the view's width
        boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;

        // We are allowed to change the view's height
        boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

        int pleft = getPaddingLeft();
        int pright = getPaddingRight();
        int ptop = getPaddingTop();
        int pbottom = getPaddingBottom();

        // Get the sizes that ImageView decided on.
        int widthSize = getMeasuredWidth();
        int heightSize = getMeasuredHeight();

        if (resizeWidth && !resizeHeight)
        {
            // Resize the width to the height, maintaining aspect ratio.
            int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
            setMeasuredDimension(newWidth, heightSize);
        }
        else if (resizeHeight && !resizeWidth)
        {
            int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
            setMeasuredDimension(widthSize, newHeight);
        }
    }
}

버그 보고서를 제출 했습니다 . 무시되므로 조심하십시오!
Timmmm

3
분명히 나는 ​​내 말을 먹어야한다. 그들은 그것이 향후 릴리스에서 수정되었다고 말한다!
Timmmm

Tim 대단히 감사합니다. 이것은 최종 정답이되어야합니다. 나는 많은 시간을 검색했지만 당신의 솔루션보다 더 좋은 것은 없습니다.!
tainy

위의 StretchyImageView를 사용할 때 maxHeight를 설정해야하는 경우 어떻게해야합니까? 나는 그것에 대한 해결책을 찾지 못했습니다.
tainy

17

adjustViewBounds를 true로 설정하고 LinearLayout 뷰 그룹을 사용하는 것이 저에게 매우 효과적이었습니다. 장치 메트릭을 하위 클래스로 분류하거나 요청할 필요가 없습니다.

//NOTE: "this" is a subclass of LinearLayout
ImageView splashImageView = new ImageView(context);
splashImageView.setImageResource(R.drawable.splash);
splashImageView.setAdjustViewBounds(true);
addView(splashImageView);

1
... 또는 이미지 뷰를 XML 속성을 사용하여 - 안드로이드 : adjustViewBounds을 = "true"로
아나톨리 Shuba

완전한! 이것은 너무 쉬웠고 이미지를 완벽하게 늘립니다. 이 답변이 올바른 답변이 아닌가? CustomView에 대한 답변이 저에게 작동하지 않았습니다 (일부 이상한 xml 오류)
user3800924

13

저는 AGES를 위해이 문제를 어떤 형태로든 고심하고 있습니다. 감사합니다. 감사합니다 .... :)

View를 확장하고 onMeasure를 재정의함으로써 Bob Lee가 한 일에서 일반화 가능한 솔루션을 얻을 수 있다는 점을 지적하고 싶었습니다. 그렇게하면 원하는 드로어 블과 함께 사용할 수 있으며 이미지가 없어도 깨지지 않습니다.

    public class CardImageView extends View {
        public CardImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

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

        public CardImageView(Context context) {
            super(context);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Drawable bg = getBackground();
            if (bg != null) {
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * bg.getIntrinsicHeight() / bg.getIntrinsicWidth();
                setMeasuredDimension(width,height);
            }
            else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    }

2
이 문제에 대한 많은, 많은 솔루션 중에서 이것은 드롭 인 솔루션 인 첫 번째 솔루션이며, 다른 솔루션에는 항상 단점이 있습니다 (예 : 코드 재 작성없이 런타임에 이미지를 변경할 수 없음). 감사합니다!
MacD 2013 년

이것은 순수한 굉장함입니다. 지금까지이 문제로 어려움을 겪어 왔으며 xml 속성을 사용하는 모든 명백한 솔루션이 작동하지 않았습니다. 이것으로 내 ImageView를 확장 된 뷰로 대체 할 수 있었고 모든 것이 예상대로 작동했습니다!
slott

이것이이 문제에 대한 절대적으로 최선의 해결책입니다.
erlando

훌륭한 대답입니다. 다음과 같이 걱정없이 xml 파일에서이 클래스를 사용할 수 있습니다. <com.yourpackagename.CardImageView android : layout_width = "fill_parent"android : layout_height = "wrap_content"android : background = "@ drawable / your_photo"/>. 큰!
arniotaki

11

어떤 경우에는이 마법의 공식이 문제를 아름답게 해결합니다.

다른 플랫폼에서이 문제를 해결하는 데 어려움을 겪고있는 사람을 위해 "크기 및 모양에 맞게" 옵션이 Android에서 아름답게 처리되지만 찾기가 어렵습니다.

일반적으로 다음 조합을 원합니다.

  • 너비 일치 부모,
  • 높이 포장 내용,
  • adjustViewBounds 켜짐 (원문)
  • 스케일 fitCenter
  • cropToPadding OFF (원문)

그렇다면 그것은 자동적이고 놀랍습니다.

당신이 iOS 개발자라면, 안드로이드에서 테이블 뷰에서 "완전히 동적 셀 높이"를 할 수 있다는 것은 정말 놀랍습니다. .. 오류, ListView를 의미합니다. 즐겨.

<com.parse.ParseImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/post_image"
    android:src="@drawable/icon_192"
    android:layout_margin="0dp"
    android:cropToPadding="false"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:background="#eff2eb"/>

여기에 이미지 설명 입력


6

이 XML 코드 만 사용하여이를 달성했습니다. 일식이 높이를 렌더링하지 않아서 크기에 맞게 확장되는 경우 일 수 있습니다. 그러나 실제로 장치에서 실행하면 제대로 렌더링되고 원하는 결과를 제공합니다. (적어도 나에게는)

<FrameLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

     <ImageView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:adjustViewBounds="true"
          android:scaleType="centerCrop"
          android:src="@drawable/whatever" />
</FrameLayout>

작동하지 않습니다. 너비를 조정하지만 centerCrop은 종횡비를 유지하지 않습니다.
ricosrealm 2014

1
ImageView를 확장하는 사용자 정의 클래스 (많은 답변과 기사에 작성 됨)로 고생하고 "다음 클래스를 찾을 수 없습니다."와 같은 예외가 발생한 후 해당 코드를 제거했습니다. 갑자기 내 ImageView의 문제가 백그라운드 속성에 있음을 발견했습니다! 로 변경 src하고 ImageView가 비례 해졌습니다.
CoolMind

5

LinearLayout 내에서 다음 값으로 수행했습니다.

Scale type: fitStart
Layout gravity: fill_horizontal
Layout height: wrap_content
Layout weight: 1
Layout width: fill_parent

진짜 예를 들어 주실 수 있나요? 이 값을 내 xml 파일에 어디에 넣습니까?
John Smith 선택적

5

모두가 프로그래밍 방식으로 수행하고 있으므로이 답변이 여기에 완벽하게 맞을 것이라고 생각했습니다. 이 코드는 xml에서 저를 위해 작동했습니다. Im 아직 비율에 대해 생각하지 않았지만 누군가에게 도움이된다면 여전히이 대답을 원했습니다.

android:adjustViewBounds="true"

건배..


3

아주 간단한 해결책은에서 제공하는 기능을 사용하는 것 RelativeLayout입니다.

다음은 표준 Android에서 가능하게하는 xml입니다 Views.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <LinearLayout
            android:id="@+id/button_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_alignParentBottom="true"
            >
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <ImageView 
            android:src="@drawable/cat"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="centerCrop"
            android:layout_above="@id/button_container"/>
    </RelativeLayout>
</ScrollView>

트릭은 ImageView화면을 채우도록를 설정 했지만 다른 레이아웃보다 위에 있어야한다는 것입니다. 이렇게하면 필요한 모든 것을 얻을 수 있습니다.


2

ImageView에 대한 XML 파일 adjustViewBounds="true"과 설정의 간단한 문제 scaleType="fitCenter"!

<ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/image"

        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        />

참고 : layout_width로 설정됩니다.match_parent


1

ScaleType을 ScaleType.FIT_XY로 설정합니다. javadocs 에 따르면 필요한 경우 가로 세로 비율을 변경하여 전체 영역에 맞게 이미지를 늘립니다. 그것은 당신이보고있는 행동을 설명 할 것입니다.

원하는 동작을 얻으려면 ... FIT_CENTER, FIT_START 또는 FIT_END가 가깝지만 이미지가 높이보다 좁 으면 너비를 채우기 시작하지 않습니다. 그러나 그것들이 어떻게 구현되는지 볼 수 있으며, 당신의 목적에 맞게 조정하는 방법을 알아낼 수있을 것입니다.


2
FIT_CENTER를 시도했지만 다른 것은 아닙니다. 불행히도 setAdjustViewBounds가 true와 false로 설정된 경우 둘 다 작동하지 않습니다. 어쨌든 장치 화면의 픽셀 너비와 다운로드 한 이미지의 너비 / 높이를 가져와 수동으로 크기를 설정하는 방법이 있습니까?
fredley 2010-06-08

1

ScaleType.CENTER_CROP은 원하는 것을 수행합니다. 전체 너비로 늘이고 그에 따라 높이를 조정합니다. 조정 된 높이가 화면 제한을 초과하면 이미지가 잘립니다.


1

문제에 대한 훨씬 더 쉬운 해결책이 있습니다.

ImageView imageView;

protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout);
    imageView =(ImageView)findViewById(R.id.your_imageView);
    Bitmap imageBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_image);
    Point screenSize = new Point();
    getWindowManager().getDefaultDisplay().getSize(screenSize);
    Bitmap temp = Bitmap.createBitmap(screenSize.x, screenSize.x, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(temp);
    canvas.drawBitmap(imageBitmap,null, new Rect(0,0,screenSize.x,screenSize.x), null);
    imageView.setImageBitmap(temp);
}

1

드로어 블의 너비와 높이에 따라 가로 세로 비율 (너비 또는 높이 기준)을 유지하면서 내 StretchableImageView 를 사용할 수 있습니다 .

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

public class StretchableImageView extends ImageView{

    public StretchableImageView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(getDrawable()!=null){
            if(getDrawable().getIntrinsicWidth()>=getDrawable().getIntrinsicHeight()){
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * getDrawable().getIntrinsicHeight()
                            / getDrawable().getIntrinsicWidth();
                setMeasuredDimension(width, height);
            }else{
                int height = MeasureSpec.getSize(heightMeasureSpec);
                int width = height * getDrawable().getIntrinsicWidth()
                            / getDrawable().getIntrinsicHeight();
                setMeasuredDimension(width, height);
            }
        }
    }
}

0

나를 위해 android : scaleType = "centerCrop"은 내 문제를 해결하지 못했습니다. 실제로 이미지를 더 확장했습니다. 그래서 android : scaleType = "fitXY"로 시도했고 훌륭하게 작동했습니다.


0

내 요구 사항에 따라 잘 작동합니다.

<ImageView android:id="@+id/imgIssue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="fitXY"/>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.