2010-06-07 98 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" 

乾杯..

相關問題