2010-06-07 102 views
118

我想下载一张图片(尺寸未知,但总是大致为正方形),并将其显示为水平填充屏幕,并在任何屏幕尺寸下垂直延伸以保持图像的高宽比。这是我的(非工作)代码。它横向延伸图像,但不是垂直,所以它被压扁...Android:如何在保持宽高比的同时将图像拉伸到屏幕宽度?

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)); 
+0

做所有的Android装置具有完全相同的宽度/高度比γ如果不是,那么根本不可能在保持原始比例的情况下缩放图像以适应整个宽度/高度... – NoozNooz42 2010-06-07 16:09:29

+4

不,我不希望图像填满屏幕,只是为了缩放到屏幕宽度,只要图像的比例正确,不关心图像垂直占用多少屏幕。 – fredley 2010-06-07 16:10:41

+1

类似的问题,很好的答案:http://stackoverflow.com/questions/4677269/how-to-stretch-three-images-across-the-screen-preserving-aspect-ratio – 2011-12-27 20:10:59

回答

131

我用自定义视图实现了这一点。设置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); 
    } 
} 
+0

这是我找到的最优雅灵活的解决方案,做得很好!谢谢! – 2010-11-04 09:50:03

+12

谢谢!这应该是正确的答案! :)我调整了这个在这篇文章更灵活一点:http://stackoverflow.com/questions/4677269/how-to-stretch-three-images-across-the-screen-preserving-aspect-ratio那里我使用一个ImageView,所以可以在XML中设置drawable,或者像代码中的普通ImageView一样使用它来设置图像。很棒! – 2011-01-14 05:51:20

+1

Freakin天才!那就像冠军一样工作!感谢它解决了我的问题,横跨顶部的图像横幅并非所有屏幕尺寸都正确!非常感谢! – JPM 2011-04-13 18:07:31

1

您正在将ScaleType设置为ScaleType.FIT_XY。根据javadocs,这将拉伸图像以适应整个区域,如有必要则更改纵横比。这将解释你所看到的行为。

要获得您想要的行为... FIT_CENTER,FIT_START或FIT_END接近,但如果图像比较窄,则不会开始填充宽度。你可以看看这些是如何实现的,你应该能够弄清楚如何根据你的目的进行调整。

+2

我曾尝试FIT_CENTER,但不是其他人。不幸的是,它们也不工作,都将setAdjustViewBounds设置为true和false。无论如何要获取设备屏幕的像素宽度,以及下载图像的宽度/高度并手动设置大小? – fredley 2010-06-08 10:42:08

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)); 
+0

我一直在寻找这种解决方案来解决我的问题。借助这一计算,我成功地加载了图像而不降低宽高比。 – Steve 2016-10-13 10:29:16

1

ScaleType .CENTER_CROP会做你想做的事:伸展到全宽,并相应地缩放高度。如果缩放的高度超出屏幕限制,则图像将被裁剪。

17

将adjustViewBounds设置为true并使用LinearLayout视图组对我工作得非常好。无需继承或询问设备的指标:一个的LinearLayout内

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

它工作。谢谢。 – 2012-03-04 03:40:52

+1

...或使用ImageView XML属性 - android:adjustViewBounds =“true” – 2015-03-03 12:05:36

+0

完美!这非常简单,它使图像更加完美。方式是这个答案不正确吗? CustomView的答案不适用于我(一些奇怪的xml错误) – user3800924 2016-03-24 19:31:32

5

我做到了这些值:

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

您能举一个真实的例子吗?我在哪里可以将这些值放在我的xml文件中? – 2014-07-02 13:23:40

13

我一直在这个问题在这种或那种形式挣扎了好半天,谢谢,谢谢,谢谢.... :)

我只是想指出,你可以得到一个普遍的解决方案,从鲍勃李的只是扩展视图和重写onMeasure完成。这样,你可以用任何你想要的绘制利用这一点,它不会打破,如果没有图像:

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-03-29 10:40:00

+0

这是纯粹的迷人 - 现在一直在努力解决这个问题,所有使用xml属性的明显解决方案都无法工作。有了这个,我可以用扩展视图替换我的ImageView,并且一切按预期工作! – slott 2013-04-05 06:56:14

+0

这绝对是解决此问题的最佳解决方案。 – erlando 2013-10-24 13:57:14

20

我刚才读了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); 

hw是图像的尺寸,并p*是填充。

然后:

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,或者换句话说,最大宽度等于图像宽度。

这意味着,,除非你设置一个确切的大小,图像从来没有放大。我认为这是一个错误,但让Google注意或修复它会带来好运。 编辑:吃我自己的话,我提交了a bug report,他们说它已经在未来的版本中修复!

另一种解决方案

这里是另一个子类解决办法,但你应该(理论上,我还没有真正测试过了!),可以在任何地方你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); 
     } 
    } 
} 
+0

我提交了[错误报告](http://code.google.com/p/android/issues/detail?id=38056)。注意,因为它被忽略! – Timmmm 2012-10-01 15:01:46

+3

显然我必须吃我的话 - 他们说它已被修复在未来的版本! – Timmmm 2012-10-02 10:53:55

+0

非常感谢Tim。这应该是最后一个正确答案。我搜索了很多时间,没有什么比您的解决方案更好。 – tainy 2015-01-23 08:09:43

3

一个非常简单的解决方案就是使用RelativeLayout提供的功能。

这里是一个能够与标准Android Views的XML:

<?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填补了屏幕,但它必须是其他布局上面。这样你就可以实现你需要的一切。

0

对于我android:scaleType =“centerCrop”没有解决我的问题。它实际上扩大了图像的方式。所以我尝试使用android:scaleType =“fitXY”,它工作得很好。

5

我已经设法使用这个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> 
+0

抱歉,这不起作用。它缩放宽度,但centerCrop不保持宽高比。 – ricosrealm 2014-04-14 03:13:34

+0

完美 - 谢谢 – formica 2015-10-14 23:57:57

+1

经过许多小时与扩展ImageView的自定义类(如许多答案和文章中所写)并且出现“无法找到以下类”之类的异常之后,我删除了该代码。突然间,我注意到我的ImageView中有一个问题是背景属性!将其更改为'src'并且ImageView成比例。 – CoolMind 2016-07-12 19:45:24

10

在某些情况下,这个神奇的公式很好地解决了这个问题。

对于任何与此相关的人员来自另一个平台,“尺寸和形状适合”选项在Android中处理得很漂亮,但很难找到。

你通常希望该组合:

  • 宽度匹配父,
  • 高度涡卷内容,
  • adjustViewBounds接通(原文如此)
  • 规模fitCenter
  • cropToPadding OFF(原文如此)

然后它是自动和惊人的。

如果你是一位iOS开发人员,那真是太神奇了,你可以在表格视图中完成“完全动态的单元格高度”。err,我的意思是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"/> 

enter image description here

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

这工作正常按我的要求

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

5

每个人都在这样做程序化,所以我认为这个答案会fi在这里完美无缺。这段代码适用于我的XML。我没有考虑比例,但仍然希望能够提出这个答案,如果它能帮助任何人。

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

可以取决于可拉伸宽度和高度用我StretchableImageView保持纵横比(由宽度或通过高度)在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

2

及其简单的事情:

android:adjustViewBounds="true" 

干杯..

相关问题