[英]Android: How to stretch an image to the screen width while maintaining aspect ratio?
我想下載一個圖像(大小未知,但始終大致為正方形)並顯示它,使其水平填充屏幕,並在任何屏幕尺寸上垂直拉伸以保持圖像的縱橫比。 這是我的(非工作)代碼。 它水平拉伸圖像,而不是垂直拉伸,所以它被壓扁了......
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));
我使用自定義視圖完成了此操作。 設置 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);
}
}
最后,我手動生成了尺寸,效果很好:
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));
我剛剛閱讀了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
和w
是圖像的尺寸, 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 注意到或修復它好運。 編輯:吃我自己的話,我提交了一個錯誤報告,他們說它已在未來的版本中修復!
這是另一種子類化的解決方法,但您應該(理論上,我還沒有真正測試過它!)能夠在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);
}
}
}
將 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);
我一直在以一種或另一種形式為這個問題苦苦掙扎 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);
}
}
}
在某些情況下,這個神奇的公式可以很好地解決問題。
對於來自另一個平台的任何人來說, “適合的大小和形狀”選項在 Android 中處理得很好,但很難找到。
您通常需要這種組合:
然后它是自動的和驚人的。
如果您是 iOS 開發人員,那么在 Android 中,您可以在表格視圖中實現“完全動態的單元格高度”,這真是太神奇了……呃,我的意思是 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"/>
我僅使用此 XML 代碼就設法實現了這一點。 可能是 Eclipse 沒有渲染高度以顯示它擴展以適應; 但是,當您在設備上實際運行它時,它會正確呈現並提供所需的結果。 (至少對我來說)
<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>
每個人都在以編程方式執行此操作,所以我認為這個答案非常適合這里。 這段代碼在 xml 中對我有用。 我還沒有考慮比率,但如果它對任何人有幫助,仍然想放置這個答案。
android:adjustViewBounds="true"
干杯..
我在 LinearLayout 中使用這些值做到了:
Scale type: fitStart
Layout gravity: fill_horizontal
Layout height: wrap_content
Layout weight: 1
Layout width: fill_parent
一個非常簡單的解決方案是只使用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
設置為填充屏幕,但它必須高於其他布局。 通過這種方式,您可以實現所需的一切。
在 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
您正在將 ScaleType 設置為 ScaleType.FIT_XY。 根據javadocs ,這將拉伸圖像以適應整個區域,必要時更改縱橫比。 這將解釋您所看到的行為。
要獲得您想要的行為... FIT_CENTER、FIT_START 或 FIT_END 很接近,但如果圖像窄於高,則不會開始填充寬度。 你可以看看這些是如何實現的,你應該能夠弄清楚如何根據你的目的進行調整。
看看你的問題有一個更簡單的解決方案:
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);
}
您可以使用我的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);
}
}
}
}
ScaleType.CENTER_CROP 會做你想做的事:拉伸到全寬,並相應地縮放高度。 如果縮放高度超過屏幕限制,圖像將被裁剪。
對我來說 android:scaleType="centerCrop" 沒有解決我的問題。 它實際上更多地擴展了圖像。 所以我嘗試使用 android:scaleType="fitXY" 並且效果很好。
這按照我的要求工作正常
<ImageView android:id="@+id/imgIssue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="fitXY"/>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.