Масштабирование ImageView по ширине устройства

В моем приложении для Android у меня есть действие, которое показывает изображения следующего размера 244 x 330. Я хочу показать эти изображения во всю ширину устройства.

Мой файл макета выглядит так:

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

    <LinearLayout 
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical">

            <ImageView android:id="@+id/news_image" 
                android:layout_height="fill_parent" 
                android:layout_width="fill_parent"
                android:layout_marginLeft="18dip"
                android:layout_marginRight="18dip"
                android:background="#aaaaaa" />


    </LinearLayout>

</ScrollView>

Я попытался установить ScaleType для ImageView, но нет ScalingType, который пропорционально масштабирует ImageView. Как я могу пропорционально масштабировать изображение, чтобы оно соответствовало всему экрану в ландшафтном режиме И портретном режиме?

В основном то, что я хочу, это что-то вроде ScaleType.CENTER_CORP, но которое также устанавливает пропорциональную высоту для изображения, чтобы я мог видеть все это, а не только часть изображения.

Изменить, потому что я знаю, что сбиваю вас с толку своими "странными" квестами.

Я хочу показать это вам с изображением. Это то, что я получаю на данный момент с моим макетом. Я хочу заполнить всю серую область, масштабируя изображение до необходимого размера. Как я могу это сделать?

Когда я устанавливаю ScaleType в CENTER_CROP, я получаю это

но это не то, что я хочу, потому что вы видите не все изображение, а только часть от центра.

И вот что я хочу, чтобы это было:

Я надеюсь, что это поможет вам понять, чего я пытаюсь достичь. Кто-нибудь знает, как это сделать?

Редактировать 2:

Это может выглядеть странно и немного сбивает с толку, что я пытаюсь отобразить изображение, которое больше по высоте, чем размер экрана, но поскольку я использую ScrollView в своем примерном макете, это должно быть в порядке, и пользователь может прокручивать, если он хочет чтобы увидеть не отображаемую область.

Надеюсь, это поможет понять, что я пытаюсь сделать.


person OemerA    schedule 02.02.2011    source источник


Ответы (9)


Я действительно пробовал каждый ScaleType в моем ImageView с fill_parent и wrap_content, но ни один из них не работал. Я также пробовал все, что нашел в Google, но у меня тоже ничего не получалось, поэтому придумал что-то свое.

Было ясно, что ImageView не масштабирует мое изображение так, как я хотел, поэтому мне пришлось масштабировать его самостоятельно. После масштабирования растрового изображения я бы установил новое растровое изображение в качестве источника изображения для ImageView. Это работает довольно хорошо и очень хорошо выглядит на G1 и Motorola Milestone 2.

А вот и все куски моего кода

Макет:

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

    <LinearLayout 
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/news_wrapper">

            <ImageView android:id="@+id/news_image" 
                android:layout_height="fill_parent"
                android:layout_width="fill_parent"
                android:layout_marginLeft="18dip"
                android:layout_marginRight="18dip"
                android:background="#aaaaaa" />

    </LinearLayout>

</ScrollView>

Мероприятия

public class ScalingImages extends Activity {

    private ImageView imageView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_margin);

        this.imageView = (ImageView)findViewById(R.id.news_image);

        // The image is coming from resource folder but it could also 
        // load from the internet or whatever
        Drawable drawable = getResources().getDrawable(R.drawable.img);
        Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();

        // Get scaling factor to fit the max possible width of the ImageView
        float scalingFactor = this.getBitmapScalingFactor(bitmap);

        // Create a new bitmap with the scaling factor
        Bitmap newBitmap = Util.ScaleBitmap(bitmap, scalingFactor);

        // Set the bitmap as the ImageView source
        this.imageView.setImageBitmap(newBitmap);
    }

    private float getBitmapScalingFactor(Bitmap bm) {
        // Get display width from device
        int displayWidth = getWindowManager().getDefaultDisplay().getWidth();

        // Get margin to use it for calculating to max width of the ImageView
        LinearLayout.LayoutParams layoutParams = 
            (LinearLayout.LayoutParams)this.imageView.getLayoutParams();
        int leftMargin = layoutParams.leftMargin;
        int rightMargin = layoutParams.rightMargin;

        // Calculate the max width of the imageView
        int imageViewWidth = displayWidth - (leftMargin + rightMargin);

        // Calculate scaling factor and return it
        return ( (float) imageViewWidth / (float) bm.getWidth() );
    }
}

