Pull to refresh

Android. Вывод изображений, различные способы

Эта статья будет полезна начинающим разработчикам, здесь я предложу несколько вариантов вывода изображений на Android. Будут описаны следующие способы:

Обычный метод – стандартный способ, используя ImageView. Рассмотрены варианты загрузки картинки из ресурса, а также из файла на SD карте устройства.

Продвинутый вариант — вывод изображения, используя WebView. Добавляется поддержка масштабирования и прокрутки картинки при помощи жестов.

“Джедайский” способ – улучшенный предыдущий вариант. Добавлен полноэкранный просмотр с автоматическим масштабированием изображения при показе и поддержкой смены ориентации устройства.

Исходники тестового проекта на GitHub github.com/Voldemar123/andriod-image-habrahabr-example

В этой статье я не рассматриваю вопросы загрузки изображений из Интернета, кеширования, работы с файлами и необходимых для работы приложения permissions – только вывод картинок.

Итак, задача — предположим, в нашем приложении необходимо вывести изображение на экран.
Картинка может размерами превышать разрешение экрана и иметь различное соотношение сторон.
Хранится она либо в ресурсах приложения, либо на External Storage — SD карте.

Также допустим, мы уже записали на карту памяти несколько изображений (в тестовом проекте – загружаем из сети). Храним их в каталоге данных нашего приложения, в кеше.

public static final String APP_PREFS_NAME = Constants.class.getPackage().getName();
public static final String APP_CACHE_PATH =
Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + APP_PREFS_NAME + "/cache/";


Для начала — обычный способ
Официальная документация ImageView developer.android.com/reference/android/widget/ImageView.html

Layout, где выводится картинка

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ImageView
android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />




Масштабирование по умолчанию, по меньшей стoроне экрана.
В Activity, где загружаем содержимое картинки

private ImageView mImageView;
mImageView = (ImageView) findViewById(R.id.imageView1);


Из ресурсов приложения (файл из res/drawable/img3.jpg)

mImageView.setImageResource(R.drawable.img3);


Задавая Bitmap изображения

mImageView.setImageBitmap( imageUtil.getImageBitmap() );

FileInputStream fis = new FileInputStream(Constants.APP_CACHE_PATH + this.image);
BufferedInputStream bis = new BufferedInputStream(fis);

Bitmap img = BitmapFactory.decodeStream(bis);


Или передать URI на изображение (может хранится на карте или быть загружено из сети)

mImageView.setImageURI( imageUtil.getImageURI() );
Uri.fromFile( new File( Constants.APP_CACHE_PATH + this.image ) );


Этот способ стандартный, описан во множестве примеров и поэтому нам не особо интересен. Переходим к следующему варианту.

Предположим, мы хотим показать большое изображение (например фотографию), которое размерами превышает разрешение нашего устройства. Необходимо добавить прокрутку и масштабирование картинки на экране.

Для этого используем WebView
Официальная документация WebView developer.android.com/reference/android/webkit/WebView.html

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<WebView
android:id="@+id/webView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />




В Activity, где загружаем содержимое

protected WebView webView;
webView = (WebView) findViewById(R.id.webView1);


установка черного цвета фона для комфортной работы (по умолчанию – белый)

webView.setBackgroundColor(color.black);


включаем поддержку масштабирования

webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);


больше места для нашей картинки

webView.setPadding(0, 0, 0, 0);


полосы прокрутки – внутри изображения, увеличение места для просмотра

webView.setScrollbarFadingEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);


загружаем изображение как ссылку на файл хранящийся на карте памяти

webView.loadUrl(imageUtil.getImageFileLink() );
"file:///" + Constants.APP_CACHE_PATH + this.image;


Теперь мы хотим сделать так, чтобы картинка при показе автоматически масштабировалась по одной из сторон, при этом прокрутка остается только в одном направлении.
Например, для просмотра фотографий более удобна ландшафтная ориентация устройства.
Также при смене ориентации телефона масштаб изображения должен автоматически меняться.
Дополнительно расширим место для просмотра изображения на полный экран.

В AndroidManifest.xml для нашей Activity добавляем

android:configChanges="orientation"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"


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

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
changeContent();
}


В приватном методе описана логика пересчета масштаба для картинки
Получаем информацию о размерах дисплея. Из-за того, что мы изменили тему Activity, теперь WebView раскрыт на полный экран, никакие другие элементы интерфейса не видны. Видимый размер дисплея равен разрешению экрана нашего Android устройства.


Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

int width = display.getWidth();
int height = display.getHeight();


Размеры изображения, выбранного для показа


Bitmap img = imageUtil.getImageBitmap();

int picWidth = img.getWidth();
int picHeight = img.getHeight();


Меняем масштаб изображения если его высота больше высоты экрана. Прокрутка теперь будет только по горизонтали.


Double val = 1d;

if (picHeight > height)
val = new Double(height) / new Double(picHeight);

val = val * 100d;

webView.setInitialScale( val.intValue() );


Подбрасываем в WebView специально сформированный HTML файл, содержащий изображение.


webView.loadDataWithBaseURL("/",
imageUtil.getImageHtml(picWidth, picHeight),
"text/html",
"UTF-8",
null);

StringBuffer html = new StringBuffer();

html.append("");
html.append("");


Такой способ я применил из-того, что после загрузки изображения в WebView через метод loadUrl, как в прошлом варианте, setInitialScale после поворота устройства не изменяет масштаб картинки. Другими словами, показали картинку, повернули телефон, масштаб остался старый. Очень похоже на то, что изображение как-то кешируется.

Я не нашел в документации упоминания об этом странном поведении. Может быть местные специалисты скажут, что я делаю не так?
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.