Класс полезности

public class Util {

    public static Bitmap ScaleBitmap(Bitmap bm, float scalingFactor) {
        int scaleHeight = (int) (bm.getHeight() * scalingFactor);
        int scaleWidth = (int) (bm.getWidth() * scalingFactor);

        return Bitmap.createScaledBitmap(bm, scaleWidth, scaleHeight, true);
    }

}

Если есть лучший или более точный способ выполнить такое же масштабирование, пожалуйста, дайте мне знать, потому что я не могу поверить, что такую ​​тривиальную вещь так трудно выполнить.

Я действительно надеюсь увидеть лучший способ сделать это.

Спасибо за чтение.

person OemerA    schedule 03.02.2011
comment
Спасибо за обмен. Для этого должен быть коэффициент масштабирования. - person binW; 31.08.2011
comment
Большое спасибо - я не могу поверить, что нет более простого способа сделать это! - person John McCollum; 15.11.2011
comment
Я также потратил кучу времени, пытаясь использовать настройки в xml. Спасибо за публикацию собственного решения. - person ggenglish; 25.04.2013
comment
getWidth() теперь устарела, поэтому вместо этого я использую это... Point size = new Point(); getWindowManager().getDefaultDisplay().getSize(size); int displayWidth = size.x; - person ban-geoengineering; 09.10.2014

самый простой способ - добавить android:adjustViewBounds="true" в ImageView и установить тип шкалы на "fitCenter"

person Marian    schedule 08.05.2014
comment
Простое требование с простым решением - и у меня это сработало. (Это должен быть правильный ответ!) - person ban-geoengineering; 25.07.2014
comment
Это решение идеально - person Pavan Bilagi; 16.09.2016

Немного запутался в том, что именно вы ищете. Если вы масштабируете изображение по размеру экрана, у вас есть три варианта, два из которых являются жизнеспособными, если вы сохраняете пропорции. Вы можете использовать ScaleType fitCenter, который пропорционально уместит изображение в границах, или вы можете использовать centerCrop (который, как вы сказали, пробовали), который растянет самую короткую сторону изображения, чтобы соответствовать контейнеру (это означает, что некоторые из них будут обрезаны). в более длинном измерении). Вы не можете растянуть его, чтобы он соответствовал ширине и высоте без обрезки или непропорционального растяжения.

РЕДАКТИРОВАНИЕ: Хорошо, я думаю, теперь я понял вашу точку зрения. Во-первых, я бы установил для LinearLayout значение wrap_content для высоты. Во-вторых, в коде, вот один способ сделать это, который я могу придумать. Вероятно, есть и другой способ сделать это, сначала получив размеры экрана, затем выполнив createScaledBitmap с новыми размерами, а затем установив фоновый ресурс.

final ImageView newsImage = (ImageView)findViewById(R.id.news_image);

//get details on resolution from the display
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

//going to set what happens as the layout happens
newsImage.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {

        public void onGlobalLayout() {
            int oldHeight, oldWidth, newHeight, newWidth;

            //we want the new width to be as wide as the screen
            newWidth = metrics.widthPixels;

            oldHeight = newsImage.getDrawable().getIntrinsicHeight();
            oldWidth = newsImage.getDrawable().getIntrinsicWidth();

            //keeping the aspect ratio, the new height should be w1/h1 = w2/h2
            newHeight = Math.floor((oldHeight * newWidth) / oldWidth);
            LinearLayout.LayoutParams params = 
                (LinearLayout.LayoutParams)newsImage.getLayoutParams();
            params.height = newHeight;
            params.width = newWidth;
            newsImage.setLayoutParams(params);
            newsImage.setScaleType(ScaleType.CENTER);
            newsImage.invalidate();
            newsImage.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    }
}
person Kevin Coppock    schedule 02.02.2011
comment
Я пробовал, но ScaleType.CENTER_CROPурезал высоту. Можете ли вы предоставить образец? Попробую еще раз (может быть где-то ошибся) и отпишусь о результатах. - person OemerA; 03.02.2011
comment
Вы ДОЛЖНЫ сократить высоту, если хотите, чтобы она соответствовала ширине. Чтобы сделать то, что вы хотите, вы должны использовать тип масштабирования fitXY, но он будет масштабироваться непропорционально. Другого способа сделать это нет. - person Kevin Coppock; 03.02.2011
comment
Но я не хочу подгонять изображение под высоту экрана. Если изображение больше, чем высота дисплея, пользователь может прокручивать изображение, так как в моем примере я использую ScrollView. Я хочу, чтобы ширина соответствовала ширине, но не обрезала высоту и делала ее прокручиваемой, если высота больше высоты дисплея. Какие-либо предложения? - person OemerA; 03.02.2011

Я везде гуглил и не мог найти решение. Вот что я сделал, это сработало для меня и с прокруткой.

XML-файл:

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

    <ImageView
        android:id="@+id/manga_page_image"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter" />
</ScrollView>
person vtlinh    schedule 24.02.2014
comment
Подтвержденный ! Это сработало и для меня, и это намного проще, чем масштабировать изображение с помощью кода. - person chip; 27.08.2014

Программно через ImageView.setScaleType() пробовали ставить?

setAdjustViewBounds( false ) тоже может помочь.

Редактировать: извините, я неправильно прочитал вопрос. Тем не менее, setAdjustViewBounds() все еще может помочь. Хотя никогда им не пользовался.

person Snailer    schedule 02.02.2011
comment
Я только что попробовал setAdjustViewBounds, но это не помогло. Любые другие предложения? Может быть, мое редактирование делает мою цель более понятной. - person OemerA; 03.02.2011

Я хочу показать эти изображения во всю ширину устройства.

Это просто. У вас просто неправильные настройки маржи. Удалите эти строки, и ваше изображение будет отображаться во всю ширину устройства:

android:layout_marginLeft="18dip"
android:layout_marginRight="18dip" 
person user432209    schedule 02.02.2011
comment
Это кажется странным, но на самом деле я хотел бы иметь эти поля, иначе он будет так приклеен к экрану. Разве что те 18 провалов влево и вправо хотелось бы использовать весь размер экрана. - person OemerA; 03.02.2011

Я больше не вижу изображений, и вопрос старый, но на всякий случай, если кто-то еще найдет это и у него будет такая же проблема. Не лучше ли просто получить float screenWidth = getResources().getDisplayMetrics().widthPixels и программно установить ImageView LayoutParamters, чтобы масштабировать изображение до screenWidth. Просто идея!!

person Saad Farooq    schedule 11.01.2012

удалось достичь того, что я хотел, что, надеюсь, совпадает с вашей целью:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.pgviewer);

    ImageView PgContainer = (ImageView)findViewById(R.id.imageView1);

    String Page = String.valueOf(getIntent().getExtras().getInt("Page"));
    try {
        PgContainer.setImageBitmap(getBitmapFromAsset(Page));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    PgContainer.setScaleType(ScaleType.FIT_CENTER);
    PgContainer.scrollTo(0, 0);
    PgContainer.setScrollBarStyle(0);
}

затем масштабировать растровое изображение:

private Bitmap getBitmapFromAsset(String strName) throws IOException
{
    AssetManager assetManager = getAssets();
    InputStream istr = assetManager.open(strName+".png");
    Bitmap bitmap = BitmapFactory.decodeStream(istr);

    float screenWidth = getResources().getDisplayMetrics().widthPixels;
    int ih=bitmap.getHeight();
    int iw=bitmap.getWidth();
    float scalefactor = screenWidth/iw;
    //w = 480, h=~
    //int newh = bitmap.getHeight()/bitmap.getWidth();
    return android.graphics.Bitmap.createScaledBitmap(bitmap, (int)(iw*scalefactor), (int)(ih*scalefactor), true);
    //return bitmap;
}
person Hitesh Tailor    schedule 28.01.2012

Один из способов сделать это — установить для android:adjustViewBounds="true" значение ImageView и установить тип шкалы "fitCenter" в XML-файле. Это должно работать, как ожидалось. Вы также можете сделать это программно, установив ImageView.adjustViewBounds(true) и ImageView.setScaleType(ScaleType.FIT_CENTER).

person Parag Agrawal    schedule 13.07.2